a bit more compiler stuff
This commit is contained in:
parent
09acd55405
commit
e325188f46
145
compile.phi
145
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)
|
||||
))
|
||||
|
21
phi.js
21
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),
|
||||
|
33
runtime.js
33
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}`);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user