a bit more compiler stuff

This commit is contained in:
sfj 2025-09-18 16:03:19 +02:00
parent 09acd55405
commit e325188f46
3 changed files with 161 additions and 38 deletions

View File

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

21
phi.js
View File

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

View File

@ -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,8 +191,7 @@ 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,8 +208,7 @@ 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}`);