diff options
| author | Marijn Besseling <njirambem@gmail.com> | 2025-09-07 20:56:09 +0200 |
|---|---|---|
| committer | Marijn Besseling <njirambem@gmail.com> | 2025-09-07 20:56:09 +0200 |
| commit | 9ab322751a732d8cbc1ddf4f2ecf5022d7242baa (patch) | |
| tree | 49abc49c7d148b2f575aa5daef32875d44729561 /Blog/Components/Pages/Calc.razor.js | |
WIP migration
Diffstat (limited to 'Blog/Components/Pages/Calc.razor.js')
| -rw-r--r-- | Blog/Components/Pages/Calc.razor.js | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/Blog/Components/Pages/Calc.razor.js b/Blog/Components/Pages/Calc.razor.js new file mode 100644 index 0000000..d18634e --- /dev/null +++ b/Blog/Components/Pages/Calc.razor.js | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | import { getById, div, span, h, writeError } from "/common.module.js" | ||
| 2 | |||
| 3 | export function onLoad() { | ||
| 4 | console.log('Loaded'); | ||
| 5 | const form = getById("form"); | ||
| 6 | const input = getById("input"); | ||
| 7 | const log = getById("log"); | ||
| 8 | |||
| 9 | form.addEventListener("submit", submitForm); | ||
| 10 | |||
| 11 | const urlParams = new URLSearchParams(window.location.search); | ||
| 12 | const queryInput = urlParams.get('in'); | ||
| 13 | |||
| 14 | if (input.value.length === 0) { | ||
| 15 | input.value = queryInput; | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | export function onUpdate() { | ||
| 20 | console.log('Updated'); | ||
| 21 | } | ||
| 22 | |||
| 23 | export function onDispose() { | ||
| 24 | console.log('Disposed'); | ||
| 25 | } | ||
| 26 | |||
| 27 | /** @param {SubmitEvent} event */ | ||
| 28 | function submitForm(event) { | ||
| 29 | console.log(input.value); | ||
| 30 | resetLog(); | ||
| 31 | try { | ||
| 32 | const stack = evalString(input.value); | ||
| 33 | console.log(stack); | ||
| 34 | |||
| 35 | const path = window.location.pathname; | ||
| 36 | const params = new URLSearchParams(window.location.search); | ||
| 37 | const hash = window.location.hash; | ||
| 38 | |||
| 39 | params.set("in", input.value); | ||
| 40 | window.history.replaceState({}, '', `${path}?${params.toString()}${hash}`); | ||
| 41 | } | ||
| 42 | catch (error) { | ||
| 43 | writeError(error); | ||
| 44 | } | ||
| 45 | event.preventDefault(); | ||
| 46 | } | ||
| 47 | |||
| 48 | /** @param {string} input */ | ||
| 49 | function evalString(input) { | ||
| 50 | let words = input.trim().split(' ').filter(i => i); | ||
| 51 | return evalWords([], words); | ||
| 52 | } | ||
| 53 | |||
| 54 | function effect2(f) { | ||
| 55 | return (stack) => { | ||
| 56 | if (stack.length <= 1) throw "stack underflow"; | ||
| 57 | let [x, y, ...rest] = stack; | ||
| 58 | return [f(y, x), ...rest]; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | const plus = effect2((a, b) => a + b); | ||
| 63 | const subtract = effect2((a, b) => a - b); | ||
| 64 | const multiply = effect2((a, b) => a * b); | ||
| 65 | const divide = effect2((a, b) => a / b); | ||
| 66 | |||
| 67 | |||
| 68 | function evalWords(stack, words) { | ||
| 69 | writeLog(stack, words); | ||
| 70 | if (words.length === 0) return stack; | ||
| 71 | |||
| 72 | let [word, ...rest] = words; | ||
| 73 | return evalWords(evalWord(word, stack), rest); | ||
| 74 | } | ||
| 75 | |||
| 76 | function evalWord(word, stack, rest) { | ||
| 77 | switch (word) { | ||
| 78 | case "+": return plus(stack); | ||
| 79 | case "-": return subtract(stack); | ||
| 80 | case "*": return multiply(stack); | ||
| 81 | case "/": return divide(stack); | ||
| 82 | case "dup": return dup(stack); | ||
| 83 | case "drop": return drop(stack); | ||
| 84 | case "swap": return swap(stack); | ||
| 85 | default: return parse(word, stack); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | function dup(stack) { | ||
| 90 | let [x, ...rest] = stack; | ||
| 91 | return [x, x, ...rest]; | ||
| 92 | } | ||
| 93 | |||
| 94 | function drop(stack) { | ||
| 95 | let [_, ...rest] = stack; | ||
| 96 | return rest; | ||
| 97 | } | ||
| 98 | |||
| 99 | function swap(stack) { | ||
| 100 | let [x, y, ...rest] = stack; | ||
| 101 | return [y, x, ...rest]; | ||
| 102 | } | ||
| 103 | |||
| 104 | function parse(word, stack) { | ||
| 105 | let num = Number(word); | ||
| 106 | if (isNaN(num)) { | ||
| 107 | throw `word '${word}' not recognised`; | ||
| 108 | } | ||
| 109 | return [num, ...stack]; | ||
| 110 | } | ||
| 111 | |||
| 112 | function writeLog(stack, words) { | ||
| 113 | let log_left = span(`[${stack.join(', ')}]`); | ||
| 114 | let log_right = span(words.join(' ')); | ||
| 115 | |||
| 116 | if (words.length === 0) { | ||
| 117 | log_left.textContent += " <==" | ||
| 118 | } | ||
| 119 | |||
| 120 | let log_row = div(log_left, log_right); | ||
| 121 | log_row.className = "flex-spread"; | ||
| 122 | |||
| 123 | log.appendChild(log_row); | ||
| 124 | } | ||
| 125 | |||
| 126 | function resetLog() { | ||
| 127 | if (!log.hasChildNodes()) return; | ||
| 128 | |||
| 129 | let summary = h("summary"); | ||
| 130 | summary.textContent = log.firstChild.lastChild.textContent; | ||
| 131 | |||
| 132 | let old_log = log.cloneNode(true); | ||
| 133 | old_log.id = ''; | ||
| 134 | |||
| 135 | let details = h("details", summary, old_log); | ||
| 136 | details.className = "history" | ||
| 137 | |||
| 138 | log.insertAdjacentElement("afterend", details); | ||
| 139 | log.replaceChildren(); //remove children, clear log | ||
| 140 | } \ No newline at end of file | ||