From e325188f461d55a9c8b7d4e091f7a6a88b44a909 Mon Sep 17 00:00:00 2001 From: sfj Date: Thu, 18 Sep 2025 16:03:19 +0200 Subject: [PATCH] a bit more compiler stuff --- compile.phi | 145 +++++++++++++++++++++++++++++++++++++++++++++++----- phi.js | 21 +++----- runtime.js | 33 ++++++++---- 3 files changed, 161 insertions(+), 38 deletions(-) diff --git a/compile.phi b/compile.phi index 894c555..defeaf0 100644 --- a/compile.phi +++ b/compile.phi @@ -10,6 +10,7 @@ (call emit "const runtime = new Runtime(\"") (call emit filename) (call emit "\")\n") + (call discover_syms ast) (call emit_exprs ast) (return (call strings_join output)) )) @@ -18,6 +19,21 @@ (for expr exprs (do (call emit_expr expr) (call emit ";\n") + + )) + )) + + (fn discover_syms (exprs) (do + (for expr exprs (do + (let (ty line) expr) + (if (!= ty "list") (return)) + (let (ty line s) expr) + (if (== (call len s) 0) (return)) + (let ((_ _ id)) s) + (if (== id "fn") (do + (let (_ (_ _ name) (_ _ params) body) s) + (call define_sym name ("fn" name line)) + )) )) )) @@ -47,22 +63,22 @@ (let sym (call get_sym value)) (if (== sym null) (do - (call panic "undefined symbol '%'" value) + (call panic "undefined symbol '%' on line %" value line) )) (let (sym_ty) sym) (if (== sym_ty "builtin") (do (let (_ id) sym) - (if (== id "println") (do - (call emit "((...args) => runtime.builtinPrintln(...args))") - ) (do - (call panic "unknown builtin '%'" id) - )) + (call emit (call format "((...args) => runtime.%(...args))" id)) ) (if (== sym_ty "fn") (do (call emit (call format "_%" value)) + ) (if (== sym_ty "param") (do + (call emit (call format "_%" value)) + ) (if (== sym_ty "let") (do + (call emit (call format "_%" value)) ) (do (call panic "not implemented '%'" sym_ty) - ))) + ))))) ) (do (call panic "unknown expr type '%' on line %" ty line) ))))) @@ -74,11 +90,17 @@ (call emit "{ type: \"list\", values: [] }") (return) )) - (let ((_ _ id)) s) + (let ((id_ty _ id)) s) + (if (!= id_ty "ident") (do + (call emit "{ type: \"list\", values: [] }") + (return) + )) (if (== id "fn") (do (let (_ (_ _ name) (_ _ params) body) s) (call emit (call format "function _%(" name)) + (call enter_scope) + (let first true) (for (_ _ name) params (do (if (not first) (do @@ -87,16 +109,50 @@ (= first false) (call emit (call format "_%" name)) + + (call define_sym name ("param" name line)) )) - (call define_sym name ("fn" name line)) (call emit (call format ") {\n" name)) (call emit (call format "runtime.pushCall(\"%\");" name)) + (call emit_expr body) (call emit "}") + + (call leave_scope) + ) (if (== id "let") (do + (let (_ pat expr) s) + (call emit "let ") + (call emit_pat pat) + (call emit " = ") + (call emit_expr expr) ) (if (== id "do") (do + (call enter_scope) + (call discover_syms (call slice s 1)) (call emit_exprs (call slice s 1)) + (call leave_scope) + ) (if (== id "for") (do + (let (_ pat expr body) s) + (call emit "for (let ") + (call emit_pat pat) + (call emit " of ") + (call emit_expr expr) + (call emit ") {\n") + (call emit_expr body) + (call emit "}") + ) (if (== id "if") (do + (let (_ cond truthy falsy) s) + (call emit "if (") + (call emit_expr cond) + (call emit ") {\n") + (call emit_expr truthy) + (call emit "}") + (if (!= falsy null) (do + (call emit " else {\n") + (call emit_expr falsy) + (call emit "}") + )) ) (if (== id "return") (do (let (_ value) s) (call emit "runtime.popCall();\n") @@ -124,6 +180,27 @@ )) (call emit "))") + ) (if (== id "=") (do + (call panic "not implemented") + ) (if (== id "==") (do + (let (_ left right) s) + (call emit "runtime.opEq(") + (call emit_expr left) + (call emit ", ") + (call emit_expr right) + (call emit ")") + ) (if (== id "!=") (do + (let (_ left right) s) + (call emit "runtime.opNe(") + (call emit_expr left) + (call emit ", ") + (call emit_expr right) + (call emit ")") + ) (if (== id "not") (do + (let (_ expr) s) + (call emit "runtime.opNot(") + (call emit_expr expr) + (call emit ")") ) (do (call emit "{ type: \"list\", values: [") (let first true) @@ -136,7 +213,34 @@ (call emit_expr e) )) (call emit "] }") - ))))) + )))))))))))) + )) + + (fn emit_pat (pat) (do + (let (ty) pat) + (if (== ty "ident") (do + (let (_ line name) pat) + (if (== name "_") (do + (return) + )) + (call emit 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 @@ -148,7 +252,20 @@ (fn Syms () (do (let syms (null ( - ("println" ("builtin" "println")) + ("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 @@ -165,9 +282,9 @@ (let i 0) (loop (do (if (>= i (call len syms)) (break)) - (let (s_ident s_sym) (call at syms i)) + (let (s_ident _) (call at syms i)) (if (== ident s_ident) (do - (call set s_syms i sym) + (call set syms i sym) (return) )) (+= i 1) @@ -187,7 +304,7 @@ (+= i 1) )) (if (!= parent null) (do - (return (call find_syms parent ident)) + (return (call find_sym parent ident)) )) (return null) )) diff --git a/phi.js b/phi.js index 6abd4ec..8eb89c3 100644 --- a/phi.js +++ b/phi.js @@ -46,6 +46,7 @@ class Evaluator { } this.currentLine = expr.line; + this.runtime.setLine(expr.line) if (expr.type === "list") { return this.evalList(expr, expr.line); } else if (expr.type === "int") { @@ -154,20 +155,14 @@ class Evaluator { const right = this.evalToValue(s[2]); return { type: "value", - value: { - type: "bool", - value: this.runtime.eq(left, right), - }, + value: this.runtime.opEq(left, right), }; } else if (id === "!=") { const left = this.evalToValue(s[1]); const right = this.evalToValue(s[2]); return { type: "value", - value: { - type: "bool", - value: !this.runtime.eq(left, right), - }, + value: this.runtime.opNe(left, right), }; } else if (id in this.comparisonOps) { const left = this.evalToValue(s[1]); @@ -419,14 +414,12 @@ class Evaluator { "format": (...args) => this.runtime.builtinFormat(...args), "print": (...args) => this.runtime.builtinPrint(...args), "println": (...args) => this.runtime.builtinPrintln(...args), - "panic": (...args) => - this.runtime.builtinPanic(this.currentLine, ...args), - "read_text_file": (...args) => - this.runtime.builtinReadTextFile(...args), - "write_text_file": (...args) => - this.runtime.builtinWriteTextFile(...args), + "panic": (...args) => this.runtime.builtinPanic(...args), + "read_text_file": (...args) => this.runtime.builtinReadTextFile(...args), + "write_text_file": (...args) => this.runtime.builtinWriteTextFile(...args), "push": (...args) => this.runtime.builtinPush(...args), "at": (...args) => this.runtime.builtinAt(...args), + "set": (...args) => this.runtime.builtinSet(...args), "len": (...args) => this.runtime.builtinLen(...args), "string_to_int": (...args) => this.runtime.builtinStringToInt(...args), "char_code": (...args) => this.runtime.builtinCharCode(...args), diff --git a/runtime.js b/runtime.js index 6f06a19..c2cdbf7 100644 --- a/runtime.js +++ b/runtime.js @@ -54,7 +54,7 @@ export class Runtime { return value; } - eq(left, right) { + equalityOperation(left, right) { if (left.type === "null") { return right.type === "null"; } @@ -73,7 +73,7 @@ export class Runtime { return false; } for (let i = 0; i < left.values.length; ++i) { - if (!this.eq(left.values[i], right.values[i])) { + if (!this.opEq(left.values[i], right.values[i])) { return false; } } @@ -83,6 +83,21 @@ export class Runtime { } } + opEq(left, right) { + return { type: "bool", value: this.equalityOperation(left, right) } + } + + opNe(left, right) { + return { type: "bool", value: !this.equalityOperation(left, right) } + } + + opNot(expr) { + if (expr.type !== "bool") { + this.panic(`cannot apply not to type ${expr.type}`); + } + return { type: "bool", value: !expr.value }; + } + builtinFormat(msg, ...args) { return { type: "string", value: this.format(msg, ...args) }; } @@ -97,8 +112,8 @@ export class Runtime { return { type: "null" }; } - builtinPanic(currentLine, msg, ...args) { - this.panic(this.format(msg, ...args), currentLine); + builtinPanic(msg, ...args) { + this.panic(this.format(msg, ...args)); return { type: "null" }; } @@ -176,9 +191,8 @@ export class Runtime { } else if (value.type === "string") { return `${value.value}`; } else if (value.type === "list") { - return `(${ - value.values.map((v) => Runtime.valueToString(v)).join(" ") - })`; + return `(${value.values.map((v) => Runtime.valueToString(v)).join(" ") + })`; } else { throw new Error(`unknown value type ${value.type}`); } @@ -194,9 +208,8 @@ export class Runtime { } else if (value.type === "string") { return `"${value.value}"`; } else if (value.type === "list") { - return `(${ - value.values.map((v) => Runtime.valueToString(v)).join(" ") - })`; + return `(${value.values.map((v) => Runtime.valueToString(v)).join(" ") + })`; } else { throw new Error(`unknown value type ${value.type}`); }