self hosted

This commit is contained in:
sfja 2025-09-23 01:07:41 +02:00
parent 4289d04ec3
commit ab660ae7a8
7 changed files with 2324 additions and 911 deletions

View File

@ -1,17 +1,52 @@
(fn dbg (msg) (do
(if is_phi_compiler (do
(call println "dbg: %" msg)
))
))
(fn Emitter (ast filename) (do (fn Emitter (ast filename) (do
(let output ()) (let output ())
(let (enter_scope leave_scope define_sym get_sym print_syms) (call Syms)) (let (enter_scope leave_scope define_sym get_sym print_syms) (call Syms))
(let (let_node_reg_count let_node_reg_increment) (call Counter)) (let (let_node_reg_count let_node_reg_increment) (call Counter))
(let (sym_id_count sym_id_increment) (call Counter))
(let builtin_syms (
("format" "builtinFormat")
("print" "builtinPrint")
("println" "builtinPrintln")
("panic" "builtinPanic")
("read_text_file" "builtinReadTextFile")
("write_text_file" "builtinWriteTextFile")
("push" "builtinPush")
("at" "builtinAt")
("set" "builtinSet")
("len" "builtinLen")
("string_to_int" "builtinStringToInt")
("char_code" "builtinCharCode")
("strings_join" "builtinStringsJoin")
("get_args" "builtinGetArgs")
))
(fn generate () (do (fn generate () (do
(call emit "#!/usr/bin/env node\n") (call emit "#!/usr/bin/env node\n")
(call emit "import { Runtime } from \"./runtime.js\"\n") (call emit "import { Runtime } from \"./runtime.js\";\n")
(call emit "const runtime = new Runtime(\"") (call emit "const runtime = new Runtime({ filename: \"")
(call emit filename) (call emit filename)
(call emit "\")\n") (call emit "\" });\n")
(for (ident builtin_id) builtin_syms (do
(call define_builtin ident builtin_id)
))
(let is_phi_compiler_sym_id (call define_let "is_phi_compiler" 0))
(call emit (call format
"let _is_phi_compiler% = { type: \"bool\", value: true };\n"
is_phi_compiler_sym_id
))
(call discover_syms ast) (call discover_syms ast)
(call emit_exprs ast) (call emit_exprs ast)
(return (call strings_join output)) (return (call strings_join output))
@ -32,8 +67,8 @@
(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
(let (_ (_ _ name) (_ _ params) body) s) (let (_ (_ _ ident) (_ _ params) body) s)
(call define_sym name ("fn" name line)) (call define_fn ident line)
)) ))
)) ))
)) ))
@ -42,10 +77,10 @@
(let (ty line) expr) (let (ty line) expr)
(if (== ty "list") (do (if (== ty "list") (do
(call emit_list expr) (call emit_list expr)
) (if (== ty "int") ( ) (if (== ty "int") (do
(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") (do
(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
@ -68,16 +103,16 @@
(call panic "undefined symbol '%' on line %" value line) (call panic "undefined symbol '%' on line %" value line)
)) ))
(let (sym_ty) sym) (let (sym_id sym_ty) sym)
(if (== sym_ty "builtin") (do (if (== sym_ty "builtin") (do
(let (_ id) sym) (let (_ _ id) sym)
(call emit (call format "((...args) => runtime.%(...args))" id)) (call emit (call format "((...args) => runtime.%(...args))" id))
) (if (== sym_ty "fn") (do ) (if (== sym_ty "fn") (do
(call emit (call format "_%" value)) (call emit (call format "_%%" value sym_id))
) (if (== sym_ty "param") (do ) (if (== sym_ty "param") (do
(call emit (call format "_%" value)) (call emit (call format "_%%" value sym_id))
) (if (== sym_ty "let") (do ) (if (== sym_ty "let") (do
(call emit (call format "_%" value)) (call emit (call format "_%%" value sym_id))
) (do ) (do
(call panic "not implemented '%'" sym_ty) (call panic "not implemented '%'" sym_ty)
))))) )))))
@ -94,30 +129,33 @@
)) ))
(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_list_literal s)
(return) (return)
)) ))
(if (== id "fn") (do (if (== id "fn") (do
(let (_ (_ _ name) (_ _ params) body) s) (let (_ (_ _ ident) (_ _ params) body) s)
(call emit (call format "function _%(" name))
(let sym (call get_sym ident))
(let (sym_id) sym)
(call emit (call format "function _%%(" ident sym_id))
(call enter_scope) (call enter_scope)
(let first true) (let first true)
(for (_ _ name) params (do (for (_ _ ident) params (do
(if (not first) (do (if (not first) (do
(call emit ", ") (call emit ", ")
)) ))
(= first false) (= first false)
(call emit (call format "_%" name)) (let sym_id (call define_param ident line))
(call emit (call format "_%%" ident sym_id))
(call define_sym name ("param" name line))
)) ))
(call emit (call format ") {\n" name)) (call emit ") {\n")
(call emit (call format "runtime.pushCall(\"%\");\n" name)) (call emit (call format "runtime.pushCall(\"%\");\n" ident))
(call emit_expr body) (call emit_expr body)
(call emit ";\nruntime.popCall();\nreturn { type: \"null\" };\n}") (call emit ";\nruntime.popCall();\nreturn { type: \"null\" };\n}")
@ -127,7 +165,7 @@
(let (_ pat expr) s) (let (_ pat expr) s)
(let reg (call let_node_reg_count)) (let reg (call let_node_reg_count))
(call let_node_reg_increment) (call let_node_reg_increment)
(call emit (call format "let r_% = " reg)) (call emit (call format "const r_% = " reg))
(call emit_expr expr) (call emit_expr expr)
(call emit_let_node pat reg) (call emit_let_node pat reg)
) (if (== id "do") (do ) (if (== id "do") (do
@ -137,14 +175,22 @@
(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 ") (let reg (call let_node_reg_count))
(call emit_pat pat) (call let_node_reg_increment)
(call emit " of ") (call emit (call format "for (const r_% of " reg))
(call emit_expr expr) (call emit_expr expr)
(call emit ".values) {\n") (call emit ".values) {")
(call enter_scope)
(call emit_let_node pat reg)
(call enter_scope)
(call emit ";\n")
(call emit_expr body) (call emit_expr body)
(call emit "}") (call emit "}")
(call leave_scope)
(call leave_scope) (call leave_scope)
) (if (== id "loop") (do ) (if (== id "loop") (do
(let (_ body) s) (let (_ body) s)
@ -153,9 +199,9 @@
(call emit "}") (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 (runtime.truthy(")
(call emit_expr cond) (call emit_expr cond)
(call emit ") {\n") (call emit ")) {\n")
(call emit_expr truthy) (call emit_expr truthy)
(call emit "}") (call emit "}")
(if (!= falsy null) (do (if (!= falsy null) (do
@ -205,17 +251,17 @@
) (if (== id "or") (do ) (if (== id "or") (do
(let (_ left right) s) (let (_ left right) s)
(call emit (call format "(runtime.setLine(%)" line)) (call emit (call format "(runtime.setLine(%)" line))
(call emit ", { type: \"bool\", value: this.runtime.truthy(") (call emit ", { type: \"bool\", value: runtime.truthy(")
(call emit_expr left) (call emit_expr left)
(call emit ") || this.runtime.falsy(") (call emit ") || runtime.truthy(")
(call emit_expr right) (call emit_expr right)
(call emit ") })") (call emit ") })")
) (if (== id "and") (do ) (if (== id "and") (do
(let (_ left right) s) (let (_ left right) s)
(call emit (call format "(runtime.setLine(%)" line)) (call emit (call format "(runtime.setLine(%)" line))
(call emit ", { type: \"bool\", value: this.runtime.truthy(") (call emit ", { type: \"bool\", value: runtime.truthy(")
(call emit_expr left) (call emit_expr left)
(call emit ") && this.runtime.falsy(") (call emit ") && runtime.truthy(")
(call emit_expr right) (call emit_expr right)
(call emit ") })") (call emit ") })")
) (if (== id "==") (do ) (if (== id "==") (do
@ -240,6 +286,11 @@
(call emit_expr expr) (call emit_expr expr)
(call emit ")") (call emit ")")
) (do ) (do
(call emit_list_literal s)
))))))))))))))))))))))))
))
(fn emit_list_literal (s) (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
@ -251,7 +302,6 @@
(call emit_expr e) (call emit_expr e)
)) ))
(call emit "] })") (call emit "] })")
))))))))))))))))))))))))
)) ))
(fn emit_let_node (pat base_reg) (do (fn emit_let_node (pat base_reg) (do
@ -261,16 +311,35 @@
(if (== ident "_") (return)) (if (== ident "_") (return))
(call emit (call format ";\nlet _% = r_%" ident base_reg)) (let sym_id (call define_let ident line))
(call define_sym ident ("let" line)) (call emit (call format ";\nlet _%% = r_%" ident sym_id base_reg))
) (if (== pat_ty "list") (do ) (if (== pat_ty "list") (do
(let (_ _ pats) pat) (let (_ _ pats) pat)
//(call emit (call format
// (+ ";\nif (r_%.type !== \"list\") {\nruntime.setLine(%);"
// "\nruntime.panic(\"expected list\");\n}\n")
// base_reg
// line
//))
//(call emit (call format
// (+ ";\nif (% > r_%.values.length) {\nruntime.setLine(%);\nruntime.panic"
// "(`expected % elements, got ${r_%.values.length}`);\n}\n")
// (call len pats)
// base_reg
// line
// (call len pats)
// base_reg
//))
(let i 0) (let i 0)
(for pat pats (do (for pat pats (do
(let reg (call let_node_reg_count)) (let reg (call let_node_reg_count))
(call let_node_reg_increment) (call let_node_reg_increment)
(call emit (call format ";\nlet r_% = r_%.values[%]" reg base_reg i)) (call emit (call format
";\nconst r_% = r_%.values[%] ?? { type: \"null\"}"
reg base_reg i
))
(call emit_let_node pat reg) (call emit_let_node pat reg)
(+= i 1) (+= i 1)
)) ))
@ -298,59 +367,64 @@
(if (== sym null) (do (if (== sym null) (do
(call panic "could not find symbol '%' on line %" ident line) (call panic "could not find symbol '%' on line %" ident line)
)) ))
(let (sym_type sym_ident _) sym) (let (sym_id sym_type sym_ident _) sym)
(if (== sym_type "let") (do (if (== sym_type "let") (do
(call emit (call format "(_% = runtime.assignValue(" sym_ident)) (call emit (call format "(_%% = " sym_ident sym_id))
(if (== id "=") (do (if (== id "=") (do
(call emit_expr expr) (call emit_expr expr)
) (if (== id "+") (do ) (if (== id "+") (do
(call emit (call format "runtime.opAdd(_%, " sym_ident)) (call emit (call format "runtime.opAdd(_%%, " sym_ident sym_id))
(call emit_expr expr) (call emit_expr expr)
(call emit ")") (call emit ")")
) (if (== id "-") (do ) (if (== id "-") (do
(call emit (call format "runtime.opSub(_%, " sym_ident)) (call emit (call format "runtime.opSub(_%%, " sym_ident sym_id))
(call emit_expr expr) (call emit_expr expr)
(call emit ")") (call emit ")")
) (do ) (do
(call panic "not implemented") (call panic "not implemented")
)))) ))))
(call emit "))") (call emit ")")
) (do ) (do
(call panic "cannot assign to symbol '%' on line %" sym_ident line) (call panic "cannot assign to symbol '%' on line %" sym_ident line)
)) ))
)) ))
(fn emit_pat (pat) (do
(let (ty) pat)
(if (== ty "ident") (do
(let (_ line name) pat)
(if (== name "_") (do
(return)
))
(call emit (call format "_%" name))
(call define_sym name ("let" name line))
) (if (== ty "list") (do
(let (_ _ pats) pat)
(call emit "[")
(let first true)
(for pat pats (do
(if (not first) (do
(call emit ", ")
))
(= first false)
(call emit_pat pat)
))
(call emit "]")
) (do
(call panic "cannot assign to '%'" pat)
)))
))
(fn emit (str) (do (fn emit (str) (do
(call push output str) (call push output str)
)) ))
(fn define_builtin (ident builtin_id) (do
(let sym_id (call sym_id_count))
(call sym_id_increment)
(call define_sym ident (sym_id "builtin" builtin_id))
(return sym_id)
))
(fn define_fn (ident line) (do
(let sym_id (call sym_id_count))
(call sym_id_increment)
(call define_sym ident (sym_id "fn" ident line))
(return sym_id)
))
(fn define_param (ident line) (do
(let sym_id (call sym_id_count))
(call sym_id_increment)
(call define_sym ident (sym_id "param" ident line))
(return sym_id)
))
(fn define_let (ident line) (do
(let sym_id (call sym_id_count))
(call sym_id_increment)
(call define_sym ident (sym_id "let" ident line))
(return sym_id)
))
(return (generate)) (return (generate))
)) ))
@ -369,22 +443,7 @@
)) ))
(fn Syms () (do (fn Syms () (do
(let syms (null ( (let syms (null ()))
("format" ("builtin" "builtinFormat"))
("print" ("builtin" "builtinPrint"))
("println" ("builtin" "builtinPrintln"))
("panic" ("builtin" "builtinPanic"))
("read_text_file" ("builtin" "builtinReadTextFile"))
("write_text_file" ("builtin" "builtinWriteTextFile"))
("push" ("builtin" "builtinPush"))
("at" ("builtin" "builtinAt"))
("set" ("builtin" "builtinSet"))
("len" ("builtin" "builtinLen"))
("string_to_int" ("builtin" "builtinStringToInt"))
("char_code" ("builtin" "builtinCharCode"))
("strings_join" ("builtin" "builtinStringsJoin"))
("get_args" ("builtin" "builtinGetArgs"))
)))
(fn enter_scope () (do (fn enter_scope () (do
(= syms (syms ())) (= syms (syms ()))
@ -396,18 +455,18 @@
)) ))
(fn define (ident sym) (do (fn define (ident sym) (do
(let (_ syms) syms) (let (_ map) syms)
(let i 0) (let i 0)
(loop (do (loop (do
(if (>= i (call len syms)) (break)) (if (>= i (call len map)) (break))
(let (s_ident _) (call at syms i)) (let (s_ident _) (call at map i))
(if (== ident s_ident) (do (if (== ident s_ident) (do
(call set syms i (ident sym)) (call set map i (ident sym))
(return) (return)
)) ))
(+= i 1) (+= i 1)
)) ))
(call push syms (ident sym)) (call push map (ident sym))
)) ))
(fn find_sym (syms ident) (do (fn find_sym (syms ident) (do
@ -706,25 +765,30 @@
(return elems) (return elems)
)) ))
(let silent true) (let silent false)
(let (input_filename output_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 '%'..." input_filename))
(let text (call read_text_file input_filename)) (let text (call read_text_file input_filename))
(call println "=== text ===") //(call println "=== text ===")
// (call println text) // (call println text)
(call println (call len text)) //(call println (call len text))
(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 elem tokens (do
// (call println "%\t%\t%" line tok (if (!= value null) value "")) // (let (tok line value) elem)
// (if (!= value null) (do
// (call println "%\t%\t%" line tok value)
// ) (do
// (call println "%\t%" line tok)
// )) // ))
(call println (call len tokens)) //))
//(call println (call len tokens))
(if (not silent) (call println "parsing...")) (if (not silent) (call println "parsing..."))
(let parser (call Parser tokens)) (let parser (call Parser tokens))
@ -744,7 +808,7 @@
// (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 '%'..." output_filename))
(call write_text_file output_filename js_code) (call write_text_file output_filename js_code)

0
make_stage1.sh Normal file → Executable file
View File

0
make_stage2.sh Normal file → Executable file
View File

66
phi.js
View File

@ -46,7 +46,7 @@ class Evaluator {
} }
this.currentLine = expr.line; this.currentLine = expr.line;
this.runtime.setLine(expr.line) this.runtime.setLine(expr.line);
if (expr.type === "list") { if (expr.type === "list") {
return this.evalList(expr, expr.line); return this.evalList(expr, expr.line);
} else if (expr.type === "int") { } else if (expr.type === "int") {
@ -122,20 +122,29 @@ class Evaluator {
return { type: "value", value: { type: "bool", value: true } }; 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: { type: "bool", value: this.runtime.truthy(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 (this.runtime.truthy(left)) { if (this.runtime.truthy(left)) {
const right = this.evalToValue(s[2]); const right = this.evalToValue(s[2]);
return { type: "value", value: { type: "bool", value: this.runtime.truthy(right) } }; return {
type: "value",
value: { type: "bool", value: this.runtime.truthy(right) },
};
} else { } else {
return { type: "value", value: { type: "bool", value: false } }; 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]);
return { type: "value", value: this.artithmeticOps[id](left, right) }; return {
type: "value",
value: this.artithmeticOps[id](left, right),
};
} 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]);
@ -155,7 +164,11 @@ class Evaluator {
const right = this.evalToValue(s[2]); const right = this.evalToValue(s[2]);
return { return {
type: "value", type: "value",
value: this.runtime.comparisonOperation(left, right, this.comparisonOps[id]), value: this.runtime.comparisonOperation(
left,
right,
this.comparisonOps[id],
),
}; };
} else if (id in this.assignOps) { } else if (id in this.assignOps) {
return this.evalAssign(expr); return this.evalAssign(expr);
@ -230,38 +243,43 @@ class Evaluator {
); );
} }
const outerSyms = this.syms;
this.syms = { parent: outerSyms, map: new Map() };
for (let i = 0; i < value.values.length; ++i) { for (let i = 0; i < value.values.length; ++i) {
this.enterScope();
this.assignPattern(s[1], value.values[i]); this.assignPattern(s[1], value.values[i]);
this.enterScope();
const result = this.eval(s[3]); const result = this.eval(s[3]);
this.leaveScope();
this.leaveScope();
if (result.type === "break") { if (result.type === "break") {
return { type: "value", value: result.value }; return { type: "value", value: result.value };
} else if (result.type !== "value") { } else if (result.type !== "value") {
return result; return result;
} }
} }
this.syms = outerSyms;
return { type: "value", value: { type: "null" } }; return { type: "value", value: { type: "null" } };
} }
evalDo(expr) { evalDo(expr) {
const s = expr.values; const s = expr.values;
const outerSyms = this.syms; this.enterScope();
this.syms = { parent: outerSyms, map: new Map() };
let lastValue = { type: "null" }; let lastValue = { type: "null" };
for (const expr of s.slice(1)) { for (const expr of s.slice(1)) {
const result = this.eval(expr); const result = this.eval(expr);
if (!result) {
console.log({ expr, result });
}
if (result.type !== "value") { if (result.type !== "value") {
return result; return result;
} }
lastValue = result.value; lastValue = result.value;
} }
this.syms = outerSyms; this.leaveScope();
return { type: "value", value: lastValue }; return { type: "value", value: lastValue };
} }
@ -291,8 +309,10 @@ class Evaluator {
this.syms.map.set(fnValue.params[i], args[i]); this.syms.map.set(fnValue.params[i], args[i]);
} }
this.enterScope();
let returnValue = { type: "null" }; let returnValue = { type: "null" };
const result = this.eval(fnValue.body); const result = this.eval(fnValue.body);
this.leaveScope();
if (result.type === "value" || result.type === "return") { if (result.type === "value" || result.type === "return") {
returnValue = result.value; returnValue = result.value;
@ -337,6 +357,11 @@ class Evaluator {
if (pattern.value === "_") { if (pattern.value === "_") {
return; return;
} }
if (this.syms.map.has(pattern.value)) {
throw new Error(
`redeclaration of local symbol '${pattern.value}' on line ${pattern.line}`,
);
}
this.syms.map.set(pattern.value, { this.syms.map.set(pattern.value, {
type: "local", type: "local",
line: pattern.line, line: pattern.line,
@ -344,7 +369,7 @@ class Evaluator {
}); });
} else if (pattern.type === "list") { } else if (pattern.type === "list") {
if (value.type !== "list") { if (value.type !== "list") {
this.panic(`expected list`); this.panic(`expected list on line ${pattern.line}`);
} }
for (const [i, p] of pattern.values.entries()) { for (const [i, p] of pattern.values.entries()) {
this.assignPattern(p, value.values[i] ?? { type: "null" }); this.assignPattern(p, value.values[i] ?? { type: "null" });
@ -369,6 +394,14 @@ class Evaluator {
this.runtime.panic(msg); this.runtime.panic(msg);
} }
enterScope() {
this.syms = { parent: this.syms, map: new Map() };
}
leaveScope() {
this.syms = this.syms.parent;
}
artithmeticOps = { artithmeticOps = {
"+": (left, right) => this.runtime.opAdd(left, right), "+": (left, right) => this.runtime.opAdd(left, right),
"-": (left, right) => this.runtime.opSub(left, right), "-": (left, right) => this.runtime.opSub(left, right),
@ -398,8 +431,10 @@ class Evaluator {
"print": (...args) => this.runtime.builtinPrint(...args), "print": (...args) => this.runtime.builtinPrint(...args),
"println": (...args) => this.runtime.builtinPrintln(...args), "println": (...args) => this.runtime.builtinPrintln(...args),
"panic": (...args) => this.runtime.builtinPanic(...args), "panic": (...args) => this.runtime.builtinPanic(...args),
"read_text_file": (...args) => this.runtime.builtinReadTextFile(...args), "read_text_file": (...args) =>
"write_text_file": (...args) => this.runtime.builtinWriteTextFile(...args), this.runtime.builtinReadTextFile(...args),
"write_text_file": (...args) =>
this.runtime.builtinWriteTextFile(...args),
"push": (...args) => this.runtime.builtinPush(...args), "push": (...args) => this.runtime.builtinPush(...args),
"at": (...args) => this.runtime.builtinAt(...args), "at": (...args) => this.runtime.builtinAt(...args),
"set": (...args) => this.runtime.builtinSet(...args), "set": (...args) => this.runtime.builtinSet(...args),
@ -414,6 +449,7 @@ class Evaluator {
"null": { type: "null" }, "null": { type: "null" },
"false": { type: "bool", value: false }, "false": { type: "bool", value: false },
"true": { type: "bool", value: true }, "true": { type: "bool", value: true },
"is_phi_compiler": { type: "bool", value: false },
}; };
builtins = [ builtins = [

View File

@ -84,11 +84,11 @@ export class Runtime {
} }
opEq(left, right) { opEq(left, right) {
return { type: "bool", value: this.equalityOperation(left, right) } return { type: "bool", value: this.equalityOperation(left, right) };
} }
opNe(left, right) { opNe(left, right) {
return { type: "bool", value: !this.equalityOperation(left, right) } return { type: "bool", value: !this.equalityOperation(left, right) };
} }
opNot(expr) { opNot(expr) {
@ -105,23 +105,31 @@ export class Runtime {
return { type: "bool", value: action(left.value, right.value) }; return { type: "bool", value: action(left.value, right.value) };
} }
opLt(left, right) { return this.comparisonOperation(right, left, (l, r) => l < r); } opLt(left, right) {
opGt(left, right) { return this.comparisonOperation(right, left, (l, r) => l > r); } return this.comparisonOperation(left, right, (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); } opGt(left, right) {
return this.comparisonOperation(left, right, (l, r) => l > r);
}
opLte(left, right) {
return this.comparisonOperation(left, right, (l, r) => l <= r);
}
opGte(left, right) {
return this.comparisonOperation(left, right, (l, r) => l >= r);
}
opAdd(left, right) { opAdd(left, right) {
if (left.type === "int" && right.type === "int") { if (left.type === "int" && right.type === "int") {
return { type: "int", value: left.value + right.value } return { type: "int", value: left.value + right.value };
} else if (left.type === "string" && right.type === "string") { } else if (left.type === "string" && right.type === "string") {
return { type: "string", value: left.value + right.value } return { type: "string", value: left.value + right.value };
} else { } else {
this.panic(`cannot apply '+' on ${left.type} and ${right.type}`); this.panic(`cannot apply '+' on ${left.type} and ${right.type}`);
} }
} }
opSub(left, right) { opSub(left, right) {
if (left.type === "int" && right.type === "int") { if (left.type === "int" && right.type === "int") {
return { type: "int", value: left.value + right.value } return { type: "int", value: left.value - right.value };
} else { } else {
this.panic(`cannot apply '-' on ${left.type} and ${right.type}`); this.panic(`cannot apply '-' on ${left.type} and ${right.type}`);
} }
@ -226,7 +234,8 @@ export class Runtime {
} else if (value.type === "string") { } else if (value.type === "string") {
return `${value.value}`; return `${value.value}`;
} else if (value.type === "list") { } else if (value.type === "list") {
return `(${value.values.map((v) => Runtime.valueToString(v)).join(" ") return `(${
value.values.map((v) => Runtime.valueToString(v)).join(" ")
})`; })`;
} else { } else {
throw new Error(`unknown value type ${value.type}`); throw new Error(`unknown value type ${value.type}`);
@ -243,7 +252,8 @@ export class Runtime {
} else if (value.type === "string") { } else if (value.type === "string") {
return `"${value.value}"`; return `"${value.value}"`;
} else if (value.type === "list") { } else if (value.type === "list") {
return `(${value.values.map((v) => Runtime.valueToString(v)).join(" ") return `(${
value.values.map((v) => Runtime.valueToString(v)).join(" ")
})`; })`;
} else { } else {
throw new Error(`unknown value type ${value.type}`); throw new Error(`unknown value type ${value.type}`);

1616
stage1.js

File diff suppressed because it is too large Load Diff

1229
stage2.js

File diff suppressed because it is too large Load Diff