Last active
October 14, 2023 00:51
-
-
Save JosePedroDias/47696077307ebce6cc5e0c6ac76e922b to your computer and use it in GitHub Desktop.
simplest stack calculator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { test } from 'node:test'; | |
import { strictEqual, deepEqual } from 'node:assert'; | |
/* | |
inspired by https://www.youtube.com/watch?v=umSuLpjFUf8 | |
3 3 * 4 4 * + sqrt | |
equivalent to | |
Math.sqrt(3*3 + 4*4) | |
*/ | |
const parseTokens = (s) => s.split(' ').map(v => isFinite(v) && v !== '' ? parseFloat(v) : v); | |
const parseWithQuotes = (s) => { | |
let parts = []; | |
let i = 0; | |
let start, end; | |
while (true) { | |
start = s.indexOf('[', i); | |
if (start === -1) break; | |
else { | |
end = s.indexOf(']', start+1); | |
if (end === -1) break; | |
} | |
const prefix = s.substring(i, start); | |
if (prefix !== '') parts = [...parts, ...parseTokens(prefix)]; | |
const quotedString = s.substring(start, end+1); | |
parts.push(quotedString); | |
i = end + 1; | |
} | |
const prefix = s.substring(i); | |
if (prefix !== '') parts = [...parts, ...parseTokens(prefix)]; | |
parts = parts.filter((v) => v !== ''); | |
return parts; | |
} | |
const quote = (arr) => `[${arr.join(' ')}]`; | |
const unquote = (s) => parseWithQuotes( s.substring(1, s.length - 1) ); | |
function calc(args, stack = [], debug = false) { | |
const ops = { | |
'+': (a, b) => a + b, | |
'-': (a, b) => a - b, | |
'*': (a, b) => a * b, | |
'/': (a, b) => a / b, | |
'sqrt': (a) => Math.sqrt(a), | |
}; | |
while (args.length > 0) { | |
debug && console.log(`${stack.join(' ')} | ${args.join(' ')}`); | |
const arg = args.shift(); | |
switch (arg) { | |
case '+': | |
case '-': | |
case '*': | |
case '/': { | |
const b = stack.pop(); | |
const a = stack.pop(); | |
stack.push( ops[arg](a, b) ); | |
} break; | |
case 'sqrt': { | |
const a = stack.pop(); | |
stack.push( ops[arg](a) ); | |
} break; | |
case 'dup': { | |
const a = stack.pop(); | |
stack.push(a); | |
stack.push(a); | |
} break; | |
case 'swap': { | |
const a = stack.pop(); | |
const b = stack.pop(); | |
stack.push(a); | |
stack.push(b); | |
} break; | |
case 'apply': { | |
const a = unquote( stack.pop() ); | |
args = [...a, ...args]; | |
} break; | |
case 'dig2': { | |
const a = stack.splice(stack.length - 3, 1)[0]; | |
stack.push(a); | |
} break; | |
case 'drop': { | |
const a = stack.pop(); | |
console.log(`drop: ${a}`); | |
} break; | |
default: | |
stack.push(arg); | |
} | |
} | |
return stack; | |
} | |
if (true) { | |
const args = parseWithQuotes( process.argv[2] ); | |
const stack_ = calc(args, [], true); | |
console.log(stack_[0]); | |
} | |
else { | |
const calc_ = (s) => calc(parseWithQuotes(s)).pop(); | |
test('parseTokens', () => deepEqual([2, 3, '+', 'sqrt'], parseTokens('2 3 + sqrt'))); | |
test('parseWithQuotes 1', () => deepEqual([2, 3, '+'], parseWithQuotes('2 3 +'))); | |
test('parseWithQuotes 2', () => deepEqual([2, '[2 1 -]', '+'], parseWithQuotes('2 [2 1 -] +'))); | |
test('parseWithQuotes 3', () => deepEqual(['[2 1 -]', 5, '+'], parseWithQuotes('[2 1 -] 5 +'))); | |
test('parseWithQuotes 4', () => deepEqual([2, '[2 1 -]'], parseWithQuotes('2 [2 1 -]'))); | |
test('quote', () => deepEqual('[2 1 -]', quote([2, 1, '-']))); | |
test('unquote', () => deepEqual([2, 1, '-'], unquote('[2 1 -]'))); | |
test('sum', () => strictEqual(3, calc_('1 2 +'))); | |
test('sub 1', () => strictEqual(1, calc_('2 1 -'))); | |
test('sub 2', () => strictEqual(-1, calc_('1 2 -'))); | |
test('mul', () => strictEqual(12, calc_('3 4 *'))); | |
test('div', () => strictEqual(3, calc_('12 4 /'))); | |
test('sqrt', () => strictEqual(3, calc_('9 sqrt'))); | |
test('dup', () => strictEqual(16, calc_('4 dup *'))); | |
test('swap', () => strictEqual(8, calc_('1 9 swap -'))); | |
test('dig2', () => strictEqual(12, calc_('3 4 5 dig2 + +'))); | |
test('drop', () => strictEqual(undefined, calc_('2 drop'))); | |
test('pythagorean 1', () => strictEqual(5, calc_('3 3 * 4 4 * + sqrt'))); | |
test('pythagorean 2', () => strictEqual(5, calc_('3 4 [dup * swap dup * + sqrt] apply'))); | |
test('pythagorean 3', () => strictEqual(undefined, calc_('[dup * swap dup * + sqrt] dup 3 4 dig2 apply drop 5 12 dig2 apply drop'))); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment