more compiler stuff

This commit is contained in:
Simon From Jakobsen 2025-09-19 15:20:30 +02:00
parent e325188f46
commit bdb3117e07
6 changed files with 1002 additions and 81 deletions

View File

@ -19,7 +19,6 @@
(for expr exprs (do (for expr exprs (do
(call emit_expr expr) (call emit_expr expr)
(call emit ";\n") (call emit ";\n")
)) ))
)) ))
@ -27,7 +26,7 @@
(for expr exprs (do (for expr exprs (do
(let (ty line) expr) (let (ty line) expr)
(if (!= ty "list") (return)) (if (!= ty "list") (return))
(let (ty line s) expr) (let (_ _ s) expr)
(if (== (call len s) 0) (return)) (if (== (call len s) 0) (return))
(let ((_ _ id)) s) (let ((_ _ id)) s)
(if (== id "fn") (do (if (== id "fn") (do
@ -43,21 +42,21 @@
(call emit_list expr) (call emit_list expr)
) (if (== ty "int") ( ) (if (== ty "int") (
(let (_ _ value) expr) (let (_ _ value) expr)
(call emit (call format "{ type: \"int\", value: % }" value)) (call emit (call format "({ type: \"int\", value: % })" value))
) (if (== ty "string") ( ) (if (== ty "string") (
(let (_ _ value) expr) (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 ) (if (== ty "ident") (do
(let (_ _ value) expr) (let (_ _ value) expr)
(if (== value "null") (do (if (== value "null") (do
(call emit "{ type: \"null\" }") (call emit "({ type: \"null\" })")
(return) (return)
) (if (== value "false") (do ) (if (== value "false") (do
(call emit "{ type: \"bool\", value: false }") (call emit "({ type: \"bool\", value: false })")
(return) (return)
) (if (== value "true") (do ) (if (== value "true") (do
(call emit "{ type: \"bool\", value: true }") (call emit "({ type: \"bool\", value: true })")
(return) (return)
)))) ))))
@ -87,12 +86,12 @@
(fn emit_list (expr) (do (fn emit_list (expr) (do
(let (ty line s) expr) (let (ty line s) expr)
(if (== (call len s) 0) (do (if (== (call len s) 0) (do
(call emit "{ type: \"list\", values: [] }") (call emit "({ type: \"list\", values: [] })")
(return) (return)
)) ))
(let ((id_ty _ id)) s) (let ((id_ty _ id)) s)
(if (!= id_ty "ident") (do (if (!= id_ty "ident") (do
(call emit "{ type: \"list\", values: [] }") (call emit "({ type: \"list\", values: [] })")
(return) (return)
)) ))
(if (== id "fn") (do (if (== id "fn") (do
@ -115,18 +114,19 @@
(call emit (call format ") {\n" name)) (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_expr body)
(call emit "}") (call emit ";\nruntime.popCall();\nreturn { type: \"null\" };\n}")
(call leave_scope) (call leave_scope)
) (if (== id "let") (do ) (if (== id "let") (do
(let (_ pat expr) s) (let (_ pat expr) s)
(call emit "let ") (call emit "let ")
(call emit_pat pat) (call emit_pat pat)
(call emit " = ") (call emit " = runtime.assignValue(")
(call emit_expr expr) (call emit_expr expr)
(call emit ")")
) (if (== id "do") (do ) (if (== id "do") (do
(call enter_scope) (call enter_scope)
(call discover_syms (call slice s 1)) (call discover_syms (call slice s 1))
@ -134,6 +134,7 @@
(call leave_scope) (call leave_scope)
) (if (== id "for") (do ) (if (== id "for") (do
(let (_ pat expr body) s) (let (_ pat expr body) s)
(call enter_scope)
(call emit "for (let ") (call emit "for (let ")
(call emit_pat pat) (call emit_pat pat)
(call emit " of ") (call emit " of ")
@ -141,6 +142,12 @@
(call emit ") {\n") (call emit ") {\n")
(call emit_expr body) (call emit_expr body)
(call emit "}") (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 ) (if (== id "if") (do
(let (_ cond truthy falsy) s) (let (_ cond truthy falsy) s)
(call emit "if (") (call emit "if (")
@ -160,7 +167,13 @@
(if (!= value null) (do (if (!= value null) (do
(call emit_expr value) (call emit_expr value)
) (do ) (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 ) (if (== id "call") (do
(let (_ callee) s) (let (_ callee) s)
@ -181,28 +194,50 @@
(call emit "))") (call emit "))")
) (if (== id "=") (do ) (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 ) (if (== id "==") (do
(let (_ left right) s) (call emit_binary_op s "opEq")
(call emit "runtime.opEq(")
(call emit_expr left)
(call emit ", ")
(call emit_expr right)
(call emit ")")
) (if (== id "!=") (do ) (if (== id "!=") (do
(let (_ left right) s) (call emit_binary_op s "opNe")
(call emit "runtime.opNe(") ) (if (== id "<") (do
(call emit_expr left) (call emit_binary_op s "opLt")
(call emit ", ") ) (if (== id ">") (do
(call emit_expr right) (call emit_binary_op s "opGt")
(call emit ")") ) (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 ) (if (== id "not") (do
(let (_ expr) s) (let (_ expr) s)
(call emit "runtime.opNot(") (call emit "runtime.opNot(")
(call emit_expr expr) (call emit_expr expr)
(call emit ")") (call emit ")")
) (do ) (do
(call emit "{ type: \"list\", values: [") (call emit "({ type: \"list\", values: [")
(let first true) (let first true)
(for e s (do (for e s (do
(if (not first) (do (if (not first) (do
@ -212,8 +247,50 @@
(call emit_expr e) (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 (fn emit_pat (pat) (do
@ -223,7 +300,7 @@
(if (== name "_") (do (if (== name "_") (do
(return) (return)
)) ))
(call emit name) (call emit (call format "_%" name))
(call define_sym name ("let" name line)) (call define_sym name ("let" name line))
) (if (== ty "list") (do ) (if (== ty "list") (do
(let (_ _ pats) pat) (let (_ _ pats) pat)
@ -284,7 +361,7 @@
(if (>= i (call len syms)) (break)) (if (>= i (call len syms)) (break))
(let (s_ident _) (call at syms i)) (let (s_ident _) (call at syms i))
(if (== ident s_ident) (do (if (== ident s_ident) (do
(call set syms i sym) (call set syms i (ident sym))
(return) (return)
)) ))
(+= i 1) (+= i 1)
@ -329,7 +406,9 @@
(loop (do (loop (do
(if (>= i str_len) (break)) (if (>= i str_len) (break))
(let ch (call at str i)) (let ch (call at str i))
(if (== ch "\"") (do (if (== ch "\\") (do
(+= result "\\\\")
) (if (== ch "\"") (do
(+= result "\\\"") (+= result "\\\"")
) (if (== ch "\t") (do ) (if (== ch "\t") (do
(+= result "\\t") (+= result "\\t")
@ -341,7 +420,7 @@
(+= result "\\0") (+= result "\\0")
) (do ) (do
(+= result ch) (+= result ch)
)))))) )))))))
(+= i 1) (+= i 1)
)) ))
(return result) (return result)
@ -417,6 +496,9 @@
(let i 0) (let i 0)
(let line 1) (let line 1)
(let ident_chars (+ "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-*/%&|=?!<>'_"))
(loop (do (loop (do
(if (>= i text_len) (break)) (if (>= i text_len) (break))
@ -468,9 +550,9 @@
(+= i 1) (+= i 1)
(= ch (call at text i)) (= 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) (call panic "expected '\"' on line %" line)
))) ))
(+= i 1) (+= i 1)
(call push tokens ("string" line value)) (call push tokens ("string" line value))
) (if (call contains "0123456789" ch) (do ) (if (call contains "0123456789" ch) (do
@ -484,11 +566,11 @@
(+= i 1) (+= i 1)
)) ))
(call push tokens ("int" line value)) (call push tokens ("int" line value))
) (if (call contains identChars ch) (do ) (if (call contains ident_chars ch) (do
(let value "") (let value "")
(loop (do (loop (do
(= ch (call at text i)) (= 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) (break)
)) ))
(+= value ch) (+= value ch)
@ -504,9 +586,6 @@
(return tokens) (return tokens)
)) ))
(let identChars (+ "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-*/%&|=?!<>'_"))
(fn contains (text ch) (do (fn contains (text ch) (do
(let text_len (call len text)) (let text_len (call len text))
(let i 0) (let i 0)
@ -574,7 +653,7 @@
(let silent true) (let silent true)
(let (_ input_filename) (call get_args)) (let (input_filename output_filename) (call get_args))
(if (not silent) (call println "reading file...")) (if (not silent) (call println "reading file..."))
(let text (call read_text_file input_filename)) (let text (call read_text_file input_filename))
@ -585,31 +664,31 @@
(if (not silent) (call println "tokenizing...")) (if (not silent) (call println "tokenizing..."))
(let tokens (call tokenize text)) (let tokens (call tokenize text))
//(call println "=== tokens ===") // (call println "=== tokens ===")
//(for (tok line value) tokens (do // (for (tok line value) tokens (do
// (call println "%\t%\t%" line tok (if (!= value null) value "")) // (call println "%\t%\t%" line tok (if (!= value null) value ""))
//)) // ))
(if (not silent) (call println "parsing...")) (if (not silent) (call println "parsing..."))
(let parser (call Parser tokens)) (let parser (call Parser tokens))
(let (parse) parser) (let (parse) parser)
(let ast (call parse)) (let ast (call parse))
//(call println "=== ast ===") // (call println "=== ast ===")
//(for expr ast (do // (for expr ast (do
// (call print_expr expr 0) // (call print_expr expr 0)
//)) // ))
(if (not silent) (call println "emitting...")) (if (not silent) (call println "emitting..."))
(let emitter (call Emitter ast input_filename)) (let emitter (call Emitter ast input_filename))
(let (emit) emitter) (let (emit) emitter)
(let js_code (call emit)) (let js_code (call emit))
//(call println "=== js ===") // (call println "=== js ===")
//(call println js_code) // (call println js_code)
(if (not silent) (call println "writing file...")) (if (not silent) (call println "writing file..."))
(call write_text_file "out.js" js_code) (call write_text_file output_filename js_code)

5
make_stage1.sh Normal file
View File

@ -0,0 +1,5 @@
#!/bin/bash
set -xe
node phi.js compile.phi compile.phi stage1.js

5
make_stage2.sh Normal file
View File

@ -0,0 +1,5 @@
#!/bin/bash
set -xe
node stage1.js compile.phi stage2.js

39
phi.js
View File

@ -30,7 +30,7 @@ class Evaluator {
this.syms = { parent: undefined, map: new Map(this.builtins) }; this.syms = { parent: undefined, map: new Map(this.builtins) };
this.currentLine = 0; this.currentLine = 0;
this.filename = filename; 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") { } else if (id === "or") {
const left = this.evalToValue(s[1]); const left = this.evalToValue(s[1]);
if (left.value) { if (this.runtime.truthy(left)) {
return { type: "value", value: left }; return { type: "value", value: { type: "bool", value: true } };
} else { } else {
const right = this.evalToValue(s[2]); 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") { } else if (id === "and") {
const left = this.evalToValue(s[1]); const left = this.evalToValue(s[1]);
if (left.value) { if (this.runtime.truthy(left)) {
const right = this.evalToValue(s[2]); const right = this.evalToValue(s[2]);
return { type: "value", value: right }; return { type: "value", value: { type: "bool", value: this.runtime.truthy(right) } };
} else { } else {
return { type: "value", value: left }; return { type: "value", value: { type: "bool", value: false } };
} }
} else if (id in this.artithmeticOps) { } else if (id in this.artithmeticOps) {
const left = this.evalToValue(s[1]); const left = this.evalToValue(s[1]);
const right = this.evalToValue(s[2]); const right = this.evalToValue(s[2]);
if ( return { type: "value", value: this.artithmeticOps[id](left, right) };
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),
},
};
} else if (id === "==") { } else if (id === "==") {
const left = this.evalToValue(s[1]); const left = this.evalToValue(s[1]);
const right = this.evalToValue(s[2]); const right = this.evalToValue(s[2]);
@ -169,10 +155,7 @@ class Evaluator {
const right = this.evalToValue(s[2]); const right = this.evalToValue(s[2]);
return { return {
type: "value", type: "value",
value: { value: this.runtime.comparisonOperation(left, right, this.comparisonOps[id]),
type: "bool",
value: this.comparisonOps[id](left.value, right.value),
},
}; };
} else if (id in this.assignOps) { } else if (id in this.assignOps) {
return this.evalAssign(expr); return this.evalAssign(expr);
@ -387,8 +370,8 @@ class Evaluator {
} }
artithmeticOps = { artithmeticOps = {
"+": (left, right) => right + left, "+": (left, right) => this.runtime.opAdd(left, right),
"-": (left, right) => right - left, "-": (left, right) => this.runtime.opSub(left, right),
}; };
comparisonOps = { comparisonOps = {
"<": (left, right) => left < right, "<": (left, right) => left < right,

View File

@ -2,10 +2,11 @@ import fs from "node:fs";
import process from "node:process"; import process from "node:process";
export class Runtime { export class Runtime {
constructor(filename) { constructor({ filename, args }) {
this.syms = { parent: undefined, map: new Map(this.builtins) }; this.syms = { parent: undefined, map: new Map(this.builtins) };
this.callStack = [{ name: "<entry>", line: 0 }]; this.callStack = [{ name: "<entry>", line: 0 }];
this.filename = filename; this.filename = filename;
this.args = args ?? process.argv.slice(2);
this.currentLine = 0; this.currentLine = 0;
} }
@ -98,6 +99,42 @@ export class Runtime {
return { type: "bool", value: !expr.value }; 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) { builtinFormat(msg, ...args) {
return { type: "string", value: this.format(msg, ...args) }; return { type: "string", value: this.format(msg, ...args) };
} }
@ -175,8 +212,7 @@ export class Runtime {
builtinGetArgs() { builtinGetArgs() {
return { return {
type: "list", type: "list",
values: process.argv values: this.args
.slice(2)
.map((value) => ({ type: "string", value })), .map((value) => ({ type: "string", value })),
}; };
} }

813
stage1.js Normal file
View File

@ -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));