everything

This commit is contained in:
SimonFJ20 2024-12-11 12:36:19 +01:00
parent f3523e486b
commit 072e44eaa8
15 changed files with 186 additions and 148 deletions

View File

@ -42,6 +42,7 @@ export const Builtins = {
StringEqual: 0x11, StringEqual: 0x11,
ArraySet: 0x20, ArraySet: 0x20,
StructSet: 0x30, StructSet: 0x30,
Print: 0x40,
} as const; } as const;
export function opToString(op: number): string { export function opToString(op: number): string {
@ -119,6 +120,8 @@ export function builtinToString(builtin: number): string {
return "ArraySet"; return "ArraySet";
case Builtins.StructSet: case Builtins.StructSet:
return "StructSet"; return "StructSet";
case Builtins.Print:
return "Print";
default: default:
return `<unknown Builtin ${builtin}>`; return `<unknown Builtin ${builtin}>`;
} }

View File

@ -49,17 +49,10 @@ export class Assembler {
const locs: { [key: string]: number } = {}; const locs: { [key: string]: number } = {};
const refs: { [key: number]: string } = {}; const refs: { [key: number]: string } = {};
const debugLines: {
startIp: number;
endIp: number;
insString: string;
}[] = [];
for (const line of this.lines) { for (const line of this.lines) {
for (const label of line.labels ?? []) { for (const label of line.labels ?? []) {
locs[label] = ip; locs[label] = ip;
} }
const startIp = ip;
for (const lit of line.ins as Lit[]) { for (const lit of line.ins as Lit[]) {
if (typeof lit === "number") { if (typeof lit === "number") {
output.push(lit); output.push(lit);
@ -68,6 +61,8 @@ export class Assembler {
output.push(lit ? 1 : 0); output.push(lit ? 1 : 0);
ip += 1; ip += 1;
} else if (typeof lit === "string") { } else if (typeof lit === "string") {
output.push(lit.length);
ip += 1;
for (let i = 0; i < lit.length; ++i) { for (let i = 0; i < lit.length; ++i) {
output.push(lit.charCodeAt(i)); output.push(lit.charCodeAt(i));
ip += 1; ip += 1;
@ -78,11 +73,6 @@ export class Assembler {
ip += 1; ip += 1;
} }
} }
debugLines.push({
startIp,
endIp: ip,
insString: this.insToString(line.ins),
});
} }
for (let i = 0; i < output.length; ++i) { for (let i = 0; i < output.length; ++i) {
if (!(i in refs)) { if (!(i in refs)) {
@ -96,21 +86,14 @@ export class Assembler {
} }
output[i] = locs[refs[i]]; output[i] = locs[refs[i]];
} }
for (const line of debugLines) {
console.log(
line.startIp.toString().padStart(3, " ") + " " +
output.slice(line.startIp, line.endIp).join(", ") + "\n" +
line.insString + "\n",
);
}
return output; return output;
} }
public printProgram() { public printProgram() {
let ip = 0;
for (const line of this.lines) { for (const line of this.lines) {
for (const label of line.labels ?? []) { for (const label of line.labels ?? []) {
console.log(`${label}:`); console.log(` ${label}:`);
} }
const op = opToString(line.ins[0] as number) const op = opToString(line.ins[0] as number)
.padEnd(13, " "); .padEnd(13, " ");
@ -129,28 +112,10 @@ export class Assembler {
return lit.label; return lit.label;
} }
}).join(", "); }).join(", ");
console.log(` ${op} ${args}`); console.log(`${ip.toString().padStart(8, " ")}: ${op} ${args}`);
ip += line.ins.map((lit) =>
typeof lit === "string" ? lit.length : 1
).reduce((acc, curr) => acc + curr, 0);
} }
} }
private insToString(ins: Ins): string {
const op = opToString(ins[0] as number)
.padEnd(13, " ");
const args = (ins.slice(1) as Lit[]).map((lit) => {
if (typeof lit === "number") {
return lit;
} else if (typeof lit === "boolean") {
return lit.toString();
} else if (typeof lit === "string") {
return '"' +
lit.replaceAll("\\", "\\\\").replaceAll("\0", "\\0")
.replaceAll("\n", "\\n").replaceAll("\t", "\\t")
.replaceAll("\r", "\\r") +
'"';
} else {
return lit.label;
}
}).join(", ");
return ` ${op} ${args}`;
}
} }

View File

@ -39,6 +39,7 @@ export type StmtKind =
params: Param[]; params: Param[];
returnType?: EType; returnType?: EType;
body: Expr; body: Expr;
annos?: Anno[];
vtype?: VType; vtype?: VType;
} }
| { type: "let"; param: Param; value: Expr } | { type: "let"; param: Param; value: Expr }
@ -85,7 +86,7 @@ export type SymKind =
| { type: "fn"; stmt: Stmt } | { type: "fn"; stmt: Stmt }
| { type: "fn_param"; param: Param } | { type: "fn_param"; param: Param }
| { type: "closure"; inner: Sym } | { type: "closure"; inner: Sym }
| { type: "builtin" }; | { type: "builtin"; builtinId: number };
export type EType = { export type EType = {
kind: ETypeKind; kind: ETypeKind;
@ -98,3 +99,9 @@ export type ETypeKind =
| { type: "ident"; value: string } | { type: "ident"; value: string }
| { type: "array"; inner: EType } | { type: "array"; inner: EType }
| { type: "struct"; fields: Param[] }; | { type: "struct"; fields: Param[] };
export type Anno = {
ident: string;
values: Expr[];
pos: Pos;
};

View File

@ -1,4 +1,4 @@
import { StmtKind } from "./ast.ts"; import { Builtins } from "./arch.ts";
import { EType, Expr, Stmt } from "./ast.ts"; import { EType, Expr, Stmt } from "./ast.ts";
import { printStackTrace, Reporter } from "./info.ts"; import { printStackTrace, Reporter } from "./info.ts";
import { Pos } from "./token.ts"; import { Pos } from "./token.ts";
@ -356,6 +356,7 @@ export class Checker {
} }
const pos = expr.pos; const pos = expr.pos;
const subject = this.checkExpr(expr.kind.subject); const subject = this.checkExpr(expr.kind.subject);
console.log(expr);
if (subject.type !== "fn") { if (subject.type !== "fn") {
this.report("cannot call non-fn", pos); this.report("cannot call non-fn", pos);
return { type: "error" }; return { type: "error" };

View File

@ -91,7 +91,7 @@ export class Lexer {
this.step(); this.step();
return { ...this.token("string", pos), stringValue: value }; return { ...this.token("string", pos), stringValue: value };
} }
if (this.test(/[\+\{\};=\-\*\(\)\.,:;\[\]><!0]/)) { if (this.test(/[\+\{\};=\-\*\(\)\.,:;\[\]><!0#]/)) {
const first = this.current(); const first = this.current();
this.step(); this.step();
if (first === "=" && !this.done() && this.test("=")) { if (first === "=" && !this.done() && this.test("=")) {

View File

@ -1,9 +1,9 @@
import { Builtins } from "./arch.ts"; import { Builtins } from "./arch.ts";
import { BinaryType, Expr, Stmt } from "./ast.ts"; import { Expr, Stmt } from "./ast.ts";
import { LocalLeaf, Locals, LocalsFnRoot } from "./lowerer_locals.ts"; import { LocalLeaf, Locals, LocalsFnRoot } from "./lowerer_locals.ts";
import { Ops } from "./mod.ts"; import { Ops } from "./mod.ts";
import { Assembler, Label } from "./assembler.ts"; import { Assembler, Label } from "./assembler.ts";
import { VType, vtypeToString } from "./vtype.ts"; import { vtypeToString } from "./vtype.ts";
export class Lowerer { export class Lowerer {
private program = new Assembler(); private program = new Assembler();
@ -134,25 +134,13 @@ export class Lowerer {
for (const { ident } of stmt.kind.params) { for (const { ident } of stmt.kind.params) {
this.locals.allocSym(ident); this.locals.allocSym(ident);
} }
this.locals.allocSym("::return");
this.program.add(Ops.PushNull);
this.lowerExpr(stmt.kind.body); this.lowerExpr(stmt.kind.body);
this.program.add(Ops.StoreLocal, this.locals.symId("::return"));
this.locals = outerLocals; this.locals = outerLocals;
for ( const localAmount = fnRoot.stackReserved() -
let i = 0; stmt.kind.params.length;
i < fnRoot.stackReserved() - 1 - stmt.kind.params.length; for (let i = 0; i < localAmount; ++i) {
++i
) {
outerProgram.add(Ops.PushNull); outerProgram.add(Ops.PushNull);
this.program.add(Ops.Pop);
}
if (stmt.kind.params.length >= 1) {
this.program.add(Ops.StoreLocal, 0);
}
for (let i = 0; i < stmt.kind.params.length - 1; ++i) {
this.program.add(Ops.Pop);
} }
this.program.add(Ops.Return); this.program.add(Ops.Return);
@ -334,6 +322,8 @@ export class Lowerer {
if (expr.kind.falsy) { if (expr.kind.falsy) {
this.lowerExpr(expr.kind.falsy!); this.lowerExpr(expr.kind.falsy!);
} else {
this.program.add(Ops.PushNull);
} }
this.program.setLabel(doneLabel); this.program.setLabel(doneLabel);

View File

@ -1,14 +1,5 @@
import { Stmt } from "./ast.ts";
import { Lexer } from "./lexer.ts";
import { Parser } from "./parser.ts";
export * from "./parser.ts"; export * from "./parser.ts";
export * from "./ast.ts"; export * from "./ast.ts";
export * from "./arch.ts"; export * from "./arch.ts";
export * from "./lexer.ts"; export * from "./lexer.ts";
export * from "./token.ts"; export * from "./token.ts";
export async function compileWithDebug(filepath: string): Promise<Stmt[]> {
const text = await Deno.readTextFile(filepath);
return new Parser(new Lexer(text)).parseStmts();
}

View File

@ -1,4 +1,5 @@
import { import {
Anno,
BinaryType, BinaryType,
EType, EType,
ETypeKind, ETypeKind,
@ -203,6 +204,11 @@ export class Parser {
this.step(); this.step();
returnType = this.parseEType(); returnType = this.parseEType();
} }
let annos: Anno[] | null = null;
if (this.test("#")) {
annos = this.parseAnnoArgs();
}
if (!this.test("{")) { if (!this.test("{")) {
this.report("expected block"); this.report("expected block");
return this.stmt({ type: "error" }, pos); return this.stmt({ type: "error" }, pos);
@ -214,6 +220,62 @@ export class Parser {
return this.stmt({ type: "fn", ident, params, returnType, body }, pos); return this.stmt({ type: "fn", ident, params, returnType, body }, pos);
} }
public parseAnnoArgs(): Expr[] {
this.step();
if (!this.test("(")) {
this.report("expected '('");
return [];
}
this.step();
const annoArgs: Expr[] = [];
if (!this.test(")")) {
annoArgs.push(this.parseExpr());
while (this.test(",")) {
this.step();
if (this.test(")")) {
break;
}
annoArgs.push(this.parseExpr());
}
}
if (!this.test(")")) {
this.report("expected ')'");
return [];
}
this.step();
return annoArgs;
}
public parseAnnos(): Anno[] {
this.step();
if (!this.test("[")) {
this.report("expected '['");
return [];
}
this.step();
const annoArgs: Expr[] = [];
if (!this.test(")")) {
if (!this.test("ident")) {
this.report("expected identifier");
return [];
}
annoArgs.push(this.parseExpr());
while (this.test(",")) {
this.step();
if (this.test(")")) {
break;
}
annoArgs.push(this.parseExpr());
}
}
if (!this.test(")")) {
this.report("expected ')'");
return [];
}
this.step();
return annoArgs;
}
public parseFnParams(): Param[] { public parseFnParams(): Param[] {
this.step(); this.step();
if (this.test(")")) { if (this.test(")")) {

View File

@ -1,5 +1,6 @@
import { Builtins } from "./arch.ts";
import { Expr, Stmt } from "./ast.ts"; import { Expr, Stmt } from "./ast.ts";
import { Reporter } from "./info.ts"; import { printStackTrace, Reporter } from "./info.ts";
import { import {
FnSyms, FnSyms,
GlobalSyms, GlobalSyms,
@ -12,7 +13,13 @@ import { Pos } from "./token.ts";
export class Resolver { export class Resolver {
private root = new GlobalSyms(); private root = new GlobalSyms();
public constructor(private reporter: Reporter) {} public constructor(private reporter: Reporter) {
this.root.define("print", {
type: "builtin",
ident: "print",
builtinId: Builtins.Print,
});
}
public resolve(stmts: Stmt[]) { public resolve(stmts: Stmt[]) {
const scopeSyms = new StaticSyms(this.root); const scopeSyms = new StaticSyms(this.root);
@ -208,6 +215,7 @@ export class Resolver {
msg: `use of undefined symbol '${ident}'`, msg: `use of undefined symbol '${ident}'`,
pos, pos,
}); });
printStackTrace();
} }
private reportAlreadyDefined(ident: string, pos: Pos, syms: Syms) { private reportAlreadyDefined(ident: string, pos: Pos, syms: Syms) {
@ -228,5 +236,6 @@ export class Resolver {
msg: `previous definition of '${ident}'`, msg: `previous definition of '${ident}'`,
pos: prev.sym.pos, pos: prev.sym.pos,
}); });
printStackTrace();
} }
} }

View File

@ -1,5 +1,4 @@
fn main() -> int { fn main() -> int {
add(1, 2) add(1, 2)
} }
@ -11,5 +10,5 @@ fn add(a: int, b: int) -> int {
let a = c; let a = c;
+ a d + a d
} }
//+ a b
} }

View File

@ -1,6 +1,4 @@
fn print(msg: string) #[builtin(print)] {}
fn println(str: string) {
}
fn sum(a: int, b: int) -> int { fn sum(a: int, b: int) -> int {
+ a b + a b
@ -13,13 +11,13 @@ fn main() {
let b = "world"; let b = "world";
println(+ + + a " " b "!"); // -> "Hello world!" print(+ + + a " " b "!\n"); // -> "Hello world!"
if == a b { if == a b {
println("whaaaat"); print("whaaaat\n");
} }
else { else {
println(":o"); print(":o\n");
} }
loop { loop {

View File

@ -1,14 +1,17 @@
fn add(a, b) { fn add(a: int, b: int) -> int {
+ a b + a b
} }
let result = 0; fn main() -> int {
let i = 0; let result = 0;
loop { let i = 0;
loop {
if >= i 10 { if >= i 10 {
break; break;
} }
result = add(result, 5); result = add(result, 5);
i = + i 1; i = + i 1;
}
result
} }

View File

@ -10,6 +10,30 @@
namespace sliger { namespace sliger {
inline auto escape_string(std::string str) -> std::string
{
auto result = std::string();
for (auto ch : str) {
switch (ch) {
case '\n':
result += "\\n";
break;
case '\t':
result += "\\t";
break;
case '\0':
result += "\\0";
break;
case '\\':
result += "\\\\";
break;
default:
result += ch;
}
}
return result;
}
enum class ValueType { enum class ValueType {
Null, Null,
Int, Int,
@ -137,7 +161,7 @@ public:
case ValueType::Bool: case ValueType::Bool:
return as_bool().value ? "true" : "false"; return as_bool().value ? "true" : "false";
case ValueType::String: case ValueType::String:
return std::format("\"{}\"", as_string().value); return std::format("\"{}\"", escape_string(as_string().value));
case ValueType::Ptr: case ValueType::Ptr:
return std::to_string(as_ptr().value); return std::to_string(as_ptr().value);
} }

View File

@ -13,56 +13,37 @@ using namespace sliger;
inline auto maybe_op_to_string(uint32_t value) -> std::string inline auto maybe_op_to_string(uint32_t value) -> std::string
{ {
switch (static_cast<Op>(value)) { switch (static_cast<Op>(value)) {
case Op::Nop: /* clang-format off */
return "Nop"; case Op::Nop: return "Nop";
case Op::PushNull: case Op::PushNull: return "PushNull";
return "PushNull"; case Op::PushInt: return "PushInt";
case Op::PushInt: case Op::PushBool: return "PushBool";
return "PushInt"; case Op::PushString: return "PushString";
case Op::PushBool: case Op::PushPtr: return "PushPtr";
return "PushBool"; case Op::Pop: return "Pop";
case Op::PushString: case Op::ReserveStatic: return "ReserveStatic";
return "PushString"; case Op::LoadStatic: return "LoadStatic";
case Op::PushPtr: case Op::StoreStatic: return "StoreStatic";
return "PushPtr"; case Op::LoadLocal: return "LoadLocal";
case Op::Pop: case Op::StoreLocal: return "StoreLocal";
return "Pop"; case Op::Call: return "Call";
case Op::LoadLocal: case Op::Return: return "Return";
return "LoadLocal"; case Op::Jump: return "Jump";
case Op::StoreLocal: case Op::JumpIfTrue: return "JumpIfTrue";
return "StoreLocal"; case Op::Builtin: return "Builtin";
case Op::Call: case Op::Add: return "Add";
return "Call"; case Op::Subtract: return "Subtract";
case Op::Return: case Op::Multiply: return "Multiply";
return "Return"; case Op::Divide: return "Divide";
case Op::Jump: case Op::Remainder: return "Remainder";
return "Jump"; case Op::Equal: return "Equal";
case Op::JumpIfTrue: case Op::LessThan: return "LessThan";
return "JumpIfTrue"; case Op::And: return "And";
case Op::Add: case Op::Or: return "Or";
return "Add"; case Op::Xor: return "Xor";
case Op::Subtract: case Op::Not: return "Not";
return "Subtract"; case Op::SourceMap: return "SourceMap";
case Op::Multiply: /* clang-format on */
return "Multiply";
case Op::Divide:
return "Divide";
case Op::Remainder:
return "Remainder";
case Op::Equal:
return "Equal";
case Op::LessThan:
return "LessThan";
case Op::And:
return "And";
case Op::Or:
return "Or";
case Op::Xor:
return "Xor";
case Op::Not:
return "Not";
case Op::SourceMap:
return "SourceMap";
default: default:
return std::to_string(value); return std::to_string(value);
} }
@ -88,7 +69,7 @@ void VM::run_n_instructions(size_t amount)
void VM::run_instruction() void VM::run_instruction()
{ {
std::cout << std::format(" {:>4}: {:<12}{}\n", this->pc, std::cout << std::format(" {:>4}: {:<12}{}\n", this->pc,
maybe_op_to_string(this->program[this->pc]), stack_repr_string(6)); maybe_op_to_string(this->program[this->pc]), stack_repr_string(8));
auto op = eat_op(); auto op = eat_op();
switch (op) { switch (op) {
case Op::Nop: case Op::Nop:
@ -179,12 +160,11 @@ void VM::run_instruction()
} }
stack_push(Ptr { .value = this->pc }); stack_push(Ptr { .value = this->pc });
stack_push(Ptr { .value = this->bp }); stack_push(Ptr { .value = this->bp });
this->pc = fn_ptr.as_ptr().value;
this->bp = static_cast<uint32_t>(this->stack.size());
for (size_t i = arguments.size(); i > 0; --i) { for (size_t i = arguments.size(); i > 0; --i) {
stack_push(std::move(arguments.at(i - 1))); stack_push(std::move(arguments.at(i - 1)));
} }
this->pc = fn_ptr.as_ptr().value;
this->bp
= static_cast<uint32_t>(this->stack.size() - arguments.size());
if (this->opts.flame_graph) { if (this->opts.flame_graph) {
this->flame_graph.report_call( this->flame_graph.report_call(
fn_ptr.as_ptr().value, this->instruction_counter); fn_ptr.as_ptr().value, this->instruction_counter);
@ -194,6 +174,9 @@ void VM::run_instruction()
case Op::Return: { case Op::Return: {
assert_stack_has(3); assert_stack_has(3);
auto ret_val = stack_pop(); auto ret_val = stack_pop();
while (this->stack.size() > this->bp) {
stack_pop();
}
auto bp_val = stack_pop(); auto bp_val = stack_pop();
auto pc_val = stack_pop(); auto pc_val = stack_pop();
this->bp = bp_val.as_ptr().value; this->bp = bp_val.as_ptr().value;
@ -331,16 +314,16 @@ void VM::run_builtin(Builtin builtin_id)
switch (builtin_id) { switch (builtin_id) {
case Builtin::StringConcat: { case Builtin::StringConcat: {
assert_stack_has(2); assert_stack_has(2);
auto right = stack_pop();
auto left = stack_pop(); auto left = stack_pop();
auto right = stack_pop();
stack_push( stack_push(
String(right.as_string().value + left.as_string().value)); String(right.as_string().value + left.as_string().value));
break; break;
} }
case Builtin::StringEqual: { case Builtin::StringEqual: {
assert_stack_has(2); assert_stack_has(2);
auto right = stack_pop();
auto left = stack_pop(); auto left = stack_pop();
auto right = stack_pop();
stack_push(Bool(right.as_string().value == left.as_string().value)); stack_push(Bool(right.as_string().value == left.as_string().value));
break; break;
} }

View File

@ -2,11 +2,14 @@
set -e set -e
echo Text:
cat $1
echo Compiling $1... echo Compiling $1...
deno run --allow-read --allow-write compiler/main.ts $1 deno run --allow-read --allow-write compiler/main.ts $1
echo "Running out.slgbc..." echo Running out.slgbc...
./runtime/build/sliger run out.slgbc ./runtime/build/sliger run out.slgbc