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

View File

@ -49,17 +49,10 @@ export class Assembler {
const locs: { [key: string]: number } = {};
const refs: { [key: number]: string } = {};
const debugLines: {
startIp: number;
endIp: number;
insString: string;
}[] = [];
for (const line of this.lines) {
for (const label of line.labels ?? []) {
locs[label] = ip;
}
const startIp = ip;
for (const lit of line.ins as Lit[]) {
if (typeof lit === "number") {
output.push(lit);
@ -68,6 +61,8 @@ export class Assembler {
output.push(lit ? 1 : 0);
ip += 1;
} else if (typeof lit === "string") {
output.push(lit.length);
ip += 1;
for (let i = 0; i < lit.length; ++i) {
output.push(lit.charCodeAt(i));
ip += 1;
@ -78,11 +73,6 @@ export class Assembler {
ip += 1;
}
}
debugLines.push({
startIp,
endIp: ip,
insString: this.insToString(line.ins),
});
}
for (let i = 0; i < output.length; ++i) {
if (!(i in refs)) {
@ -96,18 +86,11 @@ export class Assembler {
}
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;
}
public printProgram() {
let ip = 0;
for (const line of this.lines) {
for (const label of line.labels ?? []) {
console.log(` ${label}:`);
@ -129,28 +112,10 @@ export class Assembler {
return lit.label;
}
}).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[];
returnType?: EType;
body: Expr;
annos?: Anno[];
vtype?: VType;
}
| { type: "let"; param: Param; value: Expr }
@ -85,7 +86,7 @@ export type SymKind =
| { type: "fn"; stmt: Stmt }
| { type: "fn_param"; param: Param }
| { type: "closure"; inner: Sym }
| { type: "builtin" };
| { type: "builtin"; builtinId: number };
export type EType = {
kind: ETypeKind;
@ -98,3 +99,9 @@ export type ETypeKind =
| { type: "ident"; value: string }
| { type: "array"; inner: EType }
| { 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 { printStackTrace, Reporter } from "./info.ts";
import { Pos } from "./token.ts";
@ -356,6 +356,7 @@ export class Checker {
}
const pos = expr.pos;
const subject = this.checkExpr(expr.kind.subject);
console.log(expr);
if (subject.type !== "fn") {
this.report("cannot call non-fn", pos);
return { type: "error" };

View File

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

View File

@ -1,9 +1,9 @@
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 { Ops } from "./mod.ts";
import { Assembler, Label } from "./assembler.ts";
import { VType, vtypeToString } from "./vtype.ts";
import { vtypeToString } from "./vtype.ts";
export class Lowerer {
private program = new Assembler();
@ -134,25 +134,13 @@ export class Lowerer {
for (const { ident } of stmt.kind.params) {
this.locals.allocSym(ident);
}
this.locals.allocSym("::return");
this.program.add(Ops.PushNull);
this.lowerExpr(stmt.kind.body);
this.program.add(Ops.StoreLocal, this.locals.symId("::return"));
this.locals = outerLocals;
for (
let i = 0;
i < fnRoot.stackReserved() - 1 - stmt.kind.params.length;
++i
) {
const localAmount = fnRoot.stackReserved() -
stmt.kind.params.length;
for (let i = 0; i < localAmount; ++i) {
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);
@ -334,6 +322,8 @@ export class Lowerer {
if (expr.kind.falsy) {
this.lowerExpr(expr.kind.falsy!);
} else {
this.program.add(Ops.PushNull);
}
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 "./ast.ts";
export * from "./arch.ts";
export * from "./lexer.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 {
Anno,
BinaryType,
EType,
ETypeKind,
@ -203,6 +204,11 @@ export class Parser {
this.step();
returnType = this.parseEType();
}
let annos: Anno[] | null = null;
if (this.test("#")) {
annos = this.parseAnnoArgs();
}
if (!this.test("{")) {
this.report("expected block");
return this.stmt({ type: "error" }, pos);
@ -214,6 +220,62 @@ export class Parser {
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[] {
this.step();
if (this.test(")")) {

View File

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

View File

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

View File

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

View File

@ -1,7 +1,8 @@
fn add(a, b) {
fn add(a: int, b: int) -> int {
+ a b
}
fn main() -> int {
let result = 0;
let i = 0;
loop {
@ -11,4 +12,6 @@ loop {
result = add(result, 5);
i = + i 1;
}
result
}

View File

@ -10,6 +10,30 @@
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 {
Null,
Int,
@ -137,7 +161,7 @@ public:
case ValueType::Bool:
return as_bool().value ? "true" : "false";
case ValueType::String:
return std::format("\"{}\"", as_string().value);
return std::format("\"{}\"", escape_string(as_string().value));
case ValueType::Ptr:
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
{
switch (static_cast<Op>(value)) {
case Op::Nop:
return "Nop";
case Op::PushNull:
return "PushNull";
case Op::PushInt:
return "PushInt";
case Op::PushBool:
return "PushBool";
case Op::PushString:
return "PushString";
case Op::PushPtr:
return "PushPtr";
case Op::Pop:
return "Pop";
case Op::LoadLocal:
return "LoadLocal";
case Op::StoreLocal:
return "StoreLocal";
case Op::Call:
return "Call";
case Op::Return:
return "Return";
case Op::Jump:
return "Jump";
case Op::JumpIfTrue:
return "JumpIfTrue";
case Op::Add:
return "Add";
case Op::Subtract:
return "Subtract";
case Op::Multiply:
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";
/* clang-format off */
case Op::Nop: return "Nop";
case Op::PushNull: return "PushNull";
case Op::PushInt: return "PushInt";
case Op::PushBool: return "PushBool";
case Op::PushString: return "PushString";
case Op::PushPtr: return "PushPtr";
case Op::Pop: return "Pop";
case Op::ReserveStatic: return "ReserveStatic";
case Op::LoadStatic: return "LoadStatic";
case Op::StoreStatic: return "StoreStatic";
case Op::LoadLocal: return "LoadLocal";
case Op::StoreLocal: return "StoreLocal";
case Op::Call: return "Call";
case Op::Return: return "Return";
case Op::Jump: return "Jump";
case Op::JumpIfTrue: return "JumpIfTrue";
case Op::Builtin: return "Builtin";
case Op::Add: return "Add";
case Op::Subtract: return "Subtract";
case Op::Multiply: 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";
/* clang-format on */
default:
return std::to_string(value);
}
@ -88,7 +69,7 @@ void VM::run_n_instructions(size_t amount)
void VM::run_instruction()
{
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();
switch (op) {
case Op::Nop:
@ -179,12 +160,11 @@ void VM::run_instruction()
}
stack_push(Ptr { .value = this->pc });
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) {
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) {
this->flame_graph.report_call(
fn_ptr.as_ptr().value, this->instruction_counter);
@ -194,6 +174,9 @@ void VM::run_instruction()
case Op::Return: {
assert_stack_has(3);
auto ret_val = stack_pop();
while (this->stack.size() > this->bp) {
stack_pop();
}
auto bp_val = stack_pop();
auto pc_val = stack_pop();
this->bp = bp_val.as_ptr().value;
@ -331,16 +314,16 @@ void VM::run_builtin(Builtin builtin_id)
switch (builtin_id) {
case Builtin::StringConcat: {
assert_stack_has(2);
auto right = stack_pop();
auto left = stack_pop();
auto right = stack_pop();
stack_push(
String(right.as_string().value + left.as_string().value));
break;
}
case Builtin::StringEqual: {
assert_stack_has(2);
auto right = stack_pop();
auto left = stack_pop();
auto right = stack_pop();
stack_push(Bool(right.as_string().value == left.as_string().value));
break;
}

View File

@ -2,11 +2,14 @@
set -e
echo Text:
cat $1
echo Compiling $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