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 "const runtime = new Runtime(\"")
|
||||||
(call emit filename)
|
(call emit filename)
|
||||||
(call emit "\")\n")
|
(call emit "\")\n")
|
||||||
|
(call discover_syms ast)
|
||||||
(call emit_exprs ast)
|
(call emit_exprs ast)
|
||||||
(return (call strings_join output))
|
(return (call strings_join output))
|
||||||
))
|
))
|
||||||
@ -18,6 +19,21 @@
|
|||||||
(for expr exprs (do
|
(for expr exprs (do
|
||||||
(call emit_expr expr)
|
(call emit_expr expr)
|
||||||
(call emit ";\n")
|
(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))
|
(let sym (call get_sym value))
|
||||||
(if (== sym null) (do
|
(if (== sym null) (do
|
||||||
(call panic "undefined symbol '%'" value)
|
(call panic "undefined symbol '%' on line %" value line)
|
||||||
))
|
))
|
||||||
|
|
||||||
(let (sym_ty) sym)
|
(let (sym_ty) sym)
|
||||||
(if (== sym_ty "builtin") (do
|
(if (== sym_ty "builtin") (do
|
||||||
(let (_ id) sym)
|
(let (_ id) sym)
|
||||||
(if (== id "println") (do
|
(call emit (call format "((...args) => runtime.%(...args))" id))
|
||||||
(call emit "((...args) => runtime.builtinPrintln(...args))")
|
|
||||||
) (do
|
|
||||||
(call panic "unknown builtin '%'" id)
|
|
||||||
))
|
|
||||||
) (if (== sym_ty "fn") (do
|
) (if (== sym_ty "fn") (do
|
||||||
(call emit (call format "_%" value))
|
(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
|
) (do
|
||||||
(call panic "not implemented '%'" sym_ty)
|
(call panic "not implemented '%'" sym_ty)
|
||||||
)))
|
)))))
|
||||||
) (do
|
) (do
|
||||||
(call panic "unknown expr type '%' on line %" ty line)
|
(call panic "unknown expr type '%' on line %" ty line)
|
||||||
)))))
|
)))))
|
||||||
@ -74,11 +90,17 @@
|
|||||||
(call emit "{ type: \"list\", values: [] }")
|
(call emit "{ type: \"list\", values: [] }")
|
||||||
(return)
|
(return)
|
||||||
))
|
))
|
||||||
(let ((_ _ id)) s)
|
(let ((id_ty _ id)) s)
|
||||||
|
(if (!= id_ty "ident") (do
|
||||||
|
(call emit "{ type: \"list\", values: [] }")
|
||||||
|
(return)
|
||||||
|
))
|
||||||
(if (== id "fn") (do
|
(if (== id "fn") (do
|
||||||
(let (_ (_ _ name) (_ _ params) body) s)
|
(let (_ (_ _ name) (_ _ params) body) s)
|
||||||
(call emit (call format "function _%(" name))
|
(call emit (call format "function _%(" name))
|
||||||
|
|
||||||
|
(call enter_scope)
|
||||||
|
|
||||||
(let first true)
|
(let first true)
|
||||||
(for (_ _ name) params (do
|
(for (_ _ name) params (do
|
||||||
(if (not first) (do
|
(if (not first) (do
|
||||||
@ -87,16 +109,50 @@
|
|||||||
(= first false)
|
(= first false)
|
||||||
|
|
||||||
(call emit (call format "_%" name))
|
(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 ") {\n" name))
|
||||||
(call emit (call format "runtime.pushCall(\"%\");" name))
|
(call emit (call format "runtime.pushCall(\"%\");" name))
|
||||||
|
|
||||||
(call emit_expr body)
|
(call emit_expr body)
|
||||||
(call emit "}")
|
(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
|
) (if (== id "do") (do
|
||||||
|
(call enter_scope)
|
||||||
|
(call discover_syms (call slice s 1))
|
||||||
(call emit_exprs (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
|
) (if (== id "return") (do
|
||||||
(let (_ value) s)
|
(let (_ value) s)
|
||||||
(call emit "runtime.popCall();\n")
|
(call emit "runtime.popCall();\n")
|
||||||
@ -124,6 +180,27 @@
|
|||||||
))
|
))
|
||||||
|
|
||||||
(call emit "))")
|
(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
|
) (do
|
||||||
(call emit "{ type: \"list\", values: [")
|
(call emit "{ type: \"list\", values: [")
|
||||||
(let first true)
|
(let first true)
|
||||||
@ -136,7 +213,34 @@
|
|||||||
(call emit_expr e)
|
(call emit_expr e)
|
||||||
))
|
))
|
||||||
(call emit "] }")
|
(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
|
(fn emit (str) (do
|
||||||
@ -148,7 +252,20 @@
|
|||||||
|
|
||||||
(fn Syms () (do
|
(fn Syms () (do
|
||||||
(let syms (null (
|
(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
|
(fn enter_scope () (do
|
||||||
@ -165,9 +282,9 @@
|
|||||||
(let i 0)
|
(let i 0)
|
||||||
(loop (do
|
(loop (do
|
||||||
(if (>= i (call len syms)) (break))
|
(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
|
(if (== ident s_ident) (do
|
||||||
(call set s_syms i sym)
|
(call set syms i sym)
|
||||||
(return)
|
(return)
|
||||||
))
|
))
|
||||||
(+= i 1)
|
(+= i 1)
|
||||||
@ -187,7 +304,7 @@
|
|||||||
(+= i 1)
|
(+= i 1)
|
||||||
))
|
))
|
||||||
(if (!= parent null) (do
|
(if (!= parent null) (do
|
||||||
(return (call find_syms parent ident))
|
(return (call find_sym parent ident))
|
||||||
))
|
))
|
||||||
(return null)
|
(return null)
|
||||||
))
|
))
|
||||||
|
21
phi.js
21
phi.js
@ -46,6 +46,7 @@ class Evaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.currentLine = expr.line;
|
this.currentLine = 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") {
|
||||||
@ -154,20 +155,14 @@ class Evaluator {
|
|||||||
const right = this.evalToValue(s[2]);
|
const right = this.evalToValue(s[2]);
|
||||||
return {
|
return {
|
||||||
type: "value",
|
type: "value",
|
||||||
value: {
|
value: this.runtime.opEq(left, right),
|
||||||
type: "bool",
|
|
||||||
value: this.runtime.eq(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]);
|
||||||
return {
|
return {
|
||||||
type: "value",
|
type: "value",
|
||||||
value: {
|
value: this.runtime.opNe(left, right),
|
||||||
type: "bool",
|
|
||||||
value: !this.runtime.eq(left, right),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
} else if (id in this.comparisonOps) {
|
} else if (id in this.comparisonOps) {
|
||||||
const left = this.evalToValue(s[1]);
|
const left = this.evalToValue(s[1]);
|
||||||
@ -419,14 +414,12 @@ class Evaluator {
|
|||||||
"format": (...args) => this.runtime.builtinFormat(...args),
|
"format": (...args) => this.runtime.builtinFormat(...args),
|
||||||
"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) =>
|
"panic": (...args) => this.runtime.builtinPanic(...args),
|
||||||
this.runtime.builtinPanic(this.currentLine, ...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),
|
||||||
"len": (...args) => this.runtime.builtinLen(...args),
|
"len": (...args) => this.runtime.builtinLen(...args),
|
||||||
"string_to_int": (...args) => this.runtime.builtinStringToInt(...args),
|
"string_to_int": (...args) => this.runtime.builtinStringToInt(...args),
|
||||||
"char_code": (...args) => this.runtime.builtinCharCode(...args),
|
"char_code": (...args) => this.runtime.builtinCharCode(...args),
|
||||||
|
29
runtime.js
29
runtime.js
@ -54,7 +54,7 @@ export class Runtime {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
eq(left, right) {
|
equalityOperation(left, right) {
|
||||||
if (left.type === "null") {
|
if (left.type === "null") {
|
||||||
return right.type === "null";
|
return right.type === "null";
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ export class Runtime {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < left.values.length; ++i) {
|
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;
|
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) {
|
builtinFormat(msg, ...args) {
|
||||||
return { type: "string", value: this.format(msg, ...args) };
|
return { type: "string", value: this.format(msg, ...args) };
|
||||||
}
|
}
|
||||||
@ -97,8 +112,8 @@ export class Runtime {
|
|||||||
return { type: "null" };
|
return { type: "null" };
|
||||||
}
|
}
|
||||||
|
|
||||||
builtinPanic(currentLine, msg, ...args) {
|
builtinPanic(msg, ...args) {
|
||||||
this.panic(this.format(msg, ...args), currentLine);
|
this.panic(this.format(msg, ...args));
|
||||||
return { type: "null" };
|
return { type: "null" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,8 +191,7 @@ 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 `(${
|
return `(${value.values.map((v) => Runtime.valueToString(v)).join(" ")
|
||||||
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}`);
|
||||||
@ -194,8 +208,7 @@ 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 `(${
|
return `(${value.values.map((v) => Runtime.valueToString(v)).join(" ")
|
||||||
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}`);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user