├── App.js
├── README.md
├── app.json
├── assets
├── icon.png
└── splash.png
├── components
├── CalcButton.js
├── CalcDisplay.js
└── index.js
├── lib
├── swisscalc.calc.calculator.js
├── swisscalc.calc.loanCalculator.js
├── swisscalc.calc.tipCalculator.js
├── swisscalc.display.fixedPointDisplay.js
├── swisscalc.display.memoryDisplay.js
├── swisscalc.display.numericDisplay.js
├── swisscalc.lib.format.js
├── swisscalc.lib.operator.js
├── swisscalc.lib.operatorCache.js
└── swisscalc.lib.shuntingYard.js
├── package.json
└── screens
└── CalculatorScreen.js
/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, Text, View } from 'react-native';
3 | import CalculatorScreen from './screens/CalculatorScreen';
4 |
5 | export default class App extends React.Component {
6 | render() {
7 | return
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ReactCalculator
2 | Calculator built using React Native
3 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "react-calc-01",
4 | "description": "This project is really great.",
5 | "slug": "react-calc-01",
6 | "privacy": "public",
7 | "sdkVersion": "26.0.0",
8 | "platforms": ["ios", "android"],
9 | "version": "1.0.0",
10 | "icon": "./assets/icon.png",
11 | "splash": {
12 | "image": "./assets/splash.png",
13 | "resizeMode": "contain",
14 | "backgroundColor": "#ffffff"
15 | },
16 | "updates": {
17 | "fallbackToCacheTimeout": 0
18 | },
19 | "assetBundlePatterns": [
20 | "**/*"
21 | ],
22 | "ios": {
23 | "supportsTablet": true
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProProgramming101/ReactCalculator/26bab9b44b10783d50934aa6752c0bf2885d4d6f/assets/icon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProProgramming101/ReactCalculator/26bab9b44b10783d50934aa6752c0bf2885d4d6f/assets/splash.png
--------------------------------------------------------------------------------
/components/CalcButton.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react';
3 | import { StyleSheet, View, Text, TouchableOpacity } from 'react-native';
4 |
5 | export default class CalcButton extends React.Component {
6 |
7 | static defaultProps = {
8 | onPress: function() { },
9 | title: "",
10 | color: "white",
11 | backgroundColor: "black",
12 | radius: 40,
13 |
14 | style: { },
15 | }
16 |
17 |
18 | render() {
19 | var r = this.props.radius;
20 | var w = this.props.radius * 2;
21 | var h = this.props.radius * 2;
22 | var bc = this.props.backgroundColor;
23 |
24 | return (
25 |
27 | {this.props.title}
28 |
29 | );
30 | }
31 | }
32 |
33 | const styles = StyleSheet.create({
34 | container: { alignItems: "center", justifyContent: "center", margin: 5, },
35 | text: { fontSize: 30, fontWeight: "bold", },
36 | });
--------------------------------------------------------------------------------
/components/CalcDisplay.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react';
3 | import { StyleSheet, View, Text }from 'react-native';
4 |
5 | export default class CalcDisplay extends React.Component {
6 |
7 | static defaultProps = {
8 | display: "",
9 | }
10 |
11 | render() {
12 | return (
13 |
14 | {this.props.display}
15 |
16 | )
17 | }
18 | }
19 |
20 | const styles = StyleSheet.create({
21 | container: { padding: 20, },
22 | display: { fontSize: 70, color: "white", textAlign: "right", },
23 | })
--------------------------------------------------------------------------------
/components/index.js:
--------------------------------------------------------------------------------
1 |
2 | export { default as CalcButton } from './CalcButton';
3 | export { default as CalcDisplay } from './CalcDisplay';
--------------------------------------------------------------------------------
/lib/swisscalc.calc.calculator.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Class for implementing a basic/scientific calculator
7 |
8 | /*
9 | Usage:
10 |
11 | var oc = global.swisscalc.lib.operatorCache;
12 | var calc = new global.swisscalc.calc.calculator();
13 |
14 | // Calculate: 12 + 45 =
15 | calc.addDigit("1");
16 | calc.addDigit("2");
17 | calc.addBinaryOperator(oc.AdditionOperator);
18 | calc.addDigit("4");
19 | calc.addDigit("5");
20 | calc.equalsPressed();
21 | alert(calc.getMainDisplay()); // 57
22 | calc.clear();
23 |
24 | */
25 |
26 | global.swisscalc = global.swisscalc || {};
27 | global.swisscalc.calc = global.swisscalc.calc || {};
28 | global.swisscalc.calc.calculator = function() {
29 | this._state = 0; // STATE_AWAITING_OPERATOR
30 | this._evaluator = new global.swisscalc.lib.shuntingYard();
31 | this._mainDisplay = new global.swisscalc.display.numericDisplay(true, 7);
32 | this._memoryDisplay = new global.swisscalc.display.memoryDisplay();
33 | };
34 |
35 | // Constants...
36 | global.swisscalc.calc.calculator.STATE_AWAITING_OPERAND = 0; // Don't use. Use STATE_AWAITING_OPERATOR instead
37 | global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR = 0;
38 | global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND = 1;
39 | global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR = 2;
40 |
41 | // Sets the current state of the calculator.
42 | global.swisscalc.calc.calculator.prototype.setState = function(state) {
43 | this._state = state;
44 | };
45 |
46 | // Pushes the value of _mainDisplay onto the operand stack.
47 | global.swisscalc.calc.calculator.prototype.pushDisplay = function() {
48 | var val = this._mainDisplay.getDisplayValue();
49 | this._evaluator.addOperand(val);
50 | };
51 |
52 | // Adds the given digit, or starts the display over if applicable.
53 | // Only send 0...9 or . (decimal). Must be a string. State dependent.
54 | global.swisscalc.calc.calculator.prototype.addDigit = function(digit) {
55 | if (this._state == global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR)
56 | {
57 | this._mainDisplay.clear();
58 | this._mainDisplay.addDigit(digit);
59 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND);
60 | }
61 | else if (this._state == global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND)
62 | {
63 | this._mainDisplay.addDigit(digit);
64 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND);
65 | }
66 | else if (this._state == global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR)
67 | {
68 | this._mainDisplay.clear();
69 | this._mainDisplay.addDigit(digit);
70 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND);
71 | }
72 | };
73 |
74 | // Removes the last character if applicable. State dependent.
75 | global.swisscalc.calc.calculator.prototype.backspace = function() {
76 | if (this._state == global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR)
77 | {
78 | this.setState(global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR);
79 | }
80 | else if (this._state == global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND)
81 | {
82 | this._mainDisplay.backspace();
83 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND);
84 | }
85 | else if (this._state == global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR)
86 | {
87 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR);
88 | }
89 | };
90 |
91 | // Clears everything and returns to initial state
92 | global.swisscalc.calc.calculator.prototype.clear = function() {
93 | this._mainDisplay.clear();
94 | this._evaluator.clear();
95 | this.setState(global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR);
96 | };
97 |
98 | // Clears the display. Does not change state. (Like pressing CE on a calculator)
99 | global.swisscalc.calc.calculator.prototype.clearEntry = function() {
100 | this._mainDisplay.clear();
101 | };
102 |
103 | // Pushes display, evaluates, and updates display.
104 | global.swisscalc.calc.calculator.prototype.equalsPressed = function() {
105 | this.pushDisplay();
106 | var result = this._evaluator.evaluate();
107 | this._mainDisplay.setDisplayValue(result);
108 | this.setState(global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR);
109 | };
110 |
111 | // Adds parenthesis and clears display.
112 | global.swisscalc.calc.calculator.prototype.openParen = function() {
113 | this._evaluator.addOpenParen(global.swisscalc.lib.operatorCache.OpenParenOperator);
114 | this._mainDisplay.clear();
115 | this.setState(global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR);
116 | };
117 |
118 | // If in a sub-expression, pushes display, applies parenthesis, and updates display.
119 | global.swisscalc.calc.calculator.prototype.closeParen = function() {
120 | // Ignore if not in sub-expression...
121 | if (!this._evaluator.inSubExpression())
122 | return;
123 |
124 | this.pushDisplay();
125 | this._evaluator.addCloseParen(global.swisscalc.lib.operatorCache.CloseParenOperator);
126 | this._mainDisplay.setDisplayValue(this._evaluator.popOperand());
127 | this.setState(global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR);
128 | };
129 |
130 | // Just displays the constant on the screen.
131 | global.swisscalc.calc.calculator.prototype.addNullaryOperator = function(nullaryOperator) {
132 | var val = nullaryOperator.evaluate();
133 | this._mainDisplay.setDisplayValue(val);
134 | this.setState(global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR);
135 | };
136 |
137 | // Negation is a special type of unary operator because the user must be allowed to continue typing the number.
138 | global.swisscalc.calc.calculator.prototype.negate = function() {
139 | if (this._state == global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR)
140 | {
141 | this.addUnaryOperator(global.swisscalc.lib.operatorCache.NegateOperator);
142 | }
143 | else if (this._state == global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND)
144 | {
145 | this._mainDisplay.negate();
146 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND);
147 | }
148 | else if (this._state == global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR)
149 | {
150 | this.addUnaryOperator(global.swisscalc.lib.operatorCache.NegateOperator);
151 | }
152 | };
153 |
154 | // Adds the given unary operator. Do NOT send this function a NegateOperator; use negate() instead.
155 | global.swisscalc.calc.calculator.prototype.addUnaryOperator = function(unaryOperator) {
156 | this.pushDisplay();
157 | this._evaluator.addUnaryOperator(unaryOperator);
158 | this._mainDisplay.setDisplayValue(this._evaluator.popOperand());
159 | this.setState(global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR);
160 | };
161 |
162 | // Adds the given binary operator.
163 | global.swisscalc.calc.calculator.prototype.addBinaryOperator = function(binaryOperator) {
164 | if (this._state == global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR)
165 | {
166 | this.pushDisplay();
167 | this._evaluator.addBinaryOperator(binaryOperator);
168 | this._mainDisplay.setDisplayValue(this._evaluator.peekOperand());
169 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR);
170 | }
171 | else if (this._state == global.swisscalc.calc.calculator.STATE_ENTERING_OPERAND)
172 | {
173 | this.pushDisplay();
174 | this._evaluator.addBinaryOperator(binaryOperator);
175 | this._mainDisplay.setDisplayValue(this._evaluator.peekOperand());
176 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR);
177 | }
178 | else if (this._state == global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR)
179 | {
180 | // If entering an operator, we must have already had one, so we can pop..
181 | this._evaluator.popOperator();
182 | this._evaluator.addBinaryOperator(binaryOperator);
183 | this._mainDisplay.setDisplayValue(this._evaluator.peekOperand());
184 | this.setState(global.swisscalc.calc.calculator.STATE_ENTERING_OPERATOR);
185 | }
186 | };
187 |
188 | // Returns the current display on the _mainDisplay.
189 | global.swisscalc.calc.calculator.prototype.getMainDisplay = function() {
190 | return this._mainDisplay.getCurrentDisplay();
191 | };
192 |
193 | //
194 | // *** MEMORY FUNCTIONS ***
195 | //
196 |
197 | // Clears the memory.
198 | global.swisscalc.calc.calculator.prototype.memoryClear = function() {
199 | this._memoryDisplay.memoryClear();
200 | };
201 |
202 | // Adds current display to memory.
203 | global.swisscalc.calc.calculator.prototype.memoryPlus = function() {
204 | var val = this._mainDisplay.getDisplayValue();
205 | this._memoryDisplay.memoryPlus(val);
206 | };
207 |
208 | // Subtracts current display from memory.
209 | global.swisscalc.calc.calculator.prototype.memoryMinus = function() {
210 | var val = this._mainDisplay.getDisplayValue();
211 | this._memoryDisplay.memoryMinus(val);
212 | };
213 |
214 | // Sets memory to the display.
215 | global.swisscalc.calc.calculator.prototype.memorySet = function() {
216 | var val = this._mainDisplay.getDisplayValue();
217 | this._memoryDisplay.memorySet(val);
218 | };
219 |
220 | // Displays memory on the display and waits for operator.
221 | global.swisscalc.calc.calculator.prototype.memoryRecall = function() {
222 | // Ignore if memory not set...
223 | if (!this._memoryDisplay.hasMemory())
224 | return;
225 |
226 | var val = this._memoryDisplay.memoryRecall();
227 | this._mainDisplay.setDisplayValue(val);
228 | this.setState(global.swisscalc.calc.calculator.STATE_AWAITING_OPERATOR);
229 | };
--------------------------------------------------------------------------------
/lib/swisscalc.calc.loanCalculator.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Class for implementing a loan calculator
7 |
8 | var swisscalc = swisscalc || {};
9 | swisscalc.calc = swisscalc.calc || {};
10 | swisscalc.calc.loanCalculator = function(termUnit) {
11 | this._termUnit = (typeof termUnit === "undefined") ? 1 : termUnit; // Default: TERM_UNIT_MONTHS
12 | this._loanAmount = new swisscalc.display.numericDisplay(); // Unit: Dollars
13 | this._loanTerm = new swisscalc.display.fixedPointDisplay(0); // Unit: Months
14 | this._downPayment = new swisscalc.display.numericDisplay(); // Unit: Dollars
15 | this._interestRate = new swisscalc.display.numericDisplay(); // Unit: Decimal (I.e. 0.01 == 1%)
16 | };
17 |
18 | // Constants...
19 | swisscalc.calc.loanCalculator.TERM_UNIT_MONTHS = 1;
20 | swisscalc.calc.loanCalculator.TERM_UNIT_YEARS = 2;
21 |
22 | // Getters...
23 | swisscalc.calc.loanCalculator.prototype.getTermMonths = function() { var v = this._loanTerm.getDisplayValue(); return (this._termUnit == swisscalc.calc.loanCalculator.TERM_UNIT_MONTHS) ? v : v * 12; };
24 | swisscalc.calc.loanCalculator.prototype.getTermYears = function() { var v = this._loanTerm.getDisplayValue(); return (this._termUnit == swisscalc.calc.loanCalculator.TERM_UNIT_YEARS) ? v : v / 12; };
25 | swisscalc.calc.loanCalculator.prototype.getLoanAmount = function() { return this._loanAmount.getDisplayValue(); };
26 | swisscalc.calc.loanCalculator.prototype.getDownPayment = function() { return this._downPayment.getDisplayValue(); };
27 | swisscalc.calc.loanCalculator.prototype.getDownPaymentPercent = function() { return (this.getDownPayment() / this.getLoanAmount()) * 100.0; };
28 | swisscalc.calc.loanCalculator.prototype.getInterestRateDecimal = function() { return this._interestRate.getDisplayValue() / 100.0; };
29 | swisscalc.calc.loanCalculator.prototype.getInterestRatePercentage = function() { return this._interestRate.getDisplayValue(); };
30 |
31 | // Setters...
32 | swisscalc.calc.loanCalculator.prototype.setTermMonths = function(term) { this._loanTerm.setDisplayValue(term); this._termUnit = swisscalc.calc.loanCalculator.TERM_UNIT_MONTHS; }; // Set term in months
33 | swisscalc.calc.loanCalculator.prototype.setTermYears = function(term) { this._loanTerm.setDisplayValue(term); this._termUnit = swisscalc.calc.loanCalculator.TERM_UNIT_YEARS; }; // Set term in years
34 | swisscalc.calc.loanCalculator.prototype.setLoanAmount = function(lAmount) { this._loanAmount.setDisplayValue(lAmount); }; // Set the loan amount
35 | swisscalc.calc.loanCalculator.prototype.setDownPayment = function(dPayment) { this._downPayment.setDisplayValue(dPayment); }; // Set the down payment
36 | swisscalc.calc.loanCalculator.prototype.setDownPaymentPercent = function(perc) { this._downPayment.setDisplayValue((perc/100.0) * this.getLoanAmount()); }; // Set down payment as percentage of loan
37 | swisscalc.calc.loanCalculator.prototype.setInterestRateDecimal = function(decimal) { this._interestRate.setDisplayValue(decimal * 100); }; // Set interest rate as a decimal
38 | swisscalc.calc.loanCalculator.prototype.setInterestRatePercentage = function(perc) { this._interestRate.setDisplayValue(perc); }; // Set interest rate by percentage (e.g. 12 == 12%)
39 |
40 | // Display functions...
41 | swisscalc.calc.loanCalculator.prototype.getTermDisplay = function() { return this._loanTerm.getCurrentDisplay(); };
42 | swisscalc.calc.loanCalculator.prototype.getLoanAmountDisplay = function() { return swisscalc.lib.format.asUSCurrency(this.getLoanAmount()); };
43 | swisscalc.calc.loanCalculator.prototype.getDownPaymentDisplay = function() { return swisscalc.lib.format.asUSCurrency(this.getDownPayment()); };
44 | swisscalc.calc.loanCalculator.prototype.getInterestRateDisplay = function() { return this._interestRate.getCurrentDisplay() + "%"; };
45 |
46 | // Returns the total monthly payment to be paid on this loan
47 | swisscalc.calc.loanCalculator.prototype.getMonthlyPayment = function() {
48 | var n = this.getTermMonths();
49 | var i = this.getInterestRateDecimal() / 12.0;
50 | var A = this.getLoanAmount() - this.getDownPayment();
51 |
52 | // If no interest and no term, return full amount...
53 | if (i === 0 && n === 0)
54 | return A;
55 |
56 | // If no term, just return full amount...
57 | if (n === 0)
58 | return A;
59 |
60 | // If no interest, just divide by terms...
61 | if (i === 0)
62 | return A / n;
63 |
64 | // Standard formula...
65 | return (i * A) / (1 - Math.pow(1 + i, -1 * n));
66 | };
67 |
68 | // Returns the total payment to be paid on this loan
69 | swisscalc.calc.loanCalculator.prototype.getTotalPayment = function(monthlyPayment) {
70 | var n = this.getTermMonths();
71 | return monthlyPayment * n;
72 | };
73 |
74 | // Returns the total interest to be paid on this loan
75 | swisscalc.calc.loanCalculator.prototype.getTotalInterest = function(monthlyPayment) {
76 | var n = this.getTermMonths();
77 | var A = this.getLoanAmount() - this.getDownPayment();
78 |
79 | // If there was no term, just return 0 interest
80 | if (n === 0) return 0;
81 |
82 | return monthlyPayment * n - A;
83 | };
84 |
85 | // Returns a div containing formatted output.
86 | swisscalc.calc.loanCalculator.prototype.getDisplay = function() {
87 | var div = document.createElement("div");
88 | this.addDisplay(div);
89 | return div;
90 | };
91 |
92 | // Adds the formatted output to the given div.
93 | swisscalc.calc.loanCalculator.prototype.addDisplay = function(div) {
94 | // Perform calculations...
95 | var monthlyPayment = this.getMonthlyPayment();
96 | var totalPayment = this.getTotalPayment(monthlyPayment);
97 | var totalInterest = this.getTotalInterest(monthlyPayment);
98 |
99 | // Set formatting...
100 | monthlyPayment = swisscalc.lib.format.asUSCurrency(monthlyPayment);
101 | totalPayment = swisscalc.lib.format.asUSCurrency(totalPayment);
102 | totalInterest = swisscalc.lib.format.asUSCurrency(totalInterest);
103 |
104 | // Build output div...
105 | div.style.fontFamily = "\"Lucida Console\",Monaco,monospace";
106 | div.style.whiteSpace = "pre";
107 | div.innerHTML = "";
108 | div.innerHTML += " Monthly: " + monthlyPayment + "
";
109 | div.innerHTML += " Interest: " + totalInterest + "
";
110 | div.innerHTML += " Total: " + totalPayment;
111 | };
--------------------------------------------------------------------------------
/lib/swisscalc.calc.tipCalculator.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Class for implementing a tip calculator
7 |
8 | var swisscalc = swisscalc || {};
9 | swisscalc.calc = swisscalc.calc || {};
10 | swisscalc.calc.tipCalculator = function() {
11 | this._subtotal = new swisscalc.display.fixedPointDisplay(2); // Use fixed point display to handle keypad inputs
12 | this._tipPercent = 0.15; // Store the actual value
13 | };
14 |
15 | // Getters...
16 | swisscalc.calc.tipCalculator.prototype.getSubtotalValue = function() { return this._subtotal.getDisplayValue(); };
17 | swisscalc.calc.tipCalculator.prototype.getTipValueDecimal = function() { return this._tipPercent; };
18 | swisscalc.calc.tipCalculator.prototype.getTipValuePercentage = function() { return this._tipPercent * 100.0; };
19 |
20 | // Setters...
21 | swisscalc.calc.tipCalculator.prototype.setSubtotalValue = function(value) { this._subtotal.setDisplayValue(value); };
22 | swisscalc.calc.tipCalculator.prototype.setTipValueDecimal = function(decimal) { this._tipPercent = decimal; };
23 | swisscalc.calc.tipCalculator.prototype.setTipValuePercentage = function(perc) { this._tipPercent = perc / 100.0; };
24 |
25 | // Display functions...
26 | swisscalc.calc.tipCalculator.prototype.getSubtotalDisplay = function() { return swisscalc.lib.format.asUSCurrency(this._subtotal.getDisplayValue()); };
27 | swisscalc.calc.tipCalculator.prototype.getTipPercentDisplay = function() { return (this._tipPercent * 100.0).toFixed(1) + "%"; };
28 | swisscalc.calc.tipCalculator.prototype.getTipAmountDisplay = function() { return swisscalc.lib.format.asUSCurrency(this.getTipAmount()); };
29 | swisscalc.calc.tipCalculator.prototype.getTipCombinedDisplay = function() { return this.getTipPercentDisplay() + " " + this.getTipAmountDisplay(); };
30 | swisscalc.calc.tipCalculator.prototype.getTotalDisplay = function() { return swisscalc.lib.format.asUSCurrency(this.getTotal()); };
31 |
32 | // Returns the tip amount (in dollars)
33 | swisscalc.calc.tipCalculator.prototype.getTipAmount = function() {
34 | var subtotal = this.getSubtotalValue();
35 | return subtotal * this._tipPercent;
36 | };
37 |
38 | // Returns the bill total including tip (in dollars)
39 | swisscalc.calc.tipCalculator.prototype.getTotal = function() {
40 | var tipAmount = this.getTipAmount();
41 | return this.getSubtotalValue() + tipAmount;
42 | };
--------------------------------------------------------------------------------
/lib/swisscalc.display.fixedPointDisplay.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Class for displaying a fixed-point number.
7 |
8 | var swisscalc = swisscalc || {};
9 | swisscalc.display = swisscalc.display || {};
10 |
11 | // Constructor.
12 | // numDecimalPlaces: Number of characters to show past decimal (default: 2)
13 | // maxLength: Maximum number of characters to display (default: 20)
14 | swisscalc.display.fixedPointDisplay = function(numDecimalPlaces, maxLength) {
15 | this._display = "";
16 | this._isNegative = false;
17 | this._numDecimalPlaces = (typeof numDecimalPlaces === "undefined") ? 2 : numDecimalPlaces;
18 | this._maxLength = (typeof maxLength === "undefined") ? 20 : maxLength;
19 | };
20 |
21 | // Returns current display
22 | swisscalc.display.fixedPointDisplay.prototype.getCurrentDisplay = function() {
23 | var str = "";
24 | var len = this._display.length; // Number of characters
25 | var num = this._numDecimalPlaces; // Number of decimal places
26 |
27 | // If no decimal places, handle separately...
28 | if (num === 0) {
29 | if (len === 0) return "0"; // If no characters, return 0
30 | if (this._isNegative) return "-" + this._display; // If negative, add a "-"
31 | return this._display; // Otherwise, display as-is
32 | }
33 |
34 | if (len > num) {
35 | var p1 = this._display.substring(0, len - num);
36 | var p2 = this._display.substring(len - num, len);
37 | str = p1 + "." + p2;
38 | } else if (len == num) {
39 | str = "0." + this._display;
40 | } else if (len < num) {
41 | str = "0.";
42 | for (var i = 0; i < num - len; i++) str += "0";
43 | str += this._display;
44 | }
45 |
46 | if (this._isNegative) str = "-" + str;
47 |
48 | return str;
49 | };
50 |
51 | // Adds the given character to the display, if appropriate.
52 | // The only valid digits are: 0...9, . (decimal). Must be a string.
53 | swisscalc.display.fixedPointDisplay.prototype.addDigit = function(digit) {
54 | // Don't go past maximum length...
55 | if (this._display.length >= this._maxLength)
56 | return;
57 |
58 | // Don't add decimals even though it says you can...
59 | if (digit == ".")
60 | return;
61 |
62 | // If display is empty, don't add any 0's...
63 | if (this._display.length === 0 && digit == "0")
64 | return;
65 |
66 | // Add the digit to the end (note: '.' will result in '0.')...
67 | this._display += digit;
68 | };
69 |
70 | // Adds or removes the negative sign
71 | swisscalc.display.fixedPointDisplay.prototype.negate = function() {
72 | this._isNegative = !this._isNegative;
73 | };
74 |
75 | // Removes the last character if possible
76 | swisscalc.display.fixedPointDisplay.prototype.backspace = function() {
77 | var len = this._display.length;
78 | if (len == 1)
79 | this._display = "";
80 | else if (len == 2 && this._display.charAt(0) == "-")
81 | this._display = "";
82 | else
83 | this._display = this._display.substring(0, len - 1);
84 | };
85 |
86 | // Clears the display
87 | swisscalc.display.fixedPointDisplay.prototype.clear = function() {
88 | this._display = "";
89 | };
90 |
91 | // Returns _display as a numeric value
92 | swisscalc.display.fixedPointDisplay.prototype.getDisplayValue = function() {
93 | var sDisplay = this.getCurrentDisplay();
94 | return parseFloat(sDisplay);
95 | };
--------------------------------------------------------------------------------
/lib/swisscalc.display.memoryDisplay.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Class for displaying/storing the memory on a calculator.
7 |
8 | global.swisscalc = global.swisscalc || {};
9 | global.swisscalc.display = global.swisscalc.display || {};
10 | global.swisscalc.display.memoryDisplay = function() {
11 | this._display = "";
12 | this._memValue = 0;
13 | this._hasMemory = false;
14 | };
15 |
16 | // Returns true if memory is set.
17 | global.swisscalc.display.memoryDisplay.prototype.hasMemory = function() {
18 | return this._hasMemory;
19 | };
20 |
21 | // Returns current display
22 | global.swisscalc.display.memoryDisplay.prototype.getCurrentDisplay = function() {
23 | return this._display;
24 | };
25 |
26 | // Returns memory value.
27 | global.swisscalc.display.memoryDisplay.prototype.memoryRecall = function() {
28 | return this._memValue;
29 | };
30 |
31 | // Sets the memory to the given value.
32 | global.swisscalc.display.memoryDisplay.prototype.memorySet = function(val) {
33 | this._hasMemory = true;
34 | this._memValue = val;
35 | this._display = "M";
36 | };
37 |
38 | // Adds given number to the memory.
39 | global.swisscalc.display.memoryDisplay.prototype.memoryPlus = function(val) {
40 | this._hasMemory = true;
41 | this._memValue += val;
42 | this._display = "M";
43 | };
44 |
45 | // Subtracts the given value from memory.
46 | global.swisscalc.display.memoryDisplay.prototype.memoryMinus = function(val) {
47 | this._hasMemory = true;
48 | this._memValue -= val;
49 | this._display = "M";
50 | };
51 |
52 | // Clears the memory.
53 | global.swisscalc.display.memoryDisplay.prototype.memoryClear = function() {
54 | this._hasMemory = false;
55 | this._memValue = 0;
56 | this._display = "";
57 | };
58 |
--------------------------------------------------------------------------------
/lib/swisscalc.display.numericDisplay.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Class for displaying a floating-point number.
7 |
8 | global.swisscalc = global.swisscalc || {};
9 | global.swisscalc.display = global.swisscalc.display || {};
10 |
11 | // Constructor.
12 | // groupDigits: Should digits be grouped by a comma (true/false) (default: true)
13 | // maxLength: Maximum number of characters to display (default: 20)
14 | global.swisscalc.display.numericDisplay = function(groupDigits, maxLength) {
15 | this._display = "0";
16 | this._groupDigits = (typeof groupDigits === "undefined") ? true : groupDigits;
17 | this._maxLength = (typeof maxLength === "undefined") ? 20 : maxLength;
18 | };
19 |
20 | // Returns current display
21 | global.swisscalc.display.numericDisplay.prototype.getCurrentDisplay = function() {
22 | return (this._groupDigits)
23 | ? global.swisscalc.lib.format.groupDigits(this._display)
24 | : this._display;
25 | };
26 |
27 | // Adds the given character to the display, if appropriate.
28 | // The only valid digits are: 0...9, . (decimal). Must be a string.
29 | global.swisscalc.display.numericDisplay.prototype.addDigit = function(digit) {
30 | // Don't go past maximum length...
31 | if (this._display.length >= this._maxLength)
32 | return;
33 |
34 | // Don't add multiple decimals...
35 | if (digit == "." && this._display.indexOf(".") >= 0)
36 | return;
37 |
38 | // If not a decimal and display is empty, remove 0...
39 | if (digit != "." && this._display == "0")
40 | this._display = "";
41 |
42 | // Add the digit to the end (note: '.' will result in '0.')...
43 | this._display += digit;
44 | };
45 |
46 | // Adds or removes the negative sign
47 | global.swisscalc.display.numericDisplay.prototype.negate = function() {
48 | var fChar = this._display.charAt(0);
49 | this._display = (fChar == "-") ? this._display.substring(1) : "-" + this._display;
50 | };
51 |
52 | // Removes the last character if possible
53 | global.swisscalc.display.numericDisplay.prototype.backspace = function() {
54 | var len = this._display.length;
55 | if (len == 1)
56 | this._display = "0";
57 | else if (len == 2 && this._display.charAt(0) == "-")
58 | this._display = "0";
59 | else
60 | this._display = this._display.substring(0, len - 1);
61 | };
62 |
63 | // Clears the display
64 | global.swisscalc.display.numericDisplay.prototype.clear = function() {
65 | this._display = "0";
66 | };
67 |
68 | // Returns _display as a numeric value
69 | global.swisscalc.display.numericDisplay.prototype.getDisplayValue = function() {
70 | return parseFloat(this._display);
71 | };
72 |
73 | // Formats the value and sets the display. "val" should be a number.
74 | global.swisscalc.display.numericDisplay.prototype.setDisplayValue = function(val) {
75 | // TODO: May need to do some formatting/rounding...
76 | this._display = val.toString();
77 | };
78 |
--------------------------------------------------------------------------------
/lib/swisscalc.lib.format.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | global.swisscalc = global.swisscalc || {};
7 | global.swisscalc.lib = global.swisscalc.lib || {};
8 | global.swisscalc.lib.format = function() {};
9 |
10 | // Adds commas to the given numeric-string to group digits.
11 | global.swisscalc.lib.format.groupDigits = function(number) {
12 | // http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript/2901298#2901298
13 | var parts = number.toString().split(".");
14 | parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
15 | return parts.join(".");
16 | };
17 |
18 | // Formats the given number as a US currency string
19 | global.swisscalc.lib.format.asUSCurrency = function(number) {
20 | var s = number.toFixed(2);
21 | s = global.swisscalc.lib.format.groupDigits(s);
22 | return (s.charAt(0) == "-") ? "-$" + s.substring(1) : "$" + s;
23 | };
--------------------------------------------------------------------------------
/lib/swisscalc.lib.operator.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Generic operator class. Implementation of individual operators will be defined in the OperatorCache.
7 | // "evaluate" should be a function that takes a global.swisscalc.lib.shuntingYard instance as a parameter and returns the result.
8 | global.swisscalc = global.swisscalc || {};
9 | global.swisscalc.lib = global.swisscalc.lib || {};
10 | global.swisscalc.lib.operator = function(arity, associativity, precedence, numOperands, isOpenParen, isCloseParen, evaluate) {
11 | this.Arity = arity;
12 | this.Associativity = associativity;
13 | this.Precedence = precedence;
14 | this.NumOperands = numOperands;
15 | this.IsOpenParen = isOpenParen;
16 | this.IsCloseParen = isCloseParen;
17 | this.evaluate = evaluate;
18 | };
19 |
20 | // Constants
21 | global.swisscalc.lib.operator.ARITY_NULLARY = 0;
22 | global.swisscalc.lib.operator.ARITY_UNARY = 1;
23 | global.swisscalc.lib.operator.ARITY_BINARY = 2;
24 | global.swisscalc.lib.operator.ASSOCIATIVITY_NONE = 0;
25 | global.swisscalc.lib.operator.ASSOCIATIVITY_RIGHT = 1;
26 | global.swisscalc.lib.operator.ASSOCIATIVITY_LEFT = 2;
27 |
28 | // Static functions
29 | global.swisscalc.lib.operator.degreesToRadians = function(degrees) { return degrees * (Math.PI / 180.0); };
30 | global.swisscalc.lib.operator.radiansToDegrees = function(radians) { return radians * (180.0 / Math.PI); };
31 |
32 | // Returns true if precedence is higher than given operator
33 | global.swisscalc.lib.operator.prototype.isHigherPrecedence = function(operator) {
34 | if (this.Precedence == operator.Precedence)
35 | return (this.Associativity == global.swisscalc.lib.operator.ASSOCIATIVITY_LEFT);
36 | return (this.Precedence > operator.Precedence);
37 | };
--------------------------------------------------------------------------------
/lib/swisscalc.lib.operatorCache.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Cache for storing operators (rather than instantiating new ones).
7 | // To create a new operator, add it to the cache as a new global.swisscalc.lib.operator, filling in the properties and evaluate() function.
8 | global.swisscalc = global.swisscalc || {};
9 | global.swisscalc.lib = global.swisscalc.lib || {};
10 | global.swisscalc.lib.operatorCache = function() { };
11 |
12 | global.swisscalc.lib.operatorCache.AdditionOperator = new global.swisscalc.lib.operator(
13 | global.swisscalc.lib.operator.ARITY_BINARY, global.swisscalc.lib.operator.ASSOCIATIVITY_LEFT, 2, 2, false, false, function(sy) {
14 | var op1 = sy.popOperand();
15 | var op2 = sy.popOperand();
16 | return op1 + op2;
17 | });
18 |
19 | global.swisscalc.lib.operatorCache.SubtractionOperator = new global.swisscalc.lib.operator(
20 | global.swisscalc.lib.operator.ARITY_BINARY, global.swisscalc.lib.operator.ASSOCIATIVITY_LEFT, 2, 2, false, false, function(sy) {
21 | var op1 = sy.popOperand();
22 | var op2 = sy.popOperand();
23 | return op2 - op1;
24 | });
25 |
26 | global.swisscalc.lib.operatorCache.MultiplicationOperator = new global.swisscalc.lib.operator(
27 | global.swisscalc.lib.operator.ARITY_BINARY, global.swisscalc.lib.operator.ASSOCIATIVITY_LEFT, 3, 2, false, false, function(sy) {
28 | var op1 = sy.popOperand();
29 | var op2 = sy.popOperand();
30 | return op1 * op2;
31 | });
32 |
33 | global.swisscalc.lib.operatorCache.DivisionOperator = new global.swisscalc.lib.operator(
34 | global.swisscalc.lib.operator.ARITY_BINARY, global.swisscalc.lib.operator.ASSOCIATIVITY_LEFT, 3, 2, false, false, function(sy) {
35 | var op1 = sy.popOperand();
36 | var op2 = sy.popOperand();
37 | return op2 / op1;
38 | });
39 |
40 | global.swisscalc.lib.operatorCache.ModulusOperator = new global.swisscalc.lib.operator(
41 | global.swisscalc.lib.operator.ARITY_BINARY, global.swisscalc.lib.operator.ASSOCIATIVITY_LEFT, 3, 2, false, false, function(sy) {
42 | var op1 = sy.popOperand();
43 | var op2 = sy.popOperand();
44 | return op2 % op1;
45 | });
46 |
47 | global.swisscalc.lib.operatorCache.ExponentialOperator = new global.swisscalc.lib.operator(
48 | global.swisscalc.lib.operator.ARITY_BINARY, global.swisscalc.lib.operator.ASSOCIATIVITY_RIGHT, 4, 2, false, false, function(sy) {
49 | var op1 = sy.popOperand();
50 | var op2 = sy.popOperand();
51 | return Math.pow(op2, op1);
52 | });
53 |
54 | global.swisscalc.lib.operatorCache.RootOperator = new global.swisscalc.lib.operator(
55 | global.swisscalc.lib.operator.ARITY_BINARY, global.swisscalc.lib.operator.ASSOCIATIVITY_RIGHT, 4, 2, false, false, function(sy) {
56 | var op1 = sy.popOperand();
57 | var op2 = sy.popOperand();
58 | return Math.pow(op2, 1.0 / op1);
59 | });
60 |
61 | global.swisscalc.lib.operatorCache.EEOperator = new global.swisscalc.lib.operator(
62 | global.swisscalc.lib.operator.ARITY_BINARY, global.swisscalc.lib.operator.ASSOCIATIVITY_RIGHT, 10, 2, false, false, function(sy) {
63 | var op1 = sy.popOperand();
64 | var op2 = sy.popOperand();
65 | return op2 * Math.pow(10.0, op1);
66 | });
67 |
68 | global.swisscalc.lib.operatorCache.PiOperator = new global.swisscalc.lib.operator(
69 | global.swisscalc.lib.operator.ARITY_NULLARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 0, false, false, function(sy) {
70 | return Math.PI;
71 | });
72 |
73 | global.swisscalc.lib.operatorCache.EOperator = new global.swisscalc.lib.operator(
74 | global.swisscalc.lib.operator.ARITY_NULLARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 0, false, false, function(sy) {
75 | return Math.E;
76 | });
77 |
78 | global.swisscalc.lib.operatorCache.RandomOperator = new global.swisscalc.lib.operator(
79 | global.swisscalc.lib.operator.ARITY_NULLARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 0, false, false, function(sy) {
80 | return Math.random();
81 | });
82 |
83 | global.swisscalc.lib.operatorCache.NegateOperator = new global.swisscalc.lib.operator(
84 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
85 | var op = sy.popOperand();
86 | return -1.0 * op;
87 | });
88 |
89 | global.swisscalc.lib.operatorCache.InverseOperator = new global.swisscalc.lib.operator(
90 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
91 | var op = sy.popOperand();
92 | return 1.0 / op;
93 | });
94 |
95 | global.swisscalc.lib.operatorCache.EExponentialOperator = new global.swisscalc.lib.operator(
96 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
97 | var op = sy.popOperand();
98 | return Math.pow(Math.E, op);
99 | });
100 |
101 | global.swisscalc.lib.operatorCache.TenExponentialOperator = new global.swisscalc.lib.operator(
102 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
103 | var op = sy.popOperand();
104 | return Math.pow(10.0, op);
105 | });
106 |
107 | global.swisscalc.lib.operatorCache.SquareRootOperator = new global.swisscalc.lib.operator(
108 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
109 | var op = sy.popOperand();
110 | return Math.sqrt(op);
111 | });
112 |
113 | global.swisscalc.lib.operatorCache.CubeRootOperator = new global.swisscalc.lib.operator(
114 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
115 | var op = sy.popOperand();
116 | return Math.cbrt(op);
117 | });
118 |
119 | global.swisscalc.lib.operatorCache.XSquaredOperator = new global.swisscalc.lib.operator(
120 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
121 | var op = sy.popOperand();
122 | return op * op;
123 | });
124 |
125 | global.swisscalc.lib.operatorCache.XCubedOperator = new global.swisscalc.lib.operator(
126 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
127 | var op = sy.popOperand();
128 | return Math.pow(op, 3);
129 | });
130 |
131 | global.swisscalc.lib.operatorCache.PercentOperator = new global.swisscalc.lib.operator(
132 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
133 | var op = sy.popOperand();
134 | return op / 100.0;
135 | });
136 |
137 | global.swisscalc.lib.operatorCache.LogBase10Operator = new global.swisscalc.lib.operator(
138 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
139 | var op = sy.popOperand();
140 | return Math.log(op) / Math.LN10;
141 | });
142 |
143 | global.swisscalc.lib.operatorCache.NaturalLogOperator = new global.swisscalc.lib.operator(
144 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
145 | var op = sy.popOperand();
146 | return Math.log(op);
147 | });
148 |
149 | global.swisscalc.lib.operatorCache.SineOperator = new global.swisscalc.lib.operator(
150 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
151 | var op = sy.popOperand();
152 | return Math.sin(op);
153 | });
154 |
155 | global.swisscalc.lib.operatorCache.CosineOperator = new global.swisscalc.lib.operator(
156 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
157 | var op = sy.popOperand();
158 | return Math.cos(op);
159 | });
160 |
161 | global.swisscalc.lib.operatorCache.TangentOperator = new global.swisscalc.lib.operator(
162 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
163 | var op = sy.popOperand();
164 | return Math.tan(op);
165 | });
166 |
167 | global.swisscalc.lib.operatorCache.ArcSineOperator = new global.swisscalc.lib.operator(
168 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
169 | var op = sy.popOperand();
170 | return Math.asin(op);
171 | });
172 |
173 | global.swisscalc.lib.operatorCache.ArcCosineOperator = new global.swisscalc.lib.operator(
174 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
175 | var op = sy.popOperand();
176 | return Math.acos(op);
177 | });
178 |
179 | global.swisscalc.lib.operatorCache.ArcTangentOperator = new global.swisscalc.lib.operator(
180 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
181 | var op = sy.popOperand();
182 | return Math.atan(op);
183 | });
184 |
185 | global.swisscalc.lib.operatorCache.SineDegreesOperator = new global.swisscalc.lib.operator(
186 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
187 | var op = sy.popOperand();
188 | return Math.sin(global.swisscalc.lib.operator.degreesToRadians(op));
189 | });
190 |
191 | global.swisscalc.lib.operatorCache.CosineDegreesOperator = new global.swisscalc.lib.operator(
192 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
193 | var op = sy.popOperand();
194 | return Math.cos(global.swisscalc.lib.operator.degreesToRadians(op));
195 | });
196 |
197 | global.swisscalc.lib.operatorCache.TangentDegreesOperator = new global.swisscalc.lib.operator(
198 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
199 | var op = sy.popOperand();
200 | return Math.tan(global.swisscalc.lib.operator.degreesToRadians(op));
201 | });
202 |
203 | global.swisscalc.lib.operatorCache.ArcSineDegreesOperator = new global.swisscalc.lib.operator(
204 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
205 | var op = sy.popOperand();
206 | return global.swisscalc.lib.operator.radiansToDegrees(Math.asin(op));
207 | });
208 |
209 | global.swisscalc.lib.operatorCache.ArcCosineDegreesOperator = new global.swisscalc.lib.operator(
210 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
211 | var op = sy.popOperand();
212 | return global.swisscalc.lib.operator.radiansToDegrees(Math.acos(op));
213 | });
214 |
215 | global.swisscalc.lib.operatorCache.ArcTangentDegreesOperator = new global.swisscalc.lib.operator(
216 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
217 | var op = sy.popOperand();
218 | return global.swisscalc.lib.operator.radiansToDegrees(Math.atan(op));
219 | });
220 |
221 | global.swisscalc.lib.operatorCache.HyperbolicSineOperator = new global.swisscalc.lib.operator(
222 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
223 | var op = sy.popOperand();
224 | return 0.5 * (Math.pow(Math.E, op) - Math.pow(Math.E, -1.0 * op));
225 | });
226 |
227 | global.swisscalc.lib.operatorCache.HyperbolicCosineOperator = new global.swisscalc.lib.operator(
228 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
229 | var op = sy.popOperand();
230 | return 0.5 * (Math.pow(Math.E, op) + Math.pow(Math.E, -1.0 * op));
231 | });
232 |
233 | global.swisscalc.lib.operatorCache.HyperbolicTangentOperator = new global.swisscalc.lib.operator(
234 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
235 | var op = sy.popOperand();
236 | return (1 - Math.pow(Math.E, -2.0 * op)) / (1 + Math.pow(Math.E, -2.0 * op));
237 | });
238 |
239 | global.swisscalc.lib.operatorCache.InverseHyperbolicSineOperator = new global.swisscalc.lib.operator(
240 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
241 | var op = sy.popOperand();
242 | return Math.log(op + Math.sqrt((op * op) + 1));
243 | });
244 |
245 | global.swisscalc.lib.operatorCache.InverseHyperbolicCosineOperator = new global.swisscalc.lib.operator(
246 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
247 | var op = sy.popOperand();
248 | return Math.log(op + Math.sqrt((op * op) - 1));
249 | });
250 |
251 | global.swisscalc.lib.operatorCache.InverseHyperbolicTangentOperator = new global.swisscalc.lib.operator(
252 | global.swisscalc.lib.operator.ARITY_UNARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 1, false, false, function(sy) {
253 | var op = sy.popOperand();
254 | return 0.5 * Math.log((1 + op) / (1 - op));
255 | });
256 |
257 | global.swisscalc.lib.operatorCache.OpenParenOperator = new global.swisscalc.lib.operator(
258 | global.swisscalc.lib.operator.ARITY_NULLARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 0, true, false, function(sy) {
259 | console.error("Cannot evaluate open parenthesis.");
260 | });
261 |
262 | global.swisscalc.lib.operatorCache.CloseParenOperator = new global.swisscalc.lib.operator(
263 | global.swisscalc.lib.operator.ARITY_NULLARY, global.swisscalc.lib.operator.ASSOCIATIVITY_NONE, 0, 0, false, true, function(sy) {
264 | console.error("Cannot evaluate close parenthesis.");
265 | });
--------------------------------------------------------------------------------
/lib/swisscalc.lib.shuntingYard.js:
--------------------------------------------------------------------------------
1 | //
2 | // Eric Morgan
3 | // Copyright (c) 2014.
4 | //
5 |
6 | // Implementation of the Shunting Yard algorithm.
7 | global.swisscalc = global.swisscalc || {};
8 | global.swisscalc.lib = global.swisscalc.lib || {};
9 | global.swisscalc.lib.shuntingYard = function() {
10 | this._numOpenParen = 0;
11 | this._operands = [];
12 | this._operators = [];
13 | this._actionBuffer = [];
14 | };
15 |
16 | // Peeks highest value on stack. Returns 0 if empty.
17 | global.swisscalc.lib.shuntingYard.prototype.peekOperand = function() {
18 | var len = this._operands.length;
19 | return (len !== 0) ? this._operands[len-1] : 0.0;
20 | };
21 |
22 | // Pops highest value on stack. Returns 0 if empty.
23 | global.swisscalc.lib.shuntingYard.prototype.popOperand = function() {
24 | var len = this._operands.length;
25 | return (len !== 0) ? this._operands.pop() : 0.0;
26 | };
27 |
28 | // Returns number of operands.
29 | global.swisscalc.lib.shuntingYard.prototype.numOperands = function() {
30 | return this._operands.length;
31 | };
32 |
33 | // Pops highest operator on stack.
34 | global.swisscalc.lib.shuntingYard.prototype.popOperator = function() {
35 | return this._actionBuffer.pop();
36 | };
37 |
38 | // Returns number of operators.
39 | global.swisscalc.lib.shuntingYard.prototype.numOperators = function() {
40 | return this._actionBuffer.length;
41 | };
42 |
43 | // Returns true if currently evaluating sub-expression.
44 | global.swisscalc.lib.shuntingYard.prototype.inSubExpression = function() {
45 | return this._numOpenParen > 0;
46 | };
47 |
48 | // Clears all stacks.
49 | global.swisscalc.lib.shuntingYard.prototype.clear = function() {
50 | this._operands.length = 0;
51 | this._operators.length = 0;
52 | this._actionBuffer.length = 0;
53 | };
54 |
55 | // Empties the stack and returns the final evaluation.
56 | global.swisscalc.lib.shuntingYard.prototype.evaluate = function() {
57 | // Push all _actionBuffer to _operators...
58 | for (var i = 0; i < this._actionBuffer.length; i++)
59 | this._operators.push(this._actionBuffer[i]);
60 | this._actionBuffer.length = 0;
61 |
62 | // Evaluate all _operators...
63 | while (this._operators.length > 0) {
64 | var operator = this._operators.pop();
65 | this.applyOperator(operator);
66 | }
67 |
68 | // Check for errors and return result...
69 | if (this._operands.length != 1)
70 | console.error("Invalid operand length (" + this._operands.length + ")");
71 |
72 | return this._operands.pop();
73 | };
74 |
75 | // Evaluates the given operator and adds result to _operands.
76 | global.swisscalc.lib.shuntingYard.prototype.applyOperator = function(operator) {
77 | var val = operator.evaluate(this);
78 | this.addOperand(val);
79 | };
80 |
81 | // Adds an operand to the stack.
82 | global.swisscalc.lib.shuntingYard.prototype.addOperand = function(operand) {
83 | this._operands.push(operand);
84 | };
85 |
86 | // Adds the given operator.
87 | global.swisscalc.lib.shuntingYard.prototype.addOperator = function(operator) {
88 | if (operator.IsOpenParen) {
89 | this.addOpenParen(operator);
90 | } else if (operator.IsCloseParen) {
91 | this.addCloseParen(operator);
92 | } else if (operator.Arity == global.swisscalc.lib.operator.ARITY_NULLARY) {
93 | this.addNullaryOperator(operator);
94 | } else if (operator.Arity == global.swisscalc.lib.operator.ARITY_UNARY) {
95 | this.addUnaryOperator(operator);
96 | } else if (operator.Arity == global.swisscalc.lib.operator.ARITY_BINARY) {
97 | this.addBinaryOperator(operator);
98 | }
99 | };
100 |
101 | // Evaluates the NullaryOperator and pushes result to stack.
102 | global.swisscalc.lib.shuntingYard.prototype.addNullaryOperator = function(operator) {
103 | this.applyOperator(operator);
104 | };
105 |
106 | // Evaluates the NullaryOperator and pushes result to stack.
107 | global.swisscalc.lib.shuntingYard.prototype.addUnaryOperator = function(operator) {
108 | this.applyOperator(operator);
109 | };
110 |
111 | // First adds operator to _actionBuffer before committing to anything.
112 | global.swisscalc.lib.shuntingYard.prototype.addBinaryOperator = function(operator) {
113 | // If not parenthesis, perform precedence checks as usual...
114 | while (this._actionBuffer.length > 0)
115 | {
116 | // If previous is not higher, exit...
117 | var abLen = this._actionBuffer.length;
118 | if (!this._actionBuffer[abLen-1].isHigherPrecedence(operator))
119 | break;
120 |
121 | var prevOperator = this._actionBuffer.pop();
122 | this.applyOperator(prevOperator);
123 | }
124 |
125 | this._actionBuffer.push(operator);
126 | };
127 |
128 | // Adds the open parenthesis operator. Just adds to _actionBuffer.
129 | global.swisscalc.lib.shuntingYard.prototype.addOpenParen = function(operator) {
130 | this._actionBuffer.push(operator);
131 | this._numOpenParen++;
132 | };
133 |
134 | // Adds the close parenthesis operator. Pops operators until open is reached.
135 | global.swisscalc.lib.shuntingYard.prototype.addCloseParen = function(operator) {
136 | // Ignore if no open parentheses...
137 | if (this._numOpenParen === 0)
138 | return;
139 |
140 | this._numOpenParen--;
141 | while (this._actionBuffer.length > 0)
142 | {
143 | // If encountered an open paren, return...
144 | var nextOperator = this._actionBuffer.pop();
145 | if (nextOperator.IsOpenParen)
146 | return;
147 |
148 | // Evaluate the operator and then push it as an operand...
149 | this.applyOperator(nextOperator);
150 | }
151 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "private": true,
4 | "dependencies": {
5 | "expo": "^26.0.0",
6 | "react": "16.3.0-alpha.1",
7 | "react-native": "https://github.com/expo/react-native/archive/sdk-26.0.0.tar.gz"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/screens/CalculatorScreen.js:
--------------------------------------------------------------------------------
1 |
2 | require("../lib/swisscalc.lib.format.js");
3 | require("../lib/swisscalc.lib.operator.js");
4 | require("../lib/swisscalc.lib.operatorCache.js");
5 | require("../lib/swisscalc.lib.shuntingYard.js");
6 | require("../lib/swisscalc.display.numericDisplay.js");
7 | require("../lib/swisscalc.display.memoryDisplay.js");
8 | require("../lib/swisscalc.calc.calculator.js");
9 |
10 | import React from 'react';
11 | import { StyleSheet, Dimensions, PanResponder, View, Text } from 'react-native';
12 | import { CalcDisplay, CalcButton } from './../components';
13 |
14 | export default class CalculatorScreen extends React.Component {
15 |
16 | constructor(props) {
17 | super(props);
18 | this.state = {
19 | display: "0",
20 | orientation: "portrait", // "portrait" or "landscape"
21 | }
22 |
23 | // Initialize calculator...
24 | this.oc = global.swisscalc.lib.operatorCache;
25 | this.calc = new global.swisscalc.calc.calculator();
26 |
27 | // Listen for orientation changes...
28 | Dimensions.addEventListener('change', () => {
29 | const { width, height } = Dimensions.get("window");
30 | var orientation = (width > height) ? "landscape" : "portrait";
31 | this.setState({ orientation: orientation });
32 | });
33 |
34 | // Setup gestures...
35 | this.panResponder = PanResponder.create({
36 | onStartShouldSetPanResponder: (evt, gestureState) => true,
37 | onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
38 | onMoveShouldSetPanResponder: (evt, gestureState) => true,
39 | onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
40 | onPanResponderMove: (evt, gestureState) => { },
41 | onPanResponderRelease: (evt, gestureState) => {
42 | if (Math.abs(gestureState.dx) >= 50) {
43 | this.onBackspacePress();
44 | }
45 | },
46 | })
47 | }
48 |
49 | onDigitPress = (digit) => {
50 | this.calc.addDigit(digit);
51 | this.setState({ display: this.calc.getMainDisplay() });
52 | }
53 |
54 | onUnaryOperatorPress = (operator) => {
55 | this.calc.addUnaryOperator(operator);
56 | this.setState({ display: this.calc.getMainDisplay() });
57 | }
58 |
59 | onBinaryOperatorPress = (operator) => {
60 | this.calc.addBinaryOperator(operator);
61 | this.setState({ display: this.calc.getMainDisplay() });
62 | }
63 |
64 | onEqualsPress = () => {
65 | this.calc.equalsPressed();
66 | this.setState({ display: this.calc.getMainDisplay() });
67 | }
68 |
69 | onClearPress = () => {
70 | this.calc.clear();
71 | this.setState({ display: this.calc.getMainDisplay() });
72 | }
73 |
74 | onPlusMinusPress = () => {
75 | this.calc.negate();
76 | this.setState({ display: this.calc.getMainDisplay() });
77 | }
78 |
79 | onBackspacePress = () => {
80 | this.calc.backspace();
81 | this.setState({ display: this.calc.getMainDisplay() });
82 | }
83 |
84 | renderPortrait() {
85 | return (
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | { this.onUnaryOperatorPress(this.oc.PercentOperator) }} title="%" color="white" backgroundColor="#DCC894" />
96 | { this.onBinaryOperatorPress(this.oc.DivisionOperator) }} title="/" color="white" backgroundColor="#DCA394" />
97 |
98 |
99 |
100 | { this.onDigitPress("7") }} title="7" color="white" backgroundColor="#607D8B" />
101 | { this.onDigitPress("8") }} title="8" color="white" backgroundColor="#607D8B" />
102 | { this.onDigitPress("9") }} title="9" color="white" backgroundColor="#607D8B" />
103 | { this.onBinaryOperatorPress(this.oc.MultiplicationOperator) }} title="x" color="white" backgroundColor="#DCA394" />
104 |
105 |
106 |
107 | { this.onDigitPress("4") }} title="4" color="white" backgroundColor="#607D8B" />
108 | { this.onDigitPress("5") }} title="5" color="white" backgroundColor="#607D8B" />
109 | { this.onDigitPress("6") }} title="6" color="white" backgroundColor="#607D8B" />
110 | { this.onBinaryOperatorPress(this.oc.SubtractionOperator) }} title="-" color="white" backgroundColor="#DCA394" />
111 |
112 |
113 |
114 | { this.onDigitPress("1") }} title="1" color="white" backgroundColor="#607D8B" />
115 | { this.onDigitPress("2") }} title="2" color="white" backgroundColor="#607D8B" />
116 | { this.onDigitPress("3") }} title="3" color="white" backgroundColor="#607D8B" />
117 | { this.onBinaryOperatorPress(this.oc.AdditionOperator) }} title="+" color="white" backgroundColor="#DCA394" />
118 |
119 |
120 |
121 | { this.onDigitPress("0") }} title="0" color="white" backgroundColor="#607D8B" style={{flex:2}} />
122 | { this.onDigitPress(".") }} title="." color="white" backgroundColor="#607D8B" />
123 |
124 |
125 |
126 |
127 |
128 | );
129 | }
130 |
131 | renderLandscape() {
132 | return (
133 |
134 | Landscape
135 |
136 | )
137 | }
138 |
139 | render() {
140 | var view = (this.state.orientation == "portrait")
141 | ? this.renderPortrait()
142 | : this.renderLandscape();
143 |
144 | return (
145 |
146 | {view}
147 |
148 | )
149 | }
150 |
151 | }
152 |
153 | const styles = StyleSheet.create({
154 | container: { flex: 1, paddingVertical: 50, backgroundColor: "black" },
155 | })
--------------------------------------------------------------------------------