From bdb3117e07b2589142d996aa55b24414c3517999 Mon Sep 17 00:00:00 2001 From: Simon From Jakobsen Date: Fri, 19 Sep 2025 15:20:30 +0200 Subject: [PATCH] more compiler stuff --- compile.phi | 179 ++++++++--- make_stage1.sh | 5 + make_stage2.sh | 5 + phi.js | 39 +-- runtime.js | 42 ++- stage1.js | 813 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1002 insertions(+), 81 deletions(-) create mode 100644 make_stage1.sh create mode 100644 make_stage2.sh create mode 100644 stage1.js diff --git a/compile.phi b/compile.phi index defeaf0..ac4b92b 100644 --- a/compile.phi +++ b/compile.phi @@ -19,7 +19,6 @@ (for expr exprs (do (call emit_expr expr) (call emit ";\n") - )) )) @@ -27,7 +26,7 @@ (for expr exprs (do (let (ty line) expr) (if (!= ty "list") (return)) - (let (ty line s) expr) + (let (_ _ s) expr) (if (== (call len s) 0) (return)) (let ((_ _ id)) s) (if (== id "fn") (do @@ -43,21 +42,21 @@ (call emit_list expr) ) (if (== ty "int") ( (let (_ _ value) expr) - (call emit (call format "{ type: \"int\", value: % }" value)) + (call emit (call format "({ type: \"int\", value: % })" value)) ) (if (== ty "string") ( (let (_ _ value) expr) - (call emit (call format "{ type: \"string\", value: \"%\" }" (call string_escape value))) + (call emit (call format "({ type: \"string\", value: \"%\" })" (call string_escape value))) ) (if (== ty "ident") (do (let (_ _ value) expr) (if (== value "null") (do - (call emit "{ type: \"null\" }") + (call emit "({ type: \"null\" })") (return) ) (if (== value "false") (do - (call emit "{ type: \"bool\", value: false }") + (call emit "({ type: \"bool\", value: false })") (return) ) (if (== value "true") (do - (call emit "{ type: \"bool\", value: true }") + (call emit "({ type: \"bool\", value: true })") (return) )))) @@ -87,12 +86,12 @@ (fn emit_list (expr) (do (let (ty line s) expr) (if (== (call len s) 0) (do - (call emit "{ type: \"list\", values: [] }") + (call emit "({ type: \"list\", values: [] })") (return) )) (let ((id_ty _ id)) s) (if (!= id_ty "ident") (do - (call emit "{ type: \"list\", values: [] }") + (call emit "({ type: \"list\", values: [] })") (return) )) (if (== id "fn") (do @@ -115,18 +114,19 @@ (call emit (call format ") {\n" name)) - (call emit (call format "runtime.pushCall(\"%\");" name)) + (call emit (call format "runtime.pushCall(\"%\");\n" name)) (call emit_expr body) - (call emit "}") + (call emit ";\nruntime.popCall();\nreturn { type: \"null\" };\n}") (call leave_scope) ) (if (== id "let") (do (let (_ pat expr) s) (call emit "let ") (call emit_pat pat) - (call emit " = ") + (call emit " = runtime.assignValue(") (call emit_expr expr) + (call emit ")") ) (if (== id "do") (do (call enter_scope) (call discover_syms (call slice s 1)) @@ -134,6 +134,7 @@ (call leave_scope) ) (if (== id "for") (do (let (_ pat expr body) s) + (call enter_scope) (call emit "for (let ") (call emit_pat pat) (call emit " of ") @@ -141,6 +142,12 @@ (call emit ") {\n") (call emit_expr body) (call emit "}") + (call leave_scope) + ) (if (== id "loop") (do + (let (_ body) s) + (call emit "while (true) {\n") + (call emit_expr body) + (call emit "}") ) (if (== id "if") (do (let (_ cond truthy falsy) s) (call emit "if (") @@ -160,7 +167,13 @@ (if (!= value null) (do (call emit_expr value) ) (do - (call emit "null") + (call emit "{ type: \"null\" }") + )) + ) (if (== id "break") (do + (let (_ value) s) + (call emit "break") + (if (!= value null) (do + (call panic "not implemented") )) ) (if (== id "call") (do (let (_ callee) s) @@ -181,28 +194,50 @@ (call emit "))") ) (if (== id "=") (do - (call panic "not implemented") + (call emit_assign_expr s line "=") + ) (if (== id "+=") (do + (call emit_assign_expr s line "+") + ) (if (== id "-=") (do + (call emit_assign_expr s line "-") + ) (if (== id "or") (do + (let (_ left right) s) + (call emit (call format "(runtime.setLine(%)" line)) + (call emit ", { type: \"bool\", value: this.runtime.truthy(") + (call emit_expr left) + (call emit ") || this.runtime.falsy(") + (call emit_expr right) + (call emit ") })") + ) (if (== id "and") (do + (let (_ left right) s) + (call emit (call format "(runtime.setLine(%)" line)) + (call emit ", { type: \"bool\", value: this.runtime.truthy(") + (call emit_expr left) + (call emit ") && this.runtime.falsy(") + (call emit_expr right) + (call emit ") })") ) (if (== id "==") (do - (let (_ left right) s) - (call emit "runtime.opEq(") - (call emit_expr left) - (call emit ", ") - (call emit_expr right) - (call emit ")") + (call emit_binary_op s "opEq") ) (if (== id "!=") (do - (let (_ left right) s) - (call emit "runtime.opNe(") - (call emit_expr left) - (call emit ", ") - (call emit_expr right) - (call emit ")") + (call emit_binary_op s "opNe") + ) (if (== id "<") (do + (call emit_binary_op s "opLt") + ) (if (== id ">") (do + (call emit_binary_op s "opGt") + ) (if (== id "<=") (do + (call emit_binary_op s "opLte") + ) (if (== id ">=") (do + (call emit_binary_op s "opGte") + ) (if (== id "+") (do + (call emit_binary_op s "opAdd") + ) (if (== id "-") (do + (call emit_binary_op s "opSub") ) (if (== id "not") (do (let (_ expr) s) (call emit "runtime.opNot(") (call emit_expr expr) (call emit ")") ) (do - (call emit "{ type: \"list\", values: [") + (call emit "({ type: \"list\", values: [") (let first true) (for e s (do (if (not first) (do @@ -212,8 +247,50 @@ (call emit_expr e) )) - (call emit "] }") - )))))))))))) + (call emit "] })") + )))))))))))))))))))))))) + )) + + (fn emit_binary_op (s id) (do + (let (_ left right) s) + (call emit (call format "runtime.%(" id)) + (call emit_expr left) + (call emit ", ") + (call emit_expr right) + (call emit ")") + )) + + (fn emit_assign_expr (s line id) (do + (let (_ (target_type) expr) s) + (if (!= target_type "ident") (do + ) (do + (call panic "cannot assign to expression on line %" line) + )) + (let (_ (_ _ ident)) s) + (let sym (call get_sym ident)) + (if (== sym null) (do + (call panic "could not find symbol '%' on line %" ident line) + )) + (let (sym_type sym_ident _) sym) + (if (== sym_type "let") (do + (call emit (call format "(_% = runtime.assignValue(" sym_ident)) + (if (== id "=") (do + (call emit_expr expr) + ) (if (== id "+") (do + (call emit (call format "runtime.opAdd(_%, " sym_ident)) + (call emit_expr expr) + (call emit ")") + ) (if (== id "-") (do + (call emit (call format "runtime.opSub(_%, " sym_ident)) + (call emit_expr expr) + (call emit ")") + ) (do + (call panic "not implemented") + )))) + (call emit "))") + ) (do + (call panic "cannot assign to symbol '%' on line %" sym_ident line) + )) )) (fn emit_pat (pat) (do @@ -223,7 +300,7 @@ (if (== name "_") (do (return) )) - (call emit name) + (call emit (call format "_%" name)) (call define_sym name ("let" name line)) ) (if (== ty "list") (do (let (_ _ pats) pat) @@ -284,7 +361,7 @@ (if (>= i (call len syms)) (break)) (let (s_ident _) (call at syms i)) (if (== ident s_ident) (do - (call set syms i sym) + (call set syms i (ident sym)) (return) )) (+= i 1) @@ -329,7 +406,9 @@ (loop (do (if (>= i str_len) (break)) (let ch (call at str i)) - (if (== ch "\"") (do + (if (== ch "\\") (do + (+= result "\\\\") + ) (if (== ch "\"") (do (+= result "\\\"") ) (if (== ch "\t") (do (+= result "\\t") @@ -341,7 +420,7 @@ (+= result "\\0") ) (do (+= result ch) - )))))) + ))))))) (+= i 1) )) (return result) @@ -417,6 +496,9 @@ (let i 0) (let line 1) + (let ident_chars (+ "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-*/%&|=?!<>'_")) + (loop (do (if (>= i text_len) (break)) @@ -468,9 +550,9 @@ (+= i 1) (= ch (call at text i)) )) - (if (or (>= i text_len) (!= ch "\"") (do + (if (or (>= i text_len) (!= ch "\"")) (do (call panic "expected '\"' on line %" line) - ))) + )) (+= i 1) (call push tokens ("string" line value)) ) (if (call contains "0123456789" ch) (do @@ -484,11 +566,11 @@ (+= i 1) )) (call push tokens ("int" line value)) - ) (if (call contains identChars ch) (do + ) (if (call contains ident_chars ch) (do (let value "") (loop (do (= ch (call at text i)) - (if (or (>= i text_len) (not (call contains identChars ch))) (do + (if (or (>= i text_len) (not (call contains ident_chars ch))) (do (break) )) (+= value ch) @@ -504,9 +586,6 @@ (return tokens) )) -(let identChars (+ "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-*/%&|=?!<>'_")) - (fn contains (text ch) (do (let text_len (call len text)) (let i 0) @@ -574,7 +653,7 @@ (let silent true) -(let (_ input_filename) (call get_args)) +(let (input_filename output_filename) (call get_args)) (if (not silent) (call println "reading file...")) (let text (call read_text_file input_filename)) @@ -585,31 +664,31 @@ (if (not silent) (call println "tokenizing...")) (let tokens (call tokenize text)) -//(call println "=== tokens ===") -//(for (tok line value) tokens (do +// (call println "=== tokens ===") +// (for (tok line value) tokens (do // (call println "%\t%\t%" line tok (if (!= value null) value "")) -//)) +// )) (if (not silent) (call println "parsing...")) (let parser (call Parser tokens)) (let (parse) parser) (let ast (call parse)) -//(call println "=== ast ===") -//(for expr ast (do +// (call println "=== ast ===") +// (for expr ast (do // (call print_expr expr 0) -//)) +// )) (if (not silent) (call println "emitting...")) (let emitter (call Emitter ast input_filename)) (let (emit) emitter) (let js_code (call emit)) -//(call println "=== js ===") -//(call println js_code) +// (call println "=== js ===") +// (call println js_code) (if (not silent) (call println "writing file...")) -(call write_text_file "out.js" js_code) +(call write_text_file output_filename js_code) diff --git a/make_stage1.sh b/make_stage1.sh new file mode 100644 index 0000000..f7d8dbc --- /dev/null +++ b/make_stage1.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -xe + +node phi.js compile.phi compile.phi stage1.js diff --git a/make_stage2.sh b/make_stage2.sh new file mode 100644 index 0000000..b57959c --- /dev/null +++ b/make_stage2.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -xe + +node stage1.js compile.phi stage2.js diff --git a/phi.js b/phi.js index 8eb89c3..7e2f576 100644 --- a/phi.js +++ b/phi.js @@ -30,7 +30,7 @@ class Evaluator { this.syms = { parent: undefined, map: new Map(this.builtins) }; this.currentLine = 0; this.filename = filename; - this.runtime = new Runtime(filename); + this.runtime = new Runtime({ filename, args: process.argv.slice(3) }); } /** @@ -118,38 +118,24 @@ class Evaluator { }; } else if (id === "or") { const left = this.evalToValue(s[1]); - if (left.value) { - return { type: "value", value: left }; + if (this.runtime.truthy(left)) { + return { type: "value", value: { type: "bool", value: true } }; } else { const right = this.evalToValue(s[2]); - return { type: "value", value: right }; + return { type: "value", value: { type: "bool", value: this.runtime.truthy(right) } }; } } else if (id === "and") { const left = this.evalToValue(s[1]); - if (left.value) { + if (this.runtime.truthy(left)) { const right = this.evalToValue(s[2]); - return { type: "value", value: right }; + return { type: "value", value: { type: "bool", value: this.runtime.truthy(right) } }; } else { - return { type: "value", value: left }; + return { type: "value", value: { type: "bool", value: false } }; } } else if (id in this.artithmeticOps) { const left = this.evalToValue(s[1]); const right = this.evalToValue(s[2]); - if ( - id === "+" && left.type === "string" && right.type === "string" - ) { - return { - type: "value", - value: { type: "string", value: left.value + right.value }, - }; - } - return { - type: "value", - value: { - type: "int", - value: this.artithmeticOps[id](left.value, right.value), - }, - }; + return { type: "value", value: this.artithmeticOps[id](left, right) }; } else if (id === "==") { const left = this.evalToValue(s[1]); const right = this.evalToValue(s[2]); @@ -169,10 +155,7 @@ class Evaluator { const right = this.evalToValue(s[2]); return { type: "value", - value: { - type: "bool", - value: this.comparisonOps[id](left.value, right.value), - }, + value: this.runtime.comparisonOperation(left, right, this.comparisonOps[id]), }; } else if (id in this.assignOps) { return this.evalAssign(expr); @@ -387,8 +370,8 @@ class Evaluator { } artithmeticOps = { - "+": (left, right) => right + left, - "-": (left, right) => right - left, + "+": (left, right) => this.runtime.opAdd(left, right), + "-": (left, right) => this.runtime.opSub(left, right), }; comparisonOps = { "<": (left, right) => left < right, diff --git a/runtime.js b/runtime.js index c2cdbf7..43aa1e6 100644 --- a/runtime.js +++ b/runtime.js @@ -2,10 +2,11 @@ import fs from "node:fs"; import process from "node:process"; export class Runtime { - constructor(filename) { + constructor({ filename, args }) { this.syms = { parent: undefined, map: new Map(this.builtins) }; this.callStack = [{ name: "", line: 0 }]; this.filename = filename; + this.args = args ?? process.argv.slice(2); this.currentLine = 0; } @@ -98,6 +99,42 @@ export class Runtime { return { type: "bool", value: !expr.value }; } + comparisonOperation(left, right, action) { + if (left.type !== "int" || right.type !== "int") { + this.panic(`cannot compare types ${left.type} with ${right.type}`); + } + return { type: "bool", value: action(left.value, right.value) }; + } + + opLt(left, right) { return this.comparisonOperation(right, left, (l, r) => l < r); } + opGt(left, right) { return this.comparisonOperation(right, left, (l, r) => l > r); } + opLte(left, right) { return this.comparisonOperation(right, left, (l, r) => l <= r); } + opGte(left, right) { return this.comparisonOperation(right, left, (l, r) => l >= r); } + + opAdd(left, right) { + if (left.type === "int" && right.type === "int") { + return { type: "int", value: left.value + right.value } + } else if (left.type === "string" && right.type === "string") { + return { type: "string", value: left.value + right.value } + } else { + this.panic(`cannot apply '+' on ${left.type} and ${right.type}`); + } + } + opSub(left, right) { + if (left.type === "int" && right.type === "int") { + return { type: "int", value: left.value + right.value } + } else { + this.panic(`cannot apply '-' on ${left.type} and ${right.type}`); + } + } + + truthy(value) { + if (value.type !== "bool") { + this.panic("expected bool"); + } + return value.value; + } + builtinFormat(msg, ...args) { return { type: "string", value: this.format(msg, ...args) }; } @@ -175,8 +212,7 @@ export class Runtime { builtinGetArgs() { return { type: "list", - values: process.argv - .slice(2) + values: this.args .map((value) => ({ type: "string", value })), }; } diff --git a/stage1.js b/stage1.js new file mode 100644 index 0000000..41d3b47 --- /dev/null +++ b/stage1.js @@ -0,0 +1,813 @@ +#!/usr/bin/env node +import { Runtime } from "./runtime.js" +const runtime = new Runtime("compile.phi") +function _Emitter(_ast, _filename) { +runtime.pushCall("Emitter"); +let _output = runtime.assignValue(({ type: "list", values: [] })); +let [_enter_scope, _leave_scope, _define_sym, _get_sym] = runtime.assignValue((runtime.setLine(5), _Syms())); +function _generate() { +runtime.pushCall("generate"); +(runtime.setLine(8), _emit(({ type: "string", value: "#!/usr/bin/env node\n" }))); +(runtime.setLine(9), _emit(({ type: "string", value: "import { Runtime } from \"./runtime.js\"\n" }))); +(runtime.setLine(10), _emit(({ type: "string", value: "const runtime = new Runtime(\"" }))); +(runtime.setLine(11), _emit(_filename)); +(runtime.setLine(12), _emit(({ type: "string", value: "\")\n" }))); +(runtime.setLine(13), _discover_syms(_ast)); +(runtime.setLine(14), _emit_exprs(_ast)); +runtime.popCall(); +return (runtime.setLine(15), ((...args) => runtime.builtinStringsJoin(...args))(_output)); +; +runtime.popCall(); +return { type: "null" }; +}; +function _emit_exprs(_exprs) { +runtime.pushCall("emit_exprs"); +for (let _expr of _exprs) { +(runtime.setLine(20), _emit_expr(_expr)); +(runtime.setLine(21), _emit(({ type: "string", value: ";\n" }))); +}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _discover_syms(_exprs) { +runtime.pushCall("discover_syms"); +for (let _expr of _exprs) { +let [_ty, _line] = runtime.assignValue(_expr); +if (runtime.opNe(_ty, ({ type: "string", value: "list" }))) { +runtime.popCall(); +return { type: "null" }}; +let [, , _s] = runtime.assignValue(_expr); +if (runtime.opEq((runtime.setLine(30), ((...args) => runtime.builtinLen(...args))(_s)), ({ type: "int", value: 0 }))) { +runtime.popCall(); +return { type: "null" }}; +let [[, , _id]] = runtime.assignValue(_s); +if (runtime.opEq(_id, ({ type: "string", value: "fn" }))) { +let [, [, , _name], [, , _params], _body] = runtime.assignValue(_s); +(runtime.setLine(34), _define_sym(_name, ({ type: "list", values: [] }))); +}; +}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _emit_expr(_expr) { +runtime.pushCall("emit_expr"); +let [_ty, _line] = runtime.assignValue(_expr); +if (runtime.opEq(_ty, ({ type: "string", value: "list" }))) { +(runtime.setLine(42), _emit_list(_expr)); +} else { +if (runtime.opEq(_ty, ({ type: "string", value: "int" }))) { +({ type: "list", values: [] })} else { +if (runtime.opEq(_ty, ({ type: "string", value: "string" }))) { +({ type: "list", values: [] })} else { +if (runtime.opEq(_ty, ({ type: "string", value: "ident" }))) { +let [, , _value] = runtime.assignValue(_expr); +if (runtime.opEq(_value, ({ type: "string", value: "null" }))) { +(runtime.setLine(53), _emit(({ type: "string", value: "({ type: \"null\" })" }))); +runtime.popCall(); +return { type: "null" }; +} else { +if (runtime.opEq(_value, ({ type: "string", value: "false" }))) { +(runtime.setLine(56), _emit(({ type: "string", value: "({ type: \"bool\", value: false })" }))); +runtime.popCall(); +return { type: "null" }; +} else { +if (runtime.opEq(_value, ({ type: "string", value: "true" }))) { +(runtime.setLine(59), _emit(({ type: "string", value: "({ type: \"bool\", value: true })" }))); +runtime.popCall(); +return { type: "null" }; +}}}; +let _sym = runtime.assignValue((runtime.setLine(63), _get_sym(_value))); +if (runtime.opEq(_sym, ({ type: "null" }))) { +(runtime.setLine(65), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "undefined symbol '%' on line %" }), _value, _line)); +}; +let [_sym_ty] = runtime.assignValue(_sym); +if (runtime.opEq(_sym_ty, ({ type: "string", value: "builtin" }))) { +let [, _id] = runtime.assignValue(_sym); +(runtime.setLine(71), _emit((runtime.setLine(71), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "((...args) => runtime.%(...args))" }), _id)))); +} else { +if (runtime.opEq(_sym_ty, ({ type: "string", value: "fn" }))) { +(runtime.setLine(73), _emit((runtime.setLine(73), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "_%" }), _value)))); +} else { +if (runtime.opEq(_sym_ty, ({ type: "string", value: "param" }))) { +(runtime.setLine(75), _emit((runtime.setLine(75), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "_%" }), _value)))); +} else { +if (runtime.opEq(_sym_ty, ({ type: "string", value: "let" }))) { +(runtime.setLine(77), _emit((runtime.setLine(77), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "_%" }), _value)))); +} else { +(runtime.setLine(79), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "not implemented '%'" }), _sym_ty)); +}}}}; +} else { +(runtime.setLine(82), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "unknown expr type '%' on line %" }), _ty, _line)); +}}}}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _emit_list(_expr) { +runtime.pushCall("emit_list"); +let [_ty, _line, _s] = runtime.assignValue(_expr); +if (runtime.opEq((runtime.setLine(88), ((...args) => runtime.builtinLen(...args))(_s)), ({ type: "int", value: 0 }))) { +(runtime.setLine(89), _emit(({ type: "string", value: "({ type: \"list\", values: [] })" }))); +runtime.popCall(); +return { type: "null" }; +}; +let [[_id_ty, , _id]] = runtime.assignValue(_s); +if (runtime.opNe(_id_ty, ({ type: "string", value: "ident" }))) { +(runtime.setLine(94), _emit(({ type: "string", value: "({ type: \"list\", values: [] })" }))); +runtime.popCall(); +return { type: "null" }; +}; +if (runtime.opEq(_id, ({ type: "string", value: "fn" }))) { +let [, [, , _name], [, , _params], _body] = runtime.assignValue(_s); +(runtime.setLine(99), _emit((runtime.setLine(99), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "function _%(" }), _name)))); +(runtime.setLine(101), _enter_scope()); +let _first = runtime.assignValue(({ type: "bool", value: true })); +for (let [, , _name] of _params) { +if (runtime.opNot(_first)) { +(runtime.setLine(106), _emit(({ type: "string", value: ", " }))); +}; +(_first = runtime.assignValue(({ type: "bool", value: false }))); +(runtime.setLine(110), _emit((runtime.setLine(110), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "_%" }), _name)))); +(runtime.setLine(112), _define_sym(_name, ({ type: "list", values: [] }))); +}; +(runtime.setLine(116), _emit((runtime.setLine(116), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: ") {\n" }), _name)))); +(runtime.setLine(117), _emit((runtime.setLine(117), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "runtime.pushCall(\"%\");\n" }), _name)))); +(runtime.setLine(119), _emit_expr(_body)); +(runtime.setLine(120), _emit(({ type: "string", value: ";\nruntime.popCall();\nreturn { type: \"null\" };\n}" }))); +(runtime.setLine(122), _leave_scope()); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "let" }))) { +let [, _pat, _expr] = runtime.assignValue(_s); +(runtime.setLine(125), _emit(({ type: "string", value: "let " }))); +(runtime.setLine(126), _emit_pat(_pat)); +(runtime.setLine(127), _emit(({ type: "string", value: " = runtime.assignValue(" }))); +(runtime.setLine(128), _emit_expr(_expr)); +(runtime.setLine(129), _emit(({ type: "string", value: ")" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "do" }))) { +(runtime.setLine(131), _enter_scope()); +(runtime.setLine(132), _discover_syms((runtime.setLine(132), _slice(_s, ({ type: "int", value: 1 }))))); +(runtime.setLine(133), _emit_exprs((runtime.setLine(133), _slice(_s, ({ type: "int", value: 1 }))))); +(runtime.setLine(134), _leave_scope()); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "for" }))) { +let [, _pat, _expr, _body] = runtime.assignValue(_s); +(runtime.setLine(137), _enter_scope()); +(runtime.setLine(138), _emit(({ type: "string", value: "for (let " }))); +(runtime.setLine(139), _emit_pat(_pat)); +(runtime.setLine(140), _emit(({ type: "string", value: " of " }))); +(runtime.setLine(141), _emit_expr(_expr)); +(runtime.setLine(142), _emit(({ type: "string", value: ") {\n" }))); +(runtime.setLine(143), _emit_expr(_body)); +(runtime.setLine(144), _emit(({ type: "string", value: "}" }))); +(runtime.setLine(145), _leave_scope()); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "loop" }))) { +let [, _body] = runtime.assignValue(_s); +(runtime.setLine(148), _emit(({ type: "string", value: "while (true) {\n" }))); +(runtime.setLine(149), _emit_expr(_body)); +(runtime.setLine(150), _emit(({ type: "string", value: "}" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "if" }))) { +let [, _cond, _truthy, _falsy] = runtime.assignValue(_s); +(runtime.setLine(153), _emit(({ type: "string", value: "if (" }))); +(runtime.setLine(154), _emit_expr(_cond)); +(runtime.setLine(155), _emit(({ type: "string", value: ") {\n" }))); +(runtime.setLine(156), _emit_expr(_truthy)); +(runtime.setLine(157), _emit(({ type: "string", value: "}" }))); +if (runtime.opNe(_falsy, ({ type: "null" }))) { +(runtime.setLine(159), _emit(({ type: "string", value: " else {\n" }))); +(runtime.setLine(160), _emit_expr(_falsy)); +(runtime.setLine(161), _emit(({ type: "string", value: "}" }))); +}; +} else { +if (runtime.opEq(_id, ({ type: "string", value: "return" }))) { +let [, _value] = runtime.assignValue(_s); +(runtime.setLine(165), _emit(({ type: "string", value: "runtime.popCall();\n" }))); +(runtime.setLine(166), _emit(({ type: "string", value: "return " }))); +if (runtime.opNe(_value, ({ type: "null" }))) { +(runtime.setLine(168), _emit_expr(_value)); +} else { +(runtime.setLine(170), _emit(({ type: "string", value: "{ type: \"null\" }" }))); +}; +} else { +if (runtime.opEq(_id, ({ type: "string", value: "break" }))) { +let [, _value] = runtime.assignValue(_s); +(runtime.setLine(174), _emit(({ type: "string", value: "break" }))); +if (runtime.opNe(_value, ({ type: "null" }))) { +(runtime.setLine(176), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "not implemented" }))); +}; +} else { +if (runtime.opEq(_id, ({ type: "string", value: "call" }))) { +let [, _callee] = runtime.assignValue(_s); +let _args = runtime.assignValue((runtime.setLine(180), _slice(_s, ({ type: "int", value: 2 })))); +(runtime.setLine(181), _emit((runtime.setLine(181), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "(runtime.setLine(%), " }), _line)))); +(runtime.setLine(182), _emit_expr(_callee)); +(runtime.setLine(183), _emit(({ type: "string", value: "(" }))); +let _first = runtime.assignValue(({ type: "bool", value: true })); +for (let _arg of _args) { +if (runtime.opNot(_first)) { +(runtime.setLine(188), _emit(({ type: "string", value: ", " }))); +}; +(_first = runtime.assignValue(({ type: "bool", value: false }))); +(runtime.setLine(192), _emit_expr(_arg)); +}; +(runtime.setLine(195), _emit(({ type: "string", value: "))" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "=" }))) { +(runtime.setLine(197), _emit_assign_expr(_s, _line, ({ type: "string", value: "=" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "+=" }))) { +(runtime.setLine(199), _emit_assign_expr(_s, _line, ({ type: "string", value: "+" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "-=" }))) { +(runtime.setLine(201), _emit_assign_expr(_s, _line, ({ type: "string", value: "-" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "or" }))) { +let [, _left, _right] = runtime.assignValue(_s); +(runtime.setLine(204), _emit((runtime.setLine(204), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "(runtime.setLine(%)" }), _line)))); +(runtime.setLine(205), _emit(({ type: "string", value: ", { type: \"bool\", value: this.runtime.truthy(" }))); +(runtime.setLine(206), _emit_expr(_left)); +(runtime.setLine(207), _emit(({ type: "string", value: ") || this.runtime.falsy(" }))); +(runtime.setLine(208), _emit_expr(_right)); +(runtime.setLine(209), _emit(({ type: "string", value: ") })" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "and" }))) { +let [, _left, _right] = runtime.assignValue(_s); +(runtime.setLine(212), _emit((runtime.setLine(212), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "(runtime.setLine(%)" }), _line)))); +(runtime.setLine(213), _emit(({ type: "string", value: ", { type: \"bool\", value: this.runtime.truthy(" }))); +(runtime.setLine(214), _emit_expr(_left)); +(runtime.setLine(215), _emit(({ type: "string", value: ") && this.runtime.falsy(" }))); +(runtime.setLine(216), _emit_expr(_right)); +(runtime.setLine(217), _emit(({ type: "string", value: ") })" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "==" }))) { +(runtime.setLine(219), _emit_binary_op(_s, ({ type: "string", value: "opEq" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "!=" }))) { +(runtime.setLine(221), _emit_binary_op(_s, ({ type: "string", value: "opNe" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "<" }))) { +(runtime.setLine(223), _emit_binary_op(_s, ({ type: "string", value: "opLt" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: ">" }))) { +(runtime.setLine(225), _emit_binary_op(_s, ({ type: "string", value: "opGt" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "<=" }))) { +(runtime.setLine(227), _emit_binary_op(_s, ({ type: "string", value: "opLte" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: ">=" }))) { +(runtime.setLine(229), _emit_binary_op(_s, ({ type: "string", value: "opGte" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "+" }))) { +(runtime.setLine(231), _emit_binary_op(_s, ({ type: "string", value: "opAdd" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "-" }))) { +(runtime.setLine(233), _emit_binary_op(_s, ({ type: "string", value: "opSub" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "not" }))) { +let [, _expr] = runtime.assignValue(_s); +(runtime.setLine(236), _emit(({ type: "string", value: "runtime.opNot(" }))); +(runtime.setLine(237), _emit_expr(_expr)); +(runtime.setLine(238), _emit(({ type: "string", value: ")" }))); +} else { +(runtime.setLine(240), _emit(({ type: "string", value: "({ type: \"list\", values: [" }))); +let _first = runtime.assignValue(({ type: "bool", value: true })); +for (let _e of _s) { +if (runtime.opNot(_first)) { +(runtime.setLine(244), _emit(({ type: "string", value: ", " }))); +}; +(_first = runtime.assignValue(({ type: "bool", value: false }))); +(runtime.setLine(248), _emit_expr(_e)); +}; +(runtime.setLine(250), _emit(({ type: "string", value: "] })" }))); +}}}}}}}}}}}}}}}}}}}}}}}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _emit_binary_op(_s, _id) { +runtime.pushCall("emit_binary_op"); +let [, _left, _right] = runtime.assignValue(_s); +(runtime.setLine(256), _emit((runtime.setLine(256), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "runtime.%(" }), _id)))); +(runtime.setLine(257), _emit_expr(_left)); +(runtime.setLine(258), _emit(({ type: "string", value: ", " }))); +(runtime.setLine(259), _emit_expr(_right)); +(runtime.setLine(260), _emit(({ type: "string", value: ")" }))); +; +runtime.popCall(); +return { type: "null" }; +}; +function _emit_assign_expr(_s, _line, _id) { +runtime.pushCall("emit_assign_expr"); +let [, [_target_type], _expr] = runtime.assignValue(_s); +if (runtime.opEq(_target_type, ({ type: "string", value: "ident" }))) { +let [, [, , _ident]] = runtime.assignValue(_s); +let _sym = runtime.assignValue((runtime.setLine(267), _get_sym(_ident))); +if (runtime.opEq(_sym, ({ type: "null" }))) { +(runtime.setLine(269), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "could not find symbol '%' on line %" }), _ident, _line)); +}; +let [_sym_type, _sym_ident, ] = runtime.assignValue(_sym); +if (runtime.opEq(_sym_type, ({ type: "string", value: "let" }))) { +(runtime.setLine(273), _emit((runtime.setLine(273), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "(_% = runtime.assignValue(" }), _sym_ident)))); +if (runtime.opEq(_id, ({ type: "string", value: "=" }))) { +(runtime.setLine(275), _emit_expr(_expr)); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "+" }))) { +(runtime.setLine(277), _emit((runtime.setLine(277), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "runtime.opAdd(_%, " }), _sym_ident)))); +(runtime.setLine(278), _emit_expr(_expr)); +(runtime.setLine(279), _emit(({ type: "string", value: ")" }))); +} else { +if (runtime.opEq(_id, ({ type: "string", value: "-" }))) { +(runtime.setLine(281), _emit((runtime.setLine(281), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "runtime.opSub(_%, " }), _sym_ident)))); +(runtime.setLine(282), _emit_expr(_expr)); +(runtime.setLine(283), _emit(({ type: "string", value: ")" }))); +} else { +(runtime.setLine(285), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "not implemented" }))); +}}}; +(runtime.setLine(287), _emit(({ type: "string", value: "))" }))); +} else { +(runtime.setLine(289), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "cannot assign to symbol '%' on line %" }), _sym_ident, _line)); +}; +} else { +(runtime.setLine(292), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "cannot assign to expression on line %" }), _line)); +}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _emit_pat(_pat) { +runtime.pushCall("emit_pat"); +let [_ty] = runtime.assignValue(_pat); +if (runtime.opEq(_ty, ({ type: "string", value: "ident" }))) { +let [, _line, _name] = runtime.assignValue(_pat); +if (runtime.opEq(_name, ({ type: "string", value: "_" }))) { +runtime.popCall(); +return { type: "null" }; +}; +(runtime.setLine(303), _emit((runtime.setLine(303), ((...args) => runtime.builtinFormat(...args))(({ type: "string", value: "_%" }), _name)))); +(runtime.setLine(304), _define_sym(_name, ({ type: "list", values: [] }))); +} else { +if (runtime.opEq(_ty, ({ type: "string", value: "list" }))) { +let [, , _pats] = runtime.assignValue(_pat); +(runtime.setLine(307), _emit(({ type: "string", value: "[" }))); +let _first = runtime.assignValue(({ type: "bool", value: true })); +for (let _pat of _pats) { +if (runtime.opNot(_first)) { +(runtime.setLine(311), _emit(({ type: "string", value: ", " }))); +}; +(_first = runtime.assignValue(({ type: "bool", value: false }))); +(runtime.setLine(315), _emit_pat(_pat)); +}; +(runtime.setLine(317), _emit(({ type: "string", value: "]" }))); +} else { +(runtime.setLine(319), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "cannot assign to '%'" }), _pat)); +}}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _emit(_str) { +runtime.pushCall("emit"); +(runtime.setLine(324), ((...args) => runtime.builtinPush(...args))(_output, _str)); +; +runtime.popCall(); +return { type: "null" }; +}; +runtime.popCall(); +return ({ type: "list", values: [_generate] }); +; +runtime.popCall(); +return { type: "null" }; +}; +function _Syms() { +runtime.pushCall("Syms"); +let _syms = runtime.assignValue(({ type: "list", values: [({ type: "null" }), ({ type: "list", values: [] })] })); +function _enter_scope() { +runtime.pushCall("enter_scope"); +(_syms = runtime.assignValue(({ type: "list", values: [_syms, ({ type: "list", values: [] })] }))); +; +runtime.popCall(); +return { type: "null" }; +}; +function _leave_scope() { +runtime.pushCall("leave_scope"); +let [_parent, ] = runtime.assignValue(_syms); +(_syms = runtime.assignValue(_parent)); +; +runtime.popCall(); +return { type: "null" }; +}; +function _define(_ident, _sym) { +runtime.pushCall("define"); +let [, _syms] = runtime.assignValue(_syms); +let _i = runtime.assignValue(({ type: "int", value: 0 })); +while (true) { +if (runtime.opGte(_i, (runtime.setLine(361), ((...args) => runtime.builtinLen(...args))(_syms)))) { +break}; +let [_s_ident, ] = runtime.assignValue((runtime.setLine(362), ((...args) => runtime.builtinAt(...args))(_syms, _i))); +if (runtime.opEq(_ident, _s_ident)) { +(runtime.setLine(364), ((...args) => runtime.builtinSet(...args))(_syms, _i, ({ type: "list", values: [_ident, _sym] }))); +runtime.popCall(); +return { type: "null" }; +}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +(runtime.setLine(369), ((...args) => runtime.builtinPush(...args))(_syms, ({ type: "list", values: [_ident, _sym] }))); +; +runtime.popCall(); +return { type: "null" }; +}; +function _find_sym(_syms, _ident) { +runtime.pushCall("find_sym"); +let [_parent, _map] = runtime.assignValue(_syms); +let _i = runtime.assignValue(({ type: "int", value: 0 })); +while (true) { +if (runtime.opGte(_i, (runtime.setLine(376), ((...args) => runtime.builtinLen(...args))(_map)))) { +break}; +let [_s_ident, _s_sym] = runtime.assignValue((runtime.setLine(377), ((...args) => runtime.builtinAt(...args))(_map, _i))); +if (runtime.opEq(_ident, _s_ident)) { +runtime.popCall(); +return _s_sym; +}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +if (runtime.opNe(_parent, ({ type: "null" }))) { +runtime.popCall(); +return (runtime.setLine(384), _find_sym(_parent, _ident)); +}; +runtime.popCall(); +return ({ type: "null" }); +; +runtime.popCall(); +return { type: "null" }; +}; +function _get(_ident) { +runtime.pushCall("get"); +runtime.popCall(); +return (runtime.setLine(390), _find_sym(_syms, _ident)); +; +runtime.popCall(); +return { type: "null" }; +}; +runtime.popCall(); +return ({ type: "list", values: [_enter_scope, _leave_scope, _define, _get] }); +; +runtime.popCall(); +return { type: "null" }; +}; +function _string_escape(_str) { +runtime.pushCall("string_escape"); +let _str_len = runtime.assignValue((runtime.setLine(403), ((...args) => runtime.builtinLen(...args))(_str))); +let _i = runtime.assignValue(({ type: "int", value: 0 })); +let _result = runtime.assignValue(({ type: "string", value: "" })); +while (true) { +if (runtime.opGte(_i, _str_len)) { +break}; +let _ch = runtime.assignValue((runtime.setLine(408), ((...args) => runtime.builtinAt(...args))(_str, _i))); +if (runtime.opEq(_ch, ({ type: "string", value: "\\" }))) { +(_result = runtime.assignValue(runtime.opAdd(_result, ({ type: "string", value: "\\\\" })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "\"" }))) { +(_result = runtime.assignValue(runtime.opAdd(_result, ({ type: "string", value: "\\\"" })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "\t" }))) { +(_result = runtime.assignValue(runtime.opAdd(_result, ({ type: "string", value: "\\t" })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "\r" }))) { +(_result = runtime.assignValue(runtime.opAdd(_result, ({ type: "string", value: "\\r" })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "\n" }))) { +(_result = runtime.assignValue(runtime.opAdd(_result, ({ type: "string", value: "\\n" })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "\n" }))) { +(_result = runtime.assignValue(runtime.opAdd(_result, ({ type: "string", value: "\\0" })))); +} else { +(_result = runtime.assignValue(runtime.opAdd(_result, _ch))); +}}}}}}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +runtime.popCall(); +return _result; +; +runtime.popCall(); +return { type: "null" }; +}; +function _Parser(_tokens) { +runtime.pushCall("Parser"); +let _i = runtime.assignValue(({ type: "int", value: 0 })); +let _tok = runtime.assignValue((runtime.setLine(431), ((...args) => runtime.builtinAt(...args))(_tokens, _i))); +function _parse() { +runtime.pushCall("parse"); +let _exprs = runtime.assignValue(({ type: "list", values: [] })); +while (true) { +if ((runtime.setLine(436), _done())) { +break}; +(runtime.setLine(437), ((...args) => runtime.builtinPush(...args))(_exprs, (runtime.setLine(437), _parse_expr()))); +}; +runtime.popCall(); +return _exprs; +; +runtime.popCall(); +return { type: "null" }; +}; +function _parse_expr() { +runtime.pushCall("parse_expr"); +let [_ty, _line, _value] = runtime.assignValue(_tok); +if ((runtime.setLine(444), _eat(({ type: "string", value: "(" })))) { +let _values = runtime.assignValue(({ type: "list", values: [] })); +while (true) { +if ((runtime.setLine(447), _test(({ type: "string", value: ")" })))) { +break}; +(runtime.setLine(448), ((...args) => runtime.builtinPush(...args))(_values, (runtime.setLine(448), _parse_expr()))); +}; +if (runtime.opNot((runtime.setLine(450), _eat(({ type: "string", value: ")" }))))) { +(runtime.setLine(451), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "expected ')' on line %" }), (runtime.setLine(451), ((...args) => runtime.builtinAt(...args))(_tok, ({ type: "int", value: 1 }))))); +}; +runtime.popCall(); +return ({ type: "list", values: [] }); +} else { +if ((runtime.setLine(454), _eat(({ type: "string", value: "string" })))) { +runtime.popCall(); +return ({ type: "list", values: [] }); +} else { +if ((runtime.setLine(456), _eat(({ type: "string", value: "int" })))) { +runtime.popCall(); +return ({ type: "list", values: [] }); +} else { +if ((runtime.setLine(458), _eat(({ type: "string", value: "ident" })))) { +runtime.popCall(); +return ({ type: "list", values: [] }); +} else { +(runtime.setLine(461), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "expected expression, got '%' on line %" }), _ty, _line)); +}}}}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _eat(_pat) { +runtime.pushCall("eat"); +if (runtime.opNot((runtime.setLine(466), _test(_pat)))) { +runtime.popCall(); +return ({ type: "bool", value: false })}; +(runtime.setLine(467), _step()); +runtime.popCall(); +return ({ type: "bool", value: true }); +; +runtime.popCall(); +return { type: "null" }; +}; +function _step() { +runtime.pushCall("step"); +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +if (runtime.opNot((runtime.setLine(473), _done()))) { +let _new_tok = runtime.assignValue((runtime.setLine(474), ((...args) => runtime.builtinAt(...args))(_tokens, _i))); +(_tok = runtime.assignValue(_new_tok)); +}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _test(_pat) { +runtime.pushCall("test"); +if ((runtime.setLine(480), _done())) { +runtime.popCall(); +return ({ type: "bool", value: false })}; +let [_ty] = runtime.assignValue(_tok); +runtime.popCall(); +return runtime.opEq(_pat, _ty); +; +runtime.popCall(); +return { type: "null" }; +}; +function _done() { +runtime.pushCall("done"); +runtime.popCall(); +return runtime.opGte(_i, (runtime.setLine(486), ((...args) => runtime.builtinLen(...args))(_tokens))); +; +runtime.popCall(); +return { type: "null" }; +}; +runtime.popCall(); +return ({ type: "list", values: [_parse] }); +; +runtime.popCall(); +return { type: "null" }; +}; +function _tokenize(_text) { +runtime.pushCall("tokenize"); +let _text_len = runtime.assignValue((runtime.setLine(493), ((...args) => runtime.builtinLen(...args))(_text))); +let _tokens = runtime.assignValue(({ type: "list", values: [] })); +let _i = runtime.assignValue(({ type: "int", value: 0 })); +let _line = runtime.assignValue(({ type: "int", value: 1 })); +let _ident_chars = runtime.assignValue(runtime.opAdd(({ type: "string", value: "abcdefghijklmnopqrstuvwxyz" }), ({ type: "string", value: "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-*/%&|=?!<>'_" }))); +while (true) { +if (runtime.opGte(_i, _text_len)) { +break}; +let _ch = runtime.assignValue((runtime.setLine(505), ((...args) => runtime.builtinAt(...args))(_text, _i))); +if ((runtime.setLine(507), _contains(({ type: "string", value: " \t\r\n" }), _ch))) { +if (runtime.opEq(_ch, ({ type: "string", value: "\n" }))) { +(_line = runtime.assignValue(runtime.opAdd(_line, ({ type: "int", value: 1 })))); +}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +} else { +if ((runtime.setLine(512), _slice_eq(_text, _i, ({ type: "string", value: "//" })))) { +while (true) { +if ((runtime.setLine(514), { type: "bool", value: this.runtime.truthy(runtime.opGte(_i, _text_len)) || this.runtime.falsy(runtime.opEq((runtime.setLine(514), ((...args) => runtime.builtinAt(...args))(_text, _i)), ({ type: "string", value: "\n" }))) })) { +break; +}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +} else { +if ((runtime.setLine(519), _contains(({ type: "string", value: "()" }), _ch))) { +(runtime.setLine(520), ((...args) => runtime.builtinPush(...args))(_tokens, ({ type: "list", values: [_ch, _line] }))); +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "\"" }))) { +let _value = runtime.assignValue(({ type: "string", value: "" })); +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +(_ch = runtime.assignValue((runtime.setLine(525), ((...args) => runtime.builtinAt(...args))(_text, _i)))); +while (true) { +if ((runtime.setLine(527), { type: "bool", value: this.runtime.truthy(runtime.opGte(_i, _text_len)) || this.runtime.falsy(runtime.opEq(_ch, ({ type: "string", value: "\"" }))) })) { +break; +}; +if (runtime.opEq(_ch, ({ type: "string", value: "\\" }))) { +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +if (runtime.opGte(_i, _text_len)) { +break; +}; +(_ch = runtime.assignValue((runtime.setLine(535), ((...args) => runtime.builtinAt(...args))(_text, _i)))); +if (runtime.opEq(_ch, ({ type: "string", value: "t" }))) { +(_value = runtime.assignValue(runtime.opAdd(_value, ({ type: "string", value: "\t" })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "r" }))) { +(_value = runtime.assignValue(runtime.opAdd(_value, ({ type: "string", value: "\r" })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "n" }))) { +(_value = runtime.assignValue(runtime.opAdd(_value, ({ type: "string", value: "\n" })))); +} else { +if (runtime.opEq(_ch, ({ type: "string", value: "0" }))) { +(_value = runtime.assignValue(runtime.opAdd(_value, ({ type: "string", value: "\n" })))); +} else { +(_value = runtime.assignValue(runtime.opAdd(_value, _ch))); +}}}}; +} else { +(_value = runtime.assignValue(runtime.opAdd(_value, _ch))); +}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +(_ch = runtime.assignValue((runtime.setLine(551), ((...args) => runtime.builtinAt(...args))(_text, _i)))); +}; +if ((runtime.setLine(553), { type: "bool", value: this.runtime.truthy(runtime.opGte(_i, _text_len)) || this.runtime.falsy(runtime.opNe(_ch, ({ type: "string", value: "\"" }))) })) { +(runtime.setLine(554), ((...args) => runtime.builtinPanic(...args))(({ type: "string", value: "expected '\"' on line %" }), _line)); +}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +(runtime.setLine(557), ((...args) => runtime.builtinPush(...args))(_tokens, ({ type: "list", values: [] }))); +} else { +if ((runtime.setLine(558), _contains(({ type: "string", value: "0123456789" }), _ch))) { +let _value = runtime.assignValue(({ type: "string", value: "" })); +while (true) { +(_ch = runtime.assignValue((runtime.setLine(561), ((...args) => runtime.builtinAt(...args))(_text, _i)))); +if ((runtime.setLine(562), { type: "bool", value: this.runtime.truthy(runtime.opGte(_i, _text_len)) || this.runtime.falsy(runtime.opNot((runtime.setLine(562), _contains(({ type: "string", value: "0123456789" }), _ch)))) })) { +break; +}; +(_value = runtime.assignValue(runtime.opAdd(_value, _ch))); +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +(runtime.setLine(568), ((...args) => runtime.builtinPush(...args))(_tokens, ({ type: "list", values: [] }))); +} else { +if ((runtime.setLine(569), _contains(_ident_chars, _ch))) { +let _value = runtime.assignValue(({ type: "string", value: "" })); +while (true) { +(_ch = runtime.assignValue((runtime.setLine(572), ((...args) => runtime.builtinAt(...args))(_text, _i)))); +if ((runtime.setLine(573), { type: "bool", value: this.runtime.truthy(runtime.opGte(_i, _text_len)) || this.runtime.falsy(runtime.opNot((runtime.setLine(573), _contains(_ident_chars, _ch)))) })) { +break; +}; +(_value = runtime.assignValue(runtime.opAdd(_value, _ch))); +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +(runtime.setLine(579), ((...args) => runtime.builtinPush(...args))(_tokens, ({ type: "list", values: [] }))); +} else { +(runtime.setLine(581), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "illegal char '%'" }), _ch)); +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}}}}}}; +}; +runtime.popCall(); +return _tokens; +; +runtime.popCall(); +return { type: "null" }; +}; +function _contains(_text, _ch) { +runtime.pushCall("contains"); +let _text_len = runtime.assignValue((runtime.setLine(590), ((...args) => runtime.builtinLen(...args))(_text))); +let _i = runtime.assignValue(({ type: "int", value: 0 })); +while (true) { +if (runtime.opGte(_i, _text_len)) { +break}; +if (runtime.opEq((runtime.setLine(594), ((...args) => runtime.builtinAt(...args))(_text, _i)), _ch)) { +runtime.popCall(); +return ({ type: "bool", value: true }); +}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +runtime.popCall(); +return ({ type: "bool", value: false }); +; +runtime.popCall(); +return { type: "null" }; +}; +function _slice_eq(_str, _slice_idx, _substr) { +runtime.pushCall("slice_eq"); +let _str_len = runtime.assignValue((runtime.setLine(603), ((...args) => runtime.builtinLen(...args))(_str))); +let _substr_len = runtime.assignValue((runtime.setLine(604), ((...args) => runtime.builtinLen(...args))(_substr))); +let _i = runtime.assignValue(({ type: "int", value: 0 })); +while (true) { +if (runtime.opGte(_i, _substr_len)) { +runtime.popCall(); +return ({ type: "bool", value: true })}; +if (runtime.opGte(runtime.opAdd(_slice_idx, _i), _str_len)) { +runtime.popCall(); +return ({ type: "bool", value: false })}; +if (runtime.opNe((runtime.setLine(611), ((...args) => runtime.builtinAt(...args))(_str, runtime.opAdd(_slice_idx, _i))), (runtime.setLine(611), ((...args) => runtime.builtinAt(...args))(_substr, _i)))) { +runtime.popCall(); +return ({ type: "bool", value: false })}; +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +runtime.popCall(); +return ({ type: "bool", value: true }); +; +runtime.popCall(); +return { type: "null" }; +}; +function _print_expr(_expr, _depth) { +runtime.pushCall("print_expr"); +let [_ty, _line, _value] = runtime.assignValue(_expr); +if (runtime.opEq(_ty, ({ type: "string", value: "list" }))) { +(runtime.setLine(621), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "%(% %" }), (runtime.setLine(621), _indent(_depth)), _ty, _line)); +for (let _e of _value) { +(runtime.setLine(623), _print_expr(_e, runtime.opAdd(_depth, ({ type: "int", value: 1 })))); +}; +(runtime.setLine(625), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "%)" }), (runtime.setLine(625), _indent(_depth)))); +} else { +(runtime.setLine(627), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "%%" }), (runtime.setLine(627), _indent(_depth)), _expr)); +}; +; +runtime.popCall(); +return { type: "null" }; +}; +function _indent(_depth) { +runtime.pushCall("indent"); +let _space = runtime.assignValue(({ type: "string", value: "" })); +let _i = runtime.assignValue(({ type: "int", value: 0 })); +while (true) { +if (runtime.opGte(_i, _depth)) { +break}; +(_space = runtime.assignValue(runtime.opAdd(_space, ({ type: "string", value: " " })))); +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +runtime.popCall(); +return _space; +; +runtime.popCall(); +return { type: "null" }; +}; +function _slice(_list, _idx) { +runtime.pushCall("slice"); +let _list_len = runtime.assignValue((runtime.setLine(643), ((...args) => runtime.builtinLen(...args))(_list))); +let _elems = runtime.assignValue(({ type: "list", values: [] })); +let _i = runtime.assignValue(_idx); +while (true) { +if (runtime.opGte(_i, _list_len)) { +break}; +(runtime.setLine(648), ((...args) => runtime.builtinPush(...args))(_elems, (runtime.setLine(648), ((...args) => runtime.builtinAt(...args))(_list, _i)))); +(_i = runtime.assignValue(runtime.opAdd(_i, ({ type: "int", value: 1 })))); +}; +runtime.popCall(); +return _elems; +; +runtime.popCall(); +return { type: "null" }; +}; +let _silent = runtime.assignValue(({ type: "bool", value: true })); +let [_input_filename, _output_filename] = runtime.assignValue((runtime.setLine(656), ((...args) => runtime.builtinGetArgs(...args))())); +if (runtime.opNot(_silent)) { +(runtime.setLine(658), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "reading file..." })))}; +let _text = runtime.assignValue((runtime.setLine(659), ((...args) => runtime.builtinReadTextFile(...args))(_input_filename))); +if (runtime.opNot(_silent)) { +(runtime.setLine(664), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "tokenizing..." })))}; +let _tokens = runtime.assignValue((runtime.setLine(665), _tokenize(_text))); +if (runtime.opNot(_silent)) { +(runtime.setLine(672), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "parsing..." })))}; +let _parser = runtime.assignValue((runtime.setLine(673), _Parser(_tokens))); +let [_parse] = runtime.assignValue(_parser); +let _ast = runtime.assignValue((runtime.setLine(675), _parse())); +if (runtime.opNot(_silent)) { +(runtime.setLine(682), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "emitting..." })))}; +let _emitter = runtime.assignValue((runtime.setLine(683), _Emitter(_ast, _input_filename))); +let [_emit] = runtime.assignValue(_emitter); +let _js_code = runtime.assignValue((runtime.setLine(685), _emit())); +if (runtime.opNot(_silent)) { +(runtime.setLine(690), ((...args) => runtime.builtinPrintln(...args))(({ type: "string", value: "writing file..." })))}; +(runtime.setLine(691), ((...args) => runtime.builtinWriteTextFile(...args))(_output_filename, _js_code));