mirror of
				https://git.sfja.dk/Mikkel/slige.git
				synced 2025-10-31 14:18:16 +00:00 
			
		
		
		
	everything
This commit is contained in:
		
							parent
							
								
									f3523e486b
								
							
						
					
					
						commit
						072e44eaa8
					
				| @ -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}>`; | ||||
|     } | ||||
|  | ||||
| @ -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,21 +86,14 @@ 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}:`); | ||||
|                 console.log(`        ${label}:`); | ||||
|             } | ||||
|             const op = opToString(line.ins[0] as number) | ||||
|                 .padEnd(13, " "); | ||||
| @ -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}`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
| }; | ||||
|  | ||||
| @ -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" }; | ||||
|  | ||||
| @ -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("=")) { | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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(); | ||||
| } | ||||
|  | ||||
| @ -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(")")) { | ||||
|  | ||||
| @ -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(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -1,14 +1,17 @@ | ||||
| fn add(a, b) { | ||||
| fn add(a: int, b: int) -> int { | ||||
|     + a b | ||||
| } | ||||
| 
 | ||||
| let result = 0; | ||||
| let i = 0; | ||||
| loop { | ||||
|     if >= i 10 { | ||||
|         break; | ||||
| fn main() -> int { | ||||
|     let result = 0; | ||||
|     let i = 0; | ||||
|     loop { | ||||
|         if >= i 10 { | ||||
|             break; | ||||
|         } | ||||
|         result = add(result, 5); | ||||
|         i = + i 1; | ||||
|     } | ||||
|     result = add(result, 5); | ||||
|     i = + i 1; | ||||
|     result | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|         } | ||||
|  | ||||
| @ -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; | ||||
|         } | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user