diff --git a/a.out b/a.out new file mode 100755 index 0000000..4ea0e71 Binary files /dev/null and b/a.out differ diff --git a/examples/test_2 b/examples/test_2 new file mode 100755 index 0000000..6277a72 Binary files /dev/null and b/examples/test_2 differ diff --git a/examples/test_2.gom b/examples/test_2.gom index cd20e9c..429da07 100644 --- a/examples/test_2.gom +++ b/examples/test_2.gom @@ -1,5 +1,6 @@ import io; +// struct type Point = { x: int, y: int diff --git a/examples/test_2.s b/examples/test_2.s new file mode 100644 index 0000000..122037f --- /dev/null +++ b/examples/test_2.s @@ -0,0 +1,147 @@ + .section __TEXT,__text,regular,pure_instructions + .build_version macos, 14, 0 + .globl _square ; -- Begin function square + .p2align 2 +_square: ; @square + .cfi_startproc +; %bb.0: ; %entry + sub sp, sp, #16 + .cfi_def_cfa_offset 16 + mov w8, w0 + mul w0, w0, w0 + str w8, [sp, #12] + add sp, sp, #16 + ret + .cfi_endproc + ; -- End function + .globl _add ; -- Begin function add + .p2align 2 +_add: ; @add + .cfi_startproc +; %bb.0: ; %entry + sub sp, sp, #16 + .cfi_def_cfa_offset 16 + mov w8, w0 + add w0, w0, w1 + stp w1, w8, [sp, #8] + add sp, sp, #16 + ret + .cfi_endproc + ; -- End function + .globl _distance ; -- Begin function distance + .p2align 2 +_distance: ; @distance + .cfi_startproc +; %bb.0: ; %entry + sub sp, sp, #48 + stp x20, x19, [sp, #16] ; 16-byte Folded Spill + stp x29, x30, [sp, #32] ; 16-byte Folded Spill + .cfi_def_cfa_offset 48 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + .cfi_offset w19, -24 + .cfi_offset w20, -32 + sub w8, w0, w2 + stp w0, w1, [sp, #8] + mov w0, w8 + stp w2, w3, [sp] + bl _square + ldr w8, [sp, #12] + mov w19, w0 + ldr w9, [sp, #4] + sub w0, w8, w9 + bl _square + add w0, w19, w0 + ldp x29, x30, [sp, #32] ; 16-byte Folded Reload + ldp x20, x19, [sp, #16] ; 16-byte Folded Reload + add sp, sp, #48 + ret + .cfi_endproc + ; -- End function + .globl _main ; -- Begin function main + .p2align 2 +_main: ; @main + .cfi_startproc +; %bb.0: ; %entry + sub sp, sp, #96 + stp x22, x21, [sp, #48] ; 16-byte Folded Spill + stp x20, x19, [sp, #64] ; 16-byte Folded Spill + stp x29, x30, [sp, #80] ; 16-byte Folded Spill + .cfi_def_cfa_offset 96 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + .cfi_offset w19, -24 + .cfi_offset w20, -32 + .cfi_offset w21, -40 + .cfi_offset w22, -48 + mov x8, #1 + mov x9, #3 + movk x8, #2, lsl #32 + movk x9, #4, lsl #32 + mov w0, #1 + mov w1, #2 + mov w2, #3 + mov w3, #4 + stp x9, x8, [sp, #32] + bl _distance + mov w19, w0 + str w0, [sp, #28] +Lloh0: + adrp x0, l_.strliteral@PAGE +Lloh1: + add x0, x0, l_.strliteral@PAGEOFF + bl _printf +Lloh2: + adrp x20, l_fmt.int@PAGE + str x19, [sp] +Lloh3: + add x20, x20, l_fmt.int@PAGEOFF + mov x0, x20 + bl _printf +Lloh4: + adrp x19, l_newline@PAGE +Lloh5: + add x19, x19, l_newline@PAGEOFF + mov x0, x19 + bl _printf + ldp w0, w1, [sp, #40] + ldp w2, w3, [sp, #32] + stp w0, w1, [sp, #8] + stp w2, w3, [sp, #16] + bl _distance + mov w21, w0 +Lloh6: + adrp x0, l_.strliteral.1@PAGE +Lloh7: + add x0, x0, l_.strliteral.1@PAGEOFF + bl _printf + mov x0, x20 + str x21, [sp] + bl _printf + mov x0, x19 + bl _printf + ldp x29, x30, [sp, #80] ; 16-byte Folded Reload + ldp x20, x19, [sp, #64] ; 16-byte Folded Reload + ldp x22, x21, [sp, #48] ; 16-byte Folded Reload + add sp, sp, #96 + ret + .loh AdrpAdd Lloh6, Lloh7 + .loh AdrpAdd Lloh4, Lloh5 + .loh AdrpAdd Lloh2, Lloh3 + .loh AdrpAdd Lloh0, Lloh1 + .cfi_endproc + ; -- End function + .section __TEXT,__cstring,cstring_literals +l_.strliteral: ; @.strliteral + .asciz "Distance between p1 and p2: " + +l_fmt.int: ; @fmt.int + .asciz "%d" + +l_newline: ; @newline + .asciz "\n" + +l_.strliteral.1: ; @.strliteral.1 + .asciz "Distance between l.p1 and l.p2: " + +.subsections_via_symbols diff --git a/examples/test_3 b/examples/test_3 new file mode 100755 index 0000000..068f852 Binary files /dev/null and b/examples/test_3 differ diff --git a/examples/test_3.gom b/examples/test_3.gom new file mode 100644 index 0000000..5590b03 --- /dev/null +++ b/examples/test_3.gom @@ -0,0 +1,31 @@ +import io; + +// tuple +type HttpResponse = { int, bool }; + + +fn process_http(url: str): HttpResponse { + if(url == "http://www.example.com") { + return { 200, true }; + } + + return { 401, false }; +} + +fn process_http_retry(url: str, retries: int): HttpResponse { + let i = 0; + for(i = retries; i > 0; i = i - 1) { + io.log("Round: ", retries - i + 1); + let resp = process_http(url); + if(resp.1) { + return resp; + } + } + + return { 500, false }; +} + +fn main() { + let resp = process_http_retry("http://www.example.com", 10); + io.log("Status: ", resp.0, " Success: ", resp.1); +} \ No newline at end of file diff --git a/examples/test_3.ll b/examples/test_3.ll new file mode 100644 index 0000000..00b447a --- /dev/null +++ b/examples/test_3.ll @@ -0,0 +1,115 @@ +; ModuleID = 'mod' +source_filename = "mod" + +@.strliteral = private unnamed_addr constant [23 x i8] c"http://www.example.com\00", align 1 +@.strliteral.1 = private unnamed_addr constant [8 x i8] c"Round: \00", align 1 +@fmt.int = private unnamed_addr constant [3 x i8] c"%d\00", align 1 +@newline = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@.strliteral.2 = private unnamed_addr constant [23 x i8] c"http://www.example.com\00", align 1 +@.strliteral.3 = private unnamed_addr constant [9 x i8] c"Status: \00", align 1 +@.strliteral.4 = private unnamed_addr constant [11 x i8] c" Success: \00", align 1 +@fmt.bool = private unnamed_addr constant [3 x i8] c"%d\00", align 1 + +declare i32 @printf(i8*, ...) + +define void @process_http({ i32, i1 }* "noalias" "sret" %0, i8* %1) { +entry: + %2 = alloca i8*, align 8 + store i8* %1, i8** %2, align 8 + %url.load = load i8*, i8** %2, align 8 + %eqtmp = icmp eq i8* %url.load, getelementptr inbounds ([23 x i8], [23 x i8]* @.strliteral, i32 0, i32 0) + br i1 %eqtmp, label %then, label %else + +then: ; preds = %entry + %fieldptr = getelementptr { i32, i1 }, { i32, i1 }* %0, i32 0, i32 0 + store i32 200, i32* %fieldptr, align 4 + %fieldptr1 = getelementptr { i32, i1 }, { i32, i1 }* %0, i32 0, i32 1 + store i1 true, i1* %fieldptr1, align 1 + ret void + br label %merge + +else: ; preds = %entry + br label %merge + +merge: ; preds = %else, %then + %fieldptr2 = getelementptr { i32, i1 }, { i32, i1 }* %0, i32 0, i32 0 + store i32 401, i32* %fieldptr2, align 4 + %fieldptr3 = getelementptr { i32, i1 }, { i32, i1 }* %0, i32 0, i32 1 + store i1 false, i1* %fieldptr3, align 1 + ret void +} + +define void @process_http_retry({ i32, i1 }* "noalias" "sret" %0, i8* %1, i32 %2) { +entry: + %3 = alloca i8*, align 8 + store i8* %1, i8** %3, align 8 + %4 = alloca i32, align 4 + store i32 %2, i32* %4, align 4 + %i = alloca i32, align 4 + store i32 0, i32* %i, align 4 + store i32 0, i32* %i, align 4 + %retries.load = load i32, i32* %4, align 4 + store i32 %retries.load, i32* %i, align 4 + br label %loop + +loop: ; preds = %loopupdate, %entry + %i.load = load i32, i32* %i, align 4 + %gttmp = icmp sgt i32 %i.load, 0 + br i1 %gttmp, label %loopbody, label %afterloop + +loopbody: ; preds = %loop + %retries.load1 = load i32, i32* %4, align 4 + %i.load2 = load i32, i32* %i, align 4 + %subtmp = sub i32 %retries.load1, %i.load2 + %addtmp = add i32 %subtmp, 1 + %calltmp0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.strliteral.1, i32 0, i32 0)) + %calltmp1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @fmt.int, i32 0, i32 0), i32 %addtmp) + %newline = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @newline, i32 0, i32 0)) + %resp = alloca { i32, i1 }, align 8 + %url.load = load i8*, i8** %3, align 8 + call void @process_http({ i32, i1 }* %resp, i8* %url.load) + %fieldptr = getelementptr { i32, i1 }, { i32, i1 }* %resp, i32 0, i32 1 + %fieldload = load i1, i1* %fieldptr, align 1 + br i1 %fieldload, label %then, label %else + +loopupdate: ; preds = %merge + %i.load3 = load i32, i32* %i, align 4 + %subtmp4 = sub i32 %i.load3, 1 + store i32 %subtmp4, i32* %i, align 4 + br label %loop + +afterloop: ; preds = %loop + %fieldptr5 = getelementptr { i32, i1 }, { i32, i1 }* %0, i32 0, i32 0 + store i32 500, i32* %fieldptr5, align 4 + %fieldptr6 = getelementptr { i32, i1 }, { i32, i1 }* %0, i32 0, i32 1 + store i1 false, i1* %fieldptr6, align 1 + ret void + +then: ; preds = %loopbody + %resp.load = load { i32, i1 }, { i32, i1 }* %resp, align 4 + store { i32, i1 } %resp.load, { i32, i1 }* %0, align 4 + ret void + br label %merge + +else: ; preds = %loopbody + br label %merge + +merge: ; preds = %else, %then + br label %loopupdate +} + +define void @main() { +entry: + %resp = alloca { i32, i1 }, align 8 + call void @process_http_retry({ i32, i1 }* %resp, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.strliteral.2, i32 0, i32 0), i32 10) + %fieldptr = getelementptr { i32, i1 }, { i32, i1 }* %resp, i32 0, i32 0 + %fieldload = load i32, i32* %fieldptr, align 4 + %fieldptr1 = getelementptr { i32, i1 }, { i32, i1 }* %resp, i32 0, i32 1 + %fieldload2 = load i1, i1* %fieldptr1, align 1 + %calltmp0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.strliteral.3, i32 0, i32 0)) + %calltmp1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @fmt.int, i32 0, i32 0), i32 %fieldload) + %calltmp2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.strliteral.4, i32 0, i32 0)) + %calltmp3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @fmt.bool, i32 0, i32 0), i1 %fieldload2) + %newline = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @newline, i32 0, i32 0)) + ret void +} diff --git a/package-lock.json b/package-lock.json index 3dd32b8..0791c63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,24 @@ { - "name": "gom", - "version": "0.0.1", + "name": "gom-lang", + "version": "0.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "gom", - "version": "0.0.1", + "name": "gom-lang", + "version": "0.0.2", "license": "ISC", "dependencies": { + "chalk": "^5.4.1", "commander": "^13.1.0", "cors": "^2.8.5", "llvm-bindings": "github:TypeFox/llvm-bindings", + "ts-pattern": "^5.6.2", "typescript": "^5.4.5" }, + "bin": { + "gomc": "run.sh" + }, "devDependencies": { "@changesets/cli": "^2.28.1", "@hono/node-server": "^1.13.8", @@ -1793,6 +1798,18 @@ "node": "*" } }, + "node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -4506,6 +4523,12 @@ } } }, + "node_modules/ts-pattern": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.6.2.tgz", + "integrity": "sha512-d4IxJUXROL5NCa3amvMg6VQW2HVtZYmUTPfvVtO7zJWGYLJ+mry9v2OmYm+z67aniQoQ8/yFNadiEwtNS9qQiw==", + "license": "MIT" + }, "node_modules/tsx": { "version": "4.19.2", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", @@ -6580,6 +6603,11 @@ "traverse": ">=0.3.0 <0.4" } }, + "chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==" + }, "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -8545,6 +8573,11 @@ "yn": "3.1.1" } }, + "ts-pattern": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.6.2.tgz", + "integrity": "sha512-d4IxJUXROL5NCa3amvMg6VQW2HVtZYmUTPfvVtO7zJWGYLJ+mry9v2OmYm+z67aniQoQ8/yFNadiEwtNS9qQiw==" + }, "tsx": { "version": "4.19.2", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", diff --git a/package.json b/package.json index 3eec672..15fc505 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "gomc": "run.sh" }, "scripts": { - "build": "tsc", "test": "vitest run", "compile": "tsx run.ts", "changeset": "changeset", @@ -17,9 +16,11 @@ "author": "", "license": "ISC", "dependencies": { + "chalk": "^5.4.1", "commander": "^13.1.0", "cors": "^2.8.5", "llvm-bindings": "github:TypeFox/llvm-bindings", + "ts-pattern": "^5.6.2", "typescript": "^5.4.5" }, "devDependencies": { diff --git a/run.ts b/run.ts index 0fbd5aa..973731c 100755 --- a/run.ts +++ b/run.ts @@ -1,7 +1,27 @@ #!/usr/bin/env tsx import { runCompile } from "./src/index"; +import { execSync } from "child_process"; const filePath = process.argv[2]; const target = (process.argv[3] || "c") as "c" | "llvm"; -(async () => await runCompile(filePath, target))(); +runCompile(filePath, target) + .then(() => { + if (target === "llvm") { + // compile using clang + execSync( + `clang -o ${filePath.replace(".gom", "")} ${filePath.replace( + ".gom", + ".ll" + )}`, + { stdio: "inherit" } + ); + console.log( + `✅ Executable generated at: ${filePath.replace(".gom", "")}` + ); + } + }) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/src/codegen/c.ts b/src/codegen/c.ts index c17c0ee..37f5e39 100644 --- a/src/codegen/c.ts +++ b/src/codegen/c.ts @@ -111,26 +111,25 @@ export class CodeGenerator extends BaseCodeGenerator { } visitFunctionDefinition(node: NodeFunctionDefinition): void { - this.symbolTableReader.enterScope(node.name.value); - this.irScopeManager.enterScope(node.name.value); - const returnType = this.mapGomTypeToC( - node.gomType.returnType as GomPrimitiveTypeOrAlias - ); - const argsType = node.gomType.args.map((arg) => - this.mapGomTypeToC(arg as GomPrimitiveTypeOrAlias) - ); - - this.writeLine( - `${returnType} ${node.name.value}(${argsType - .map((type, i) => `${type} ${node.args[i].name.token.value}`) - .join(", ")}) {` - ); - this.indent++; - node.body.forEach((stmt) => this.visit(stmt)); - this.indent--; - this.writeLine("}"); - this.symbolTableReader.exitScope(); - this.irScopeManager.exitScope(); + // this.symbolTableReader.enterScope(node.name.value); + // this.irScopeManager.enterScope(node.name.value); + // const returnType = this.mapGomTypeToC( + // node.gomType.returnType as GomPrimitiveTypeOrAlias + // ); + // const argsType = node.gomType.args.map((arg) => + // this.mapGomTypeToC(arg as GomPrimitiveTypeOrAlias) + // ); + // this.writeLine( + // `${returnType} ${node.name.value}(${argsType + // .map((type, i) => `${type} ${node.args[i].name.token.value}`) + // .join(", ")}) {` + // ); + // this.indent++; + // node.body.forEach((stmt) => this.visit(stmt)); + // this.indent--; + // this.writeLine("}"); + // this.symbolTableReader.exitScope(); + // this.irScopeManager.exitScope(); } visitLetStatement(node: NodeLetStatement): void { diff --git a/src/codegen/llvm.ts b/src/codegen/llvm.ts index 1250d9c..afb55db 100644 --- a/src/codegen/llvm.ts +++ b/src/codegen/llvm.ts @@ -18,14 +18,17 @@ import { NodeReturnStatement, NodeStructInit, NodeTerm, + NodeTupleLiteral, NodeTypeDefinition, } from "../parser/rd/nodes"; import { ScopeManager } from "../semantics/scope"; import { + GomCompositeType, GomFunctionType, GomPrimitiveTypeOrAlias, GomPrimitiveTypeOrAliasValue, GomStructType, + GomTupleType, GomType, GomTypeKind, } from "../semantics/type"; @@ -33,6 +36,8 @@ import { GomToken } from "../lexer/tokens"; import { GomErrorManager } from "../util/error"; import { Node } from "../parser/rd/tree"; import { BaseCodeGenerator } from "./common"; +import { match } from "ts-pattern"; +import { instanceOf } from "ts-pattern/dist/patterns"; export enum LLVMType { I8 = "int", @@ -40,6 +45,11 @@ export enum LLVMType { VOID = "void", } +type ExpressionContext = Partial<{ + declLhs: NodeTerm; + pointer: llvm.Value; +}>; + /** * Generates LLVM IR - todo to use llvm bindings */ @@ -104,11 +114,22 @@ export class CodeGenerator extends BaseCodeGenerator { return llvm.Type.getFloatTy(this.context); case "void": return llvm.Type.getVoidTy(this.context); + case "bool": + return llvm.Type.getInt1Ty(this.context); + case "str": + return llvm.Type.getInt8PtrTy(this.context); default: throw new Error("Unknown type: " + type.toStr()); } } + private mapGomTupleTypeToLLVMType(type: GomTupleType) { + const types = Array.from(type.fields).map((t) => + this.mapGomTypeToLLVMType(t[1]) + ); + return llvm.StructType.get(this.context, types); + } + private mapGomStructTypeToLLVMType(type: GomStructType) { const structType = this.structTypes[type.name]; if (!structType) { @@ -118,11 +139,13 @@ export class CodeGenerator extends BaseCodeGenerator { return structType; } - private mapGomTypeToLLVMType(type: GomType) { + private mapGomTypeToLLVMType(type: GomType): llvm.Type { if (type instanceof GomPrimitiveTypeOrAlias) { return this.mapGomPrimitiveTypeToLLVMType(type); } else if (type instanceof GomStructType) { return this.mapGomStructTypeToLLVMType(type); + } else if (type instanceof GomTupleType) { + return this.mapGomTupleTypeToLLVMType(type); } throw new Error("Unknown type: " + type.toStr()); @@ -186,9 +209,12 @@ export class CodeGenerator extends BaseCodeGenerator { } override generate(): string { - console.log("Generating code..."); this.symbolTableReader.enterScope("global"); this.writeGlobalVariables(); + // Somehow this works now + // Global functions have to be written here as writing format + // strings in the global scope causes an error + this.writeGlobalFunctions(); this.visit(this.ast); this.symbolTableReader.exitScope(); return this.module.print(); @@ -220,14 +246,23 @@ export class CodeGenerator extends BaseCodeGenerator { visitFunctionDefinition(node: NodeFunctionDefinition): void { this.symbolTableReader.enterScope(node.name.value); this.irScopeManager.enterScope(node.name.value); - const returnType = this.mapGomTypeToLLVMType( - (node.resultantType as GomFunctionType).returnType - ); + const fnType = node.resultantType as GomFunctionType; + const returnTypeGom = fnType.returnType; + const returnType = this.mapGomTypeToLLVMType(returnTypeGom); const argsType = (node.resultantType as GomFunctionType).args.map((arg) => this.mapGomTypeToLLVMType(arg as GomPrimitiveTypeOrAlias) ); - const funcType = llvm.FunctionType.get(returnType, argsType, false); + if (fnType.usesSret()) { + const sretArgType = llvm.PointerType.getUnqual(returnType); + argsType.unshift(sretArgType); + } + + const funcType = llvm.FunctionType.get( + fnType.usesSret() ? llvm.Type.getVoidTy(this.context) : returnType, + argsType, + false + ); const fn = llvm.Function.Create( funcType, llvm.Function.LinkageTypes.ExternalLinkage, @@ -235,14 +270,20 @@ export class CodeGenerator extends BaseCodeGenerator { this.module ); + if (fnType.usesSret()) { + fn.addParamAttr(0, llvm.Attribute.get(this.context, "sret")); + fn.addParamAttr(0, llvm.Attribute.get(this.context, "noalias")); + } + const entry = llvm.BasicBlock.Create(this.context, "entry", fn); this.builder.SetInsertPoint(entry); node.args.forEach((arg, i) => { - const alloca = this.builder.CreateAlloca(argsType[i], null); + const index = fnType.usesSret() ? i + 1 : i; + const alloca = this.builder.CreateAlloca(argsType[index], null); const argId = this.symbolTableReader.getIdentifier(arg.name.token.value); - this.builder.CreateStore(fn.getArg(i), alloca); + this.builder.CreateStore(fn.getArg(index), alloca); if (argId) { argId.allocaInst = alloca; @@ -269,10 +310,6 @@ export class CodeGenerator extends BaseCodeGenerator { this.module ); - // Global functions have to be written here as writing format - // strings in the global scope causes an error - this.writeGlobalFunctions(); - const entry = llvm.BasicBlock.Create(this.context, "entry", mainFunction); this.builder.SetInsertPoint(entry); @@ -307,7 +344,7 @@ export class CodeGenerator extends BaseCodeGenerator { continue; } - this.builder.SetInsertPoint(this.currentFunctionEntry); + // this.builder.SetInsertPoint(this.currentFunctionEntry); const type = this.mapGomTypeToLLVMType(decl.lhs.resultantType); const alloca = this.builder.CreateAlloca( @@ -321,7 +358,10 @@ export class CodeGenerator extends BaseCodeGenerator { id.allocaInst = alloca; } - const rhsValue = this.visitExpression(decl.rhs, decl.lhs); + const rhsValue = this.visitExpression(decl.rhs, { + declLhs: decl.lhs, + pointer: alloca, + }); if (!type.isStructTy()) { this.builder.CreateStore(rhsValue, alloca); @@ -342,8 +382,17 @@ export class CodeGenerator extends BaseCodeGenerator { } if (node.expr) { - const exprValue = this.visitExpression(node.expr); - this.builder.CreateRet(exprValue); + if (node.expr.resultantType instanceof GomPrimitiveTypeOrAlias) { + const exprValue = this.visitExpression(node.expr); + this.builder.CreateRet(exprValue); + } else { + const fn = this.currentFunction; + const sretPointer = fn.getArg(0); + this.visitExpression(node.expr, { + pointer: sretPointer, + }); + this.builder.CreateRetVoid(); + } } else { this.builder.CreateRetVoid(); } @@ -442,9 +491,13 @@ export class CodeGenerator extends BaseCodeGenerator { this.builder.CreateCondBr(condValue, bodyBB, afterBB); this.builder.SetInsertPoint(bodyBB); + this.symbolTableReader.enterScope("for"); + this.irScopeManager.enterScope("for"); node.body.forEach((stmt) => this.visit(stmt)); - + this.symbolTableReader.exitScope(); + this.irScopeManager.exitScope(); this.builder.CreateBr(updateBB); + this.builder.SetInsertPoint(updateBB); this.visitExpression(node.updateExpr); this.builder.CreateBr(loopBB); @@ -465,7 +518,11 @@ export class CodeGenerator extends BaseCodeGenerator { this.builder.CreateBr(loopBB); this.builder.SetInsertPoint(loopBB); + this.symbolTableReader.enterScope("for"); + this.irScopeManager.enterScope("for"); node.body.forEach((stmt) => this.visit(stmt)); + this.symbolTableReader.exitScope(); + this.irScopeManager.exitScope(); this.builder.CreateBr(loopBB); // later for break; @@ -473,19 +530,21 @@ export class CodeGenerator extends BaseCodeGenerator { } } - visitExpression(expr: NodeExpr, declLhs?: NodeTerm): llvm.Value { + visitExpression(expr: NodeExpr, context?: ExpressionContext): llvm.Value { if (expr instanceof NodeAccess) { return this.visitAccess(expr); } else if (expr instanceof NodeBinaryOp) { - return this.visitBinaryOp(expr); + return this.visitBinaryOp(expr, context); } else if (expr instanceof NodeCall) { - return this.visitCall(expr); + return this.visitCall(expr, context); } else if (expr instanceof NodeTerm) { - return this.visitTerm(expr); + return this.visitTerm(expr, context); } else if (expr instanceof NodeAssignment) { return this.visitAssignment(expr); } else if (expr instanceof NodeStructInit) { - return this.visitStructInit(expr, declLhs); + return this.visitStructInit(expr, context); + } else if (expr instanceof NodeTupleLiteral) { + return this.visitTupleLiteral(expr, context); } else if (expr instanceof NodeExprBracketed) { return this.visitExpression(expr.expr); } @@ -507,14 +566,19 @@ export class CodeGenerator extends BaseCodeGenerator { return rhsValue; } - visitStructInit(node: NodeStructInit, declLhs?: NodeTerm): llvm.Value { - if (!declLhs) { + visitStructInit( + node: NodeStructInit, + context?: ExpressionContext + ): llvm.Value { + if (!context?.declLhs) { this.errorManager.throwCodegenError({ loc: node.loc, message: "Struct init without declaration", }); } - const structId = this.symbolTableReader.getIdentifier(declLhs.token.value); + const structId = this.symbolTableReader.getIdentifier( + context.declLhs.token.value + ); if (!structId) { this.errorManager.throwCodegenError({ loc: node.loc, @@ -544,12 +608,35 @@ export class CodeGenerator extends BaseCodeGenerator { return structAlloca; } + visitTupleLiteral( + node: NodeTupleLiteral, + context?: ExpressionContext + ): llvm.Value { + const type = this.mapGomTypeToLLVMType(node.resultantType as GomTupleType); + const tuple = + context?.pointer ?? this.builder.CreateAlloca(type, null, "tuple"); + node.elements.forEach((element, i) => { + const fieldVal = this.visitExpression(element); + const fieldPtr = this.builder.CreateGEP( + type, + tuple, + [this.builder.getInt32(0), this.builder.getInt32(i)], + "fieldptr" + ); + this.builder.CreateStore(fieldVal, fieldPtr); + }); + return tuple; + } + visitAccess(node: NodeAccess): llvm.Value { const idName = node.lhs.token.value; if (idName === "io" && node.rhs instanceof NodeCall) { const fn = this.module.getFunction("printf"); if (!fn) { - throw new Error("printf function not added globally"); + this.errorManager.throwCodegenError({ + message: "printf function not added globally", + loc: node.loc, + }); } const args = node.rhs.args.map((arg) => this.visitExpression(arg)); @@ -582,10 +669,11 @@ export class CodeGenerator extends BaseCodeGenerator { this.builder.CreateCall(fn, [newline], "newline"); return this.builder.getInt32(0); } else if ( - node.lhs.resultantType instanceof GomStructType && + (node.lhs.resultantType instanceof GomStructType || + node.lhs.resultantType instanceof GomTupleType) && node.rhs instanceof NodeTerm ) { - const type = node.lhs.resultantType as GomStructType; + const type = node.lhs.resultantType; const structType = this.mapGomTypeToLLVMType(node.lhs.resultantType); const struct = this.symbolTableReader.getIdentifier(idName); if (!struct) { @@ -602,9 +690,12 @@ export class CodeGenerator extends BaseCodeGenerator { }); } - const index = this.builder.getInt32( - Array.from(type.fields.keys()).indexOf(node.rhs.token.value) - ); + const index = + type instanceof GomStructType + ? this.builder.getInt32( + Array.from(type.fields.keys()).indexOf(node.rhs.token.value) + ) + : this.builder.getInt32(Number(node.rhs.token.value)); const ptr = this.builder.CreateGEP( structType, @@ -622,79 +713,163 @@ export class CodeGenerator extends BaseCodeGenerator { return this.builder.getInt32(0); } - visitBinaryOp(node: NodeBinaryOp): llvm.Value { + visitBinaryOp(node: NodeBinaryOp, context?: ExpressionContext): llvm.Value { + const pointer = context?.pointer; const op = node.op; const lhs = this.visitExpression(node.lhs); const rhs = this.visitExpression(node.rhs); + let irOperation: llvm.Value | null = null; switch (op.type) { case GomToken.PLUS: - return this.builder.CreateAdd(lhs, rhs, "addtmp"); + irOperation = this.builder.CreateAdd(lhs, rhs, "addtmp"); + break; case GomToken.MINUS: - return this.builder.CreateSub(lhs, rhs, "subtmp"); + irOperation = this.builder.CreateSub(lhs, rhs, "subtmp"); + break; case GomToken.MUL: - return this.builder.CreateMul(lhs, rhs, "multmp"); + irOperation = this.builder.CreateMul(lhs, rhs, "multmp"); + break; case GomToken.DIV: - return this.builder.CreateSDiv(lhs, rhs, "divtmp"); + irOperation = this.builder.CreateSDiv(lhs, rhs, "divtmp"); + break; case GomToken.EQEQ: - return this.builder.CreateICmpEQ(lhs, rhs, "eqtmp"); + irOperation = this.builder.CreateICmpEQ(lhs, rhs, "eqtmp"); + break; case GomToken.LT: - return this.builder.CreateICmpSLT(lhs, rhs, "lttmp"); + irOperation = this.builder.CreateICmpSLT(lhs, rhs, "lttmp"); + break; case GomToken.GT: - return this.builder.CreateICmpSGT(lhs, rhs, "gttmp"); + irOperation = this.builder.CreateICmpSGT(lhs, rhs, "gttmp"); + break; case GomToken.LTE: - return this.builder.CreateICmpSLE(lhs, rhs, "ltetmp"); + irOperation = this.builder.CreateICmpSLE(lhs, rhs, "ltetmp"); + break; case GomToken.GTE: - return this.builder.CreateICmpSGE(lhs, rhs, "gtetmp"); + irOperation = this.builder.CreateICmpSGE(lhs, rhs, "gtetmp"); + break; default: throw new Error("Unknown operator: " + op.type); } + + if (pointer) { + return this.builder.CreateStore(irOperation, pointer); + } else { + return irOperation; + } } - visitCall(node: NodeCall): llvm.Value { + visitCall(node: NodeCall, context?: ExpressionContext): llvm.Value { const fn = this.module.getFunction(node.id.token!.value); - if (!fn) { + const gomFn = this.symbolTableReader.getIdentifier(node.id.token!.value); + if (!fn || !gomFn) { throw new Error("Unknown function: " + node.id.token!.value); } - const args = node.args.map((arg) => this.visitExpression(arg)); - return this.builder.CreateCall(fn, args, "calltmp"); + /** + * Check if the function uses sret (for any function returning a non-primitive type) + */ + if (gomFn.type instanceof GomFunctionType && gomFn.type.usesSret()) { + const sretPointer = + context?.pointer ?? + this.builder.CreateAlloca( + this.mapGomTypeToLLVMType(gomFn.type.returnType), + null, + "sret" + ); + const args = node.args.map((arg) => this.visitExpression(arg)); + this.builder.CreateCall(fn, [sretPointer, ...args]); + return sretPointer; + } else { + const args = node.args.map((arg) => + this.visitExpression(arg, { pointer: context?.pointer }) + ); + return this.builder.CreateCall(fn, args, "calltmp"); + } } - visitTerm(node: NodeTerm): llvm.Value { + visitTerm(node: NodeTerm, context?: ExpressionContext): llvm.Value { + const pointer = context?.pointer; const type = node.token.type; - if (type === GomToken.NUMLITERAL) { - return this.builder.getInt32(parseInt(node.token.value)); - } else if (type === GomToken.STRLITERAL) { - return this.getStringLiteralPointer(node); - } else if (type === GomToken.IDENTIFIER) { - const id = this.symbolTableReader.getIdentifier(node.token.value); - if (!id) { - // throw new Error("Unknown identifier: " + node.token.value); - this.errorManager.throwCodegenError({ - loc: node.loc, - message: "Unknown identifier: " + node.token.value, - }); - } - if (!id.allocaInst) { - // throw new Error("Identifier not allocated: " + node.token.value); - this.errorManager.throwCodegenError({ - loc: node.loc, - message: "Identifier not allocated: " + node.token.value, - }); - } + if (pointer) { + if (type === GomToken.NUMLITERAL) { + const value = parseInt(node.token.value); + const intValue = this.builder.getInt32(value); + this.builder.CreateStore(intValue, pointer); + return intValue; + } else if (type === GomToken.STRLITERAL) { + const strPtr = this.getStringLiteralPointer(node); + this.builder.CreateStore(strPtr, pointer); + return strPtr; + } else if (type === GomToken.IDENTIFIER) { + const id = this.symbolTableReader.getIdentifier(node.token.value); + if (!id) { + // throw new Error("Unknown identifier: " + node.token.value); + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Unknown identifier: " + node.token.value, + }); + } + if (!id.allocaInst) { + // throw new Error("Identifier not allocated: " + node.token.value); + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Identifier not allocated: " + node.token.value, + }); + } - return this.builder.CreateLoad( - this.mapGomTypeToLLVMType(id.type as GomPrimitiveTypeOrAlias), - id.allocaInst, - id.name + ".load" - ); - } else if (type === GomToken.TRUE) { - return this.builder.getInt32(1); - } else if (type === GomToken.FALSE) { - return this.builder.getInt32(0); + const loadInst = this.builder.CreateLoad( + this.mapGomTypeToLLVMType(id.type as GomPrimitiveTypeOrAlias), + id.allocaInst, + id.name + ".load" + ); + this.builder.CreateStore(loadInst, pointer); + return loadInst; + } else if (type === GomToken.TRUE) { + const trueValue = this.builder.getInt1(true); + this.builder.CreateStore(trueValue, pointer); + return trueValue; + } else if (type === GomToken.FALSE) { + const falseValue = this.builder.getInt1(false); + this.builder.CreateStore(falseValue, pointer); + return falseValue; + } else { + throw new Error("Unknown term type: " + type); + } } else { - throw new Error("Unknown term type: " + type); + if (type === GomToken.NUMLITERAL) { + return this.builder.getInt32(parseInt(node.token.value)); + } else if (type === GomToken.STRLITERAL) { + return this.getStringLiteralPointer(node); + } else if (type === GomToken.IDENTIFIER) { + const id = this.symbolTableReader.getIdentifier(node.token.value); + if (!id) { + // throw new Error("Unknown identifier: " + node.token.value); + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Unknown identifier: " + node.token.value, + }); + } + if (!id.allocaInst) { + // throw new Error("Identifier not allocated: " + node.token.value); + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Identifier not allocated: " + node.token.value, + }); + } + + return this.builder.CreateLoad( + this.mapGomTypeToLLVMType(id.type as GomPrimitiveTypeOrAlias), + id.allocaInst, + id.name + ".load" + ); + } else if (type === GomToken.TRUE) { + return this.builder.getInt1(true); + } else if (type === GomToken.FALSE) { + return this.builder.getInt1(false); + } else { + throw new Error("Unknown term type: " + type); + } } } } diff --git a/src/index.ts b/src/index.ts index 7070c98..bd13758 100644 --- a/src/index.ts +++ b/src/index.ts @@ -116,10 +116,6 @@ export const compileAndReturn = async ( }; export const runCompile = async (srcPath: string, target: "llvm" | "c") => { - try { - const src = await readFile(srcPath, "utf-8"); - await compile(srcPath, src, target); - } catch (e) { - console.error(e); - } + const src = await readFile(srcPath, "utf-8"); + await compile(srcPath, src, target); }; diff --git a/src/parser/rd/index.ts b/src/parser/rd/index.ts index 3e536aa..192d93b 100644 --- a/src/parser/rd/index.ts +++ b/src/parser/rd/index.ts @@ -1,7 +1,7 @@ import { Lexer, Token } from "../../lexer"; import { GomToken } from "../../lexer/tokens"; import { GomErrorManager } from "../../util/error"; -import { GomModule } from "./modules"; +import chalk from "chalk"; import { NodeAccess, NodeArgumentItem, @@ -15,18 +15,23 @@ import { NodeForStatement, NodeFunctionDefinition, NodeFunctionReturnType, - NodeGomTypeIdOrArray, + NodeGomType, + NodeGomTypeComposite, + NodeGomTypeId, NodeGomTypeStruct, NodeGomTypeStructField, + NodeGomTypeTuple, NodeIfStatement, NodeImportDeclaration, NodeLetStatement, + NodeListLiteral, NodeMainFunction, NodeProgram, NodeReturnStatement, NodeStatement, NodeStructInit, NodeTerm, + NodeTupleLiteral, NodeTypeDefinition, } from "./nodes"; import { NodeType } from "./tree"; @@ -57,7 +62,9 @@ export class RecursiveDescentParser { return matched; } else { this.errorManager.throwSyntaxError({ - message: `Unexpected token: ${this.token.value}`, + message: `Unexpected token: ${chalk.red( + this.token.value + )}, expected ${chalk.green(type)}`, loc: this.token.start, }); } @@ -196,19 +203,68 @@ export class RecursiveDescentParser { }); } - parseGomType(typeName: NodeTerm) { - if (this.peek(GomToken.LBRACE)) { - return this.parseStructType(typeName); - } else if ( - this.peek(GomToken.IDENTIFIER) || - this.peek(GomToken.BUILT_IN_TYPE) - ) { - return this.parseTypeIdOrArray(); + parseGomType(typeName?: NodeTerm): NodeGomType { + if (this.peek(GomToken.FN)) { + // Function type + } else if (this.peek(GomToken.LBRACE)) { + this.buffer.push(this.lexer.nextToken(), this.lexer.nextToken()); + if ( + this.buffer[this.buffer.length - 1].type === GomToken.COLON && + typeName + ) { + return this.parseStructType(typeName); + } else { + return this.parseTupleType(); + } + } else if (this.peek(GomToken.IDENTIFIER)) { + this.buffer.push(this.lexer.nextToken()); + if (this.buffer[this.buffer.length - 1].type === GomToken.LT) { + // composite type + return this.parseCompositeType(); + } else { + return this.parseTypeId(); + } + } else if (this.peek(GomToken.BUILT_IN_TYPE)) { + return this.parseTypeId(); } throw new Error(`Unexpected token: ${this.token.value}`); } + parseCompositeType(): NodeGomTypeComposite { + const baseType = this.parseTerm(); + this.match(GomToken.LT); + const fields = this.parseOneOrMore(() => { + const type = this.parseGomType(baseType); + if (!this.peek(GomToken.GT)) { + this.match(GomToken.COMMA); + } + return type; + }); + this.match(GomToken.GT); + + return new NodeGomTypeComposite({ + id: baseType, + fields, + loc: baseType.token.start, + }); + } + + parseTupleType(): NodeGomTypeTuple { + const loc = this.token.start; + this.match(GomToken.LBRACE); + const fields = this.parseZeroOrMore(() => { + const type = this.parseGomType(); + if (!this.peek(GomToken.RBRACE)) { + this.match(GomToken.COMMA); + } + return type; + }); + this.match(GomToken.RBRACE); + + return new NodeGomTypeTuple({ fields, loc }); + } + parseStructType(typeName: NodeTerm) { const loc = this.token.start; this.match(GomToken.LBRACE); @@ -222,7 +278,7 @@ export class RecursiveDescentParser { const loc = this.token.start; const name = this.match(GomToken.IDENTIFIER); this.match(GomToken.COLON); - const type = this.parseTypeIdOrArray(); + const type = this.parseTypeId(); if (!this.peek(GomToken.RBRACE)) { this.match(GomToken.COMMA); } @@ -230,22 +286,12 @@ export class RecursiveDescentParser { return new NodeGomTypeStructField({ name, fieldType: type, loc }); } - parseTypeIdOrArray() { - const baseType = this.parseTerm() as NodeTerm; - - if (this.accept(GomToken.LBRACKET)) { - const size = this.parseTerm(); - this.match(GomToken.RBRACKET); - return new NodeGomTypeIdOrArray({ - id: baseType, - arrSize: size, - loc: baseType.token.start, - }); - } + parseTypeId() { + const type = this.parseTerm() as NodeTerm; - return new NodeGomTypeIdOrArray({ - id: baseType, - loc: baseType.token.start, + return new NodeGomTypeId({ + id: type, + loc: type.token.start, }); } @@ -287,8 +333,7 @@ export class RecursiveDescentParser { parseFunctionReturnType() { const loc = this.token.start; this.match(GomToken.COLON); - const type = this.match(GomToken.BUILT_IN_TYPE); // can be custom type - + const type = this.parseGomType(); return new NodeFunctionReturnType({ returnType: type, loc }); } @@ -414,7 +459,8 @@ export class RecursiveDescentParser { * 3. Quot * 4. Expo * 5. Call - * 6. Term + * 6. Tuple/list literal + * 7. Term */ parseExpression(): NodeExpr { @@ -424,6 +470,10 @@ export class RecursiveDescentParser { const expr = this.parseExpression(); this.match(GomToken.RPAREN); return new NodeExprBracketed({ expr, loc }); + } else if (this.peek(GomToken.LBRACE)) { + return this.parseTupleLiteral(); + } else if (this.peek(GomToken.LBRACKET)) { + return this.parseListLiteral(); } else if (this.peek(GomToken.IDENTIFIER)) { this.buffer.push(this.lexer.nextToken()); if (this.buffer[1].type === GomToken.EQ) { @@ -436,6 +486,36 @@ export class RecursiveDescentParser { } } + parseTupleLiteral(): NodeTupleLiteral { + const loc = this.token.start; + this.match(GomToken.LBRACE); + const elements = this.parseZeroOrMore(() => { + const expr = this.parseExpression(); + if (!this.peek(GomToken.RBRACE)) { + this.match(GomToken.COMMA); + } + return expr; + }); + this.match(GomToken.RBRACE); + + return new NodeTupleLiteral({ elements, loc }); + } + + parseListLiteral(): NodeListLiteral { + const loc = this.token.start; + this.match(GomToken.LBRACKET); + const elements = this.parseZeroOrMore(() => { + const expr = this.parseExpression(); + if (!this.peek(GomToken.RBRACKET)) { + this.match(GomToken.COMMA); + } + return expr; + }); + this.match(GomToken.RBRACKET); + + return new NodeListLiteral({ elements, loc }); + } + parseAssignment(): NodeAssignment { const loc = this.token.start; const lhs = this.parseTerm() as NodeTerm; diff --git a/src/parser/rd/nodes/index.ts b/src/parser/rd/nodes/index.ts index 65559f3..8eef51a 100644 --- a/src/parser/rd/nodes/index.ts +++ b/src/parser/rd/nodes/index.ts @@ -2,9 +2,12 @@ import { Token } from "../../../lexer"; import { GomToken } from "../../../lexer/tokens"; import { GomArrayType, + GomCompositeType, + GomCompositeTypeKind, GomFunctionType, GomPrimitiveTypeOrAlias, GomStructType, + GomTupleType, GomType, } from "../../../semantics/type"; import { AbstractNode, Node, NodeType } from "../tree"; @@ -334,10 +337,10 @@ export class NodeArgumentItem extends AbstractNode { export class NodeFunctionReturnType extends AbstractNode { type: NodeType; - returnType: Token; + returnType: NodeGomType; children: Node[]; - constructor({ returnType, loc }: { returnType: Token; loc: number }) { + constructor({ returnType, loc }: { returnType: NodeGomType; loc: number }) { super(); this.type = NodeType.FUNCTION_RETURN_TYPE; this.loc = loc; @@ -346,35 +349,43 @@ export class NodeFunctionReturnType extends AbstractNode { } } -export type NodeGomType = NodeGomTypeIdOrArray | NodeGomTypeStruct; -export class NodeGomTypeIdOrArray extends AbstractNode { +export type NodeGomType = + | NodeGomTypeId + | NodeGomTypeStruct + | NodeGomTypeComposite + | NodeGomTypeTuple; +export class NodeGomTypeId extends AbstractNode { type: NodeType; id: NodeTerm; - arrSize?: NodeTerm; gomType: GomType; children: Node[]; - constructor({ - id, - arrSize, - loc, - }: { - id: NodeTerm; - arrSize?: NodeTerm; - loc: number; - }) { + constructor({ id, loc }: { id: NodeTerm; arrSize?: NodeTerm; loc: number }) { super(); - this.type = NodeType.GOM_TYPE_ID_OR_ARRAY; + this.type = NodeType.GOM_TYPE_ID; this.loc = loc; this.id = id; - this.arrSize = arrSize; - this.gomType = arrSize - ? new GomArrayType(id.resultantType, Number(arrSize.token.value)) - : id.resultantType; + this.gomType = id.resultantType; this.children = []; } } +export class NodeGomTypeTuple extends AbstractNode { + type: NodeType; + fields: NodeGomType[]; + gomType: GomType; + children: Node[]; + + constructor({ fields, loc }: { fields: NodeGomType[]; loc: number }) { + super(); + this.type = NodeType.GOM_TYPE_TUPLE; + this.loc = loc; + this.fields = fields; + this.gomType = new GomTupleType(fields.map((field) => field.gomType)); + this.children = formChildrenArray(fields); + } +} + export class NodeGomTypeStruct extends AbstractNode { type: NodeType; fields: NodeGomTypeStructField[]; @@ -404,6 +415,44 @@ export class NodeGomTypeStruct extends AbstractNode { } } +export class NodeGomTypeComposite extends AbstractNode { + type: NodeType; + id: NodeTerm; + fields: NodeGomType[]; + gomType: GomType; + children: Node[]; + + constructor({ + id, + fields, + loc, + }: { + id: NodeTerm; + fields: NodeGomType[]; + loc: number; + }) { + super(); + this.type = NodeType.GOM_TYPE_COMPOSITE; + this.loc = loc; + this.id = id; + this.fields = fields; + this.gomType = new GomCompositeType( + NodeGomTypeComposite.getGomCompositeTypeKind(id), + fields.map((field) => field.gomType) + ); + this.children = []; + } + + static getGomCompositeTypeKind(id: NodeTerm): GomCompositeTypeKind { + switch (id.token.value) { + case "List": + return GomCompositeTypeKind.List; + default: + return GomCompositeTypeKind._Custom; + } + } +} + export class NodeGomTypeStructField extends AbstractNode { type: NodeType; name: Token; @@ -434,8 +483,11 @@ export type NodeExprBasic = | NodeAssignment | NodeStructInit | NodeAccess + | NodeIndexedAccess | NodeCall | NodeBinaryOp + | NodeTupleLiteral + | NodeListLiteral | NodeTerm; export class NodeAssignment extends AbstractNode { @@ -593,6 +645,72 @@ export class NodeExprBracketed extends AbstractNode { } } +export class NodeIndexedAccess extends AbstractNode { + type: NodeType; + lhs: NodeExpr; + index: NodeExpr; + children: Node[]; + resultantType: GomType; + + constructor({ + lhs, + index, + loc, + }: { + lhs: NodeExpr; + index: NodeExpr; + loc: number; + }) { + super(); + this.type = NodeType.INDEXED_ACCESS; + this.loc = loc; + this.lhs = lhs; + this.index = index; + this.children = formChildrenArray(lhs, index); + this.resultantType = new GomPrimitiveTypeOrAlias("void"); + } +} + +export class NodeTupleLiteral extends AbstractNode { + type: NodeType; + elements: NodeExpr[]; + children: Node[]; + gomType: GomType; + resultantType: GomType; + + constructor({ elements, loc }: { elements: NodeExpr[]; loc: number }) { + super(); + this.type = NodeType.TUPLE_LITERAL; + this.loc = loc; + this.elements = elements; + this.children = elements; + this.gomType = new GomTupleType( + elements.map((elements) => elements.resultantType) + ); + this.resultantType = this.gomType; + } +} + +export class NodeListLiteral extends AbstractNode { + type: NodeType; + elements: NodeExpr[]; + children: Node[]; + gomType: GomType; + resultantType: GomType; + + constructor({ elements, loc }: { elements: NodeExpr[]; loc: number }) { + super(); + this.type = NodeType.LIST_LITERAL; + this.loc = loc; + this.elements = elements; + this.children = elements; + this.gomType = new GomCompositeType(GomCompositeTypeKind.List, [ + elements[0].resultantType, + ]); + this.resultantType = this.gomType; + } +} + export class NodeTerm extends AbstractNode { type: NodeType; token: Token; diff --git a/src/parser/rd/tree.ts b/src/parser/rd/tree.ts index 42ce60c..a580947 100644 --- a/src/parser/rd/tree.ts +++ b/src/parser/rd/tree.ts @@ -40,9 +40,11 @@ export enum NodeType { LET_STATEMENT = "LET_STATEMENT", CONST_STATEMENT = "CONST_STATEMENT", EXPRESSION_STATEMENT = "EXPRESSION_STATEMENT", - GOM_TYPE_ID_OR_ARRAY = "GOM_TYPE_ID_OR_ARRAY", + GOM_TYPE_ID = "GOM_TYPE_ID", + GOM_TYPE_TUPLE = "GOM_TYPE_TUPLE", GOM_TYPE_STRUCT = "GOM_TYPE_STRUCT", GOM_TYPE_STRUCT_FIELD = "GOM_TYPE_STRUCT_FIELD", + GOM_TYPE_COMPOSITE = "GOM_TYPE_COMPOSITE", ARGUMENT_ITEM = "ARGUMENT_ITEM", FUNCTION_RETURN_TYPE = "FUNCTION_RETURN_TYPE", EXPR_BASIC = "EXPR_BASIC", @@ -55,6 +57,9 @@ export enum NodeType { SUM = "SUM", QUOT = "QUOT", EXPO = "EXPO", + TUPLE_LITERAL = "TUPLE_LITERAL", + INDEXED_ACCESS = "INDEXED_ACCESS", + LIST_LITERAL = "LIST_LITERAL", TERM = "TERM", TERMINAL = "TERMINAL", } diff --git a/src/parser/rd/visitor.ts b/src/parser/rd/visitor.ts index 249a538..6c194a9 100644 --- a/src/parser/rd/visitor.ts +++ b/src/parser/rd/visitor.ts @@ -12,12 +12,15 @@ import { NodeGomTypeStructField, NodeIfStatement, NodeImportDeclaration, + NodeIndexedAccess, NodeLetStatement, + NodeListLiteral, NodeMainFunction, NodeProgram, NodeReturnStatement, NodeStructInit, NodeTerm, + NodeTupleLiteral, NodeTypeDefinition, } from "./nodes"; import { Node, NodeType } from "./tree"; @@ -118,6 +121,15 @@ export class SimpleVisitor implements Visitor { case NodeType.EXPRESSION_STATEMENT: this.visitExpressionStatement(node as NodeExpressionStatement); return; + case NodeType.TUPLE_LITERAL: + this.visitTupleLiteral(node as NodeTupleLiteral); + return; + case NodeType.LIST_LITERAL: + this.visitListLiteral(node as NodeListLiteral); + return; + case NodeType.INDEXED_ACCESS: + this.visitIndexedAccess(node as NodeIndexedAccess); + return; case NodeType.TERM: this.visitTerm(node as NodeTerm); return; @@ -187,6 +199,15 @@ export class SimpleVisitor implements Visitor { visitExpressionStatement(node: NodeExpressionStatement) { this.visitChildren(node); } + visitTupleLiteral(node: NodeTupleLiteral) { + this.visitChildren(node); + } + visitListLiteral(node: NodeListLiteral) { + this.visitChildren(node); + } + visitIndexedAccess(node: NodeIndexedAccess) { + this.visitChildren(node); + } visitTerm(node: NodeTerm) { this.visitChildren(node); } diff --git a/src/semantics/index.ts b/src/semantics/index.ts index 78524cb..4d2805b 100644 --- a/src/semantics/index.ts +++ b/src/semantics/index.ts @@ -5,6 +5,8 @@ import { NodeExpr, NodeForStatement, NodeFunctionDefinition, + NodeGomTypeComposite, + NodeGomTypeId, NodeGomTypeStruct, NodeGomTypeStructField, NodeIfStatement, @@ -12,8 +14,10 @@ import { NodeLetStatement, NodeMainFunction, NodeProgram, + NodeReturnStatement, NodeStructInit, NodeTerm, + NodeTupleLiteral, NodeTypeDefinition, } from "../parser/rd/nodes"; import { ScopeManager, SymbolTableReader } from "./scope"; @@ -22,6 +26,7 @@ import { GomFunctionType, GomPrimitiveTypeOrAlias, GomStructType, + GomTupleType, GomType, } from "./type"; import { GomErrorManager } from "../util/error"; @@ -30,6 +35,7 @@ import { GomModule } from "../parser/rd/modules"; export class SemanticAnalyzer extends SimpleVisitor { scopeManager: ScopeManager; + private currentFunctionDefinition: NodeFunctionDefinition | null = null; constructor(private ast: NodeProgram, private errorManager: GomErrorManager) { super(); @@ -79,18 +85,35 @@ export class SemanticAnalyzer extends SimpleVisitor { } visitFunctionDefinition(node: NodeFunctionDefinition): void { + this.currentFunctionDefinition = node; let returnType: GomType; + const nodeReturnType = node.returnType; + if (nodeReturnType) { + const returnTypeType = nodeReturnType.returnType; - if (node.returnType) { - const type = this.scopeManager.getType(node.returnType.returnType.value); - if (!type) { - this.errorManager.throwTypeError({ - message: `Return type ${node.returnType.returnType.value} not found`, - loc: node.returnType?.loc || node.loc, + if ( + returnTypeType instanceof NodeGomTypeId && + returnTypeType.id.token.type !== GomToken.BUILT_IN_TYPE + ) { + const type = this.scopeManager.getType(returnTypeType.id.token.value); + if (!type) { + this.errorManager.throwTypeError({ + message: `Return type ${nodeReturnType.returnType.token?.value} not found`, + loc: nodeReturnType?.loc || node.loc, + }); + } + returnType = type.gomType; + } else if (returnTypeType instanceof NodeGomTypeId) { + returnType = new GomPrimitiveTypeOrAlias(returnTypeType.id.token.value); + } else if (returnTypeType instanceof NodeGomTypeStruct) { + const fields = new Map(); + returnTypeType.fields.forEach((field) => { + return field.fieldType; }); + returnType = new GomStructType(node.name.value + "_return", fields); + } else { + returnType = returnTypeType.gomType; } - - returnType = type.gomType; } else { returnType = new GomPrimitiveTypeOrAlias("void"); } @@ -121,6 +144,7 @@ export class SemanticAnalyzer extends SimpleVisitor { }); node.body.forEach((stmt) => this.visit(stmt)); this.scopeManager.endScope(); + this.currentFunctionDefinition = null; } visitForStatement(node: NodeForStatement): void { @@ -190,10 +214,44 @@ export class SemanticAnalyzer extends SimpleVisitor { inferredType, decl.rhs ); + console.log( + "let", + decl.lhs.token.value, + this.scopeManager.getCurrentSymbolTableNode().getName() + ); } }); } + visitReturnStatement(node: NodeReturnStatement): void { + let returnType: GomType | null = null; + if (node.expr) { + this.visit(node.expr); + const typeResolver = new TypeResolver( + this.scopeManager, + this.errorManager + ); + returnType = typeResolver.resolveType(node.expr); + } + if (this.currentFunctionDefinition) { + const fnType = this.currentFunctionDefinition.resultantType; + if ( + fnType instanceof GomFunctionType && + returnType && + !returnType.isEqual(fnType.returnType) && + !( + returnType instanceof GomPrimitiveTypeOrAlias && + returnType.typeString === "void" + ) + ) { + this.errorManager.throwTypeError({ + message: `Return type mismatch: expected ${fnType.returnType.toStr()}, got ${returnType.toStr()}`, + loc: node.loc, + }); + } + } + } + visitAccess(node: NodeAccess): void { const typeResolver = new TypeResolver(this.scopeManager, this.errorManager); typeResolver.resolveType(node); @@ -300,7 +358,7 @@ class TypeResolver extends SimpleVisitor { } const gomType = type.gomType; - if (gomType instanceof GomStructType) { + if (gomType instanceof GomStructType || gomType instanceof GomTupleType) { Array.from(gomType.fields.entries()).forEach(([key, field]) => { const _field = field as GomPrimitiveTypeOrAlias; if (_field.typeString.startsWith("resolve_type@@")) { @@ -338,7 +396,7 @@ class TypeResolver extends SimpleVisitor { if (id && !id.isFunction()) { // ensure that node.lhs is a struct // only support member access for structs for now - if (id.type instanceof GomStructType) { + if (id.type instanceof GomStructType || id.type instanceof GomTupleType) { node.lhs.resultantType = id.type; if (node.rhs instanceof NodeTerm) { const structType = id.type; @@ -474,6 +532,16 @@ class TypeResolver extends SimpleVisitor { } } + visitTupleLiteral(node: NodeTupleLiteral): void { + const elements = node.elements.map((element) => { + this.visit(element); + return this.currentType!; + }); + + node.resultantType = new GomTupleType(elements); + this.currentType = node.resultantType; + } + visitTerm(node: NodeTerm): void { const type = node.gomType; diff --git a/src/semantics/scope.ts b/src/semantics/scope.ts index 49b2ae9..cfd0d9d 100644 --- a/src/semantics/scope.ts +++ b/src/semantics/scope.ts @@ -2,8 +2,10 @@ import llvm from "llvm-bindings"; import { NodeExpr, NodeFunctionDefinition, - NodeGomTypeIdOrArray, + NodeGomTypeComposite, + NodeGomTypeId, NodeGomTypeStruct, + NodeGomTypeTuple, NodeTerm, NodeTypeDefinition, } from "../parser/rd/nodes"; @@ -12,6 +14,7 @@ import { GomPrimitiveTypeOrAlias, GomPrimitiveTypeOrAliasValue, GomStructType, + GomTupleType, GomType, } from "./type"; import { GOM_BUILT_IN_TYPES, GomToken } from "../lexer/tokens"; @@ -54,22 +57,33 @@ class TypeEntry { constructor(name: string, node: NodeTypeDefinition) { this.name = name; this.node = node; - this.gomType = - node.rhs instanceof NodeGomTypeStruct - ? new GomStructType( - name, - node.rhs.fields.reduce((acc, field) => { - if (field instanceof NodeGomTypeStruct) { - throw new SyntaxError({ - message: `Nested structs are not supported`, - loc: [1, field.loc], - }); - } - acc.set(field.name.value, field.fieldType.gomType); - return acc; - }, new Map()) - ) - : new GomPrimitiveTypeOrAlias(node.name.token.value); + this.gomType = this.makeGomType(); + } + + private makeGomType() { + return this.node.rhs.gomType; + // if (this.node.rhs instanceof NodeGomTypeStruct) { + // return new GomStructType( + // this.name, + // this.node.rhs.fields.reduce((acc, field) => { + // if (field instanceof NodeGomTypeStruct) { + // throw new SyntaxError({ + // message: `Nested structs are not supported`, + // loc: [1, field.loc], + // }); + // } + // acc.set(field.name.value, field.fieldType.gomType); + // return acc; + // }, new Map()) + // ); + // } else if (this.node.rhs instanceof NodeGomTypeTuple) { + // return new GomTupleType( + // this.node.rhs.fields.map((field) => field.gomType) + // ); + // } else if (this.node.rhs instanceof NodeGomTypeComposite) { + // } else { + // return new GomPrimitiveTypeOrAlias(this.node.name.token.value); + // } } getValue() { @@ -214,14 +228,13 @@ export class ScopeManager { end: 0, type: GomToken.BUILT_IN_TYPE, }), - rhs: new NodeGomTypeIdOrArray({ + rhs: new NodeGomTypeId({ id: new NodeTerm({ value: type, start: 0, end: 0, type: GomToken.BUILT_IN_TYPE, }), - arrSize: undefined, loc: 0, }), loc: 0, diff --git a/src/semantics/type.ts b/src/semantics/type.ts index 397bb42..790cec2 100644 --- a/src/semantics/type.ts +++ b/src/semantics/type.ts @@ -1,20 +1,33 @@ /** * Gom type can be: * - Primitive, e.g. int, bool, float, str, void + * - Tuple, e.g. (int, bool) * - Struct e.g. { x: int, y: int } - * - Custom, e.g. type Number = int + * - Composite, e.g. type IntList = List * - Function, e.g. fn add(a: int, b: int): int * * For now, structs are not supported & custom types can only be aliases to primitives. */ +import assert from "assert"; + export enum GomTypeKind { PrimitiveOrAlias = "PrimitiveOrAlias", + // Deprecated, use Composite instead Array = "Array", + Tuple = "Tuple", Struct = "Struct", + Composite = "Composite", Function = "Function", } +export enum GomCompositeTypeKind { + List = "List", + _Custom = "_Custom", + // Map = "Map", + // Set = "Set", +} + export class GomType { kind: GomTypeKind = GomTypeKind.PrimitiveOrAlias; toStr(): string { @@ -55,6 +68,9 @@ export class GomPrimitiveTypeOrAlias extends GomType { } } +/** + * Deprecated, use GomCompositeType instead + */ export class GomArrayType extends GomType { kind: GomTypeKind; elementType: GomType; @@ -81,6 +97,43 @@ export class GomArrayType extends GomType { } } +export class GomTupleType extends GomType { + kind: GomTypeKind; + fields: Map; + + constructor(fields: GomType[]) { + super(); + this.kind = GomTypeKind.Tuple; + this.fields = fields.reduce((acc, field, i) => { + acc.set(i.toString(), field); + return acc; + }, new Map()); + } + + isEqual(other: GomTupleType): boolean { + if (other.kind !== GomTypeKind.Tuple) { + return false; + } + if (this.fields.size !== other.fields.size) { + return false; + } + for (let i = 0; i < this.fields.size; i++) { + const otherField = other.fields.get(i.toString()); + assert(otherField); + if (!this.fields.get(i.toString())?.isEqual(otherField)) { + return false; + } + } + return true; + } + + toStr(): string { + return `{ ${Array.from(this.fields) + .map((field) => field[1].toStr()) + .join(", ")} }`; + } +} + export class GomStructType extends GomType { kind: GomTypeKind; name: string; @@ -114,6 +167,19 @@ export class GomStructType extends GomType { } } +export class GomCompositeType extends GomType { + kind: GomTypeKind; + compositeKind: GomCompositeTypeKind; + fieldTypes: GomType[]; + + constructor(compositeKind: GomCompositeTypeKind, fieldTypes: GomType[]) { + super(); + this.kind = GomTypeKind.Composite; + this.compositeKind = compositeKind; + this.fieldTypes = fieldTypes; + } +} + export class GomFunctionType extends GomType { kind: GomTypeKind; args: GomType[]; @@ -147,4 +213,12 @@ export class GomFunctionType extends GomType { .map((arg) => arg.toStr()) .join(", ")}) => ${this.returnType.toStr()}`; } + + usesSret(): boolean { + return ( + this.returnType instanceof GomStructType || + this.returnType instanceof GomCompositeType || + this.returnType instanceof GomTupleType + ); + } } diff --git a/src/util/error.ts b/src/util/error.ts index 0f37c5d..8213502 100644 --- a/src/util/error.ts +++ b/src/util/error.ts @@ -1,6 +1,10 @@ +import chalk from "chalk"; + export class SyntaxError extends Error { constructor({ loc, message }: { loc: [number, number]; message: string }) { - super(`SyntaxError at ${loc.join(":")}: ${message}`); + super( + chalk.bold(`${chalk.red(`SyntaxError at ${loc.join(":")}`)}: ${message}`) + ); } } diff --git a/test_2 b/test_2 new file mode 100755 index 0000000..ac0c9b3 Binary files /dev/null and b/test_2 differ diff --git a/tree.json b/tree.json index 42ed419..f4fcc3d 100644 --- a/tree.json +++ b/tree.json @@ -16,307 +16,447 @@ "typeDefinitions": [ { "type": "TYPE_DEFINITION", - "loc": 12, + "loc": 21, "name": { "type": "TERM", - "loc": 17, + "loc": 26, "token": { "type": "identifier", - "value": "Point", - "start": 17, - "end": 21 + "value": "HttpResponse", + "start": 26, + "end": 37 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "resolve_type@@HttpResponse" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "resolve_type@@HttpResponse" } }, "rhs": { - "type": "GOM_TYPE_STRUCT", - "loc": 25, + "type": "GOM_TYPE_TUPLE", + "loc": 41, "fields": [ { - "type": "GOM_TYPE_STRUCT_FIELD", - "loc": 31, - "name": { - "type": "identifier", - "value": "x", - "start": 31, - "end": 31 - }, - "fieldType": { - "type": "GOM_TYPE_ID_OR_ARRAY", - "loc": 34, - "id": { - "type": "TERM", - "loc": 34, - "token": { - "type": "built_in_type", - "value": "int", - "start": 34, - "end": 36 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } + "type": "GOM_TYPE_ID", + "loc": 43, + "id": { + "type": "TERM", + "loc": 43, + "token": { + "type": "built_in_type", + "value": "int", + "start": 43, + "end": 45 }, "gomType": { "kind": "PrimitiveOrAlias", "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" } + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" } }, { - "type": "GOM_TYPE_STRUCT_FIELD", - "loc": 43, - "name": { - "type": "identifier", - "value": "y", - "start": 43, - "end": 43 - }, - "fieldType": { - "type": "GOM_TYPE_ID_OR_ARRAY", - "loc": 46, - "id": { - "type": "TERM", - "loc": 46, - "token": { - "type": "built_in_type", - "value": "int", - "start": 46, - "end": 48 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } + "type": "GOM_TYPE_ID", + "loc": 48, + "id": { + "type": "TERM", + "loc": 48, + "token": { + "type": "built_in_type", + "value": "bool", + "start": 48, + "end": 51 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "bool" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" } + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" } } ], "gomType": { - "kind": "Struct", - "name": "Point", + "kind": "Tuple", "fields": {} } } - }, + } + ], + "globalVariables": [], + "functionDeclarations": [ { - "type": "TYPE_DEFINITION", - "loc": 54, + "type": "FUNCTION_DEFINITION", + "loc": 58, "name": { - "type": "TERM", - "loc": 59, - "token": { - "type": "identifier", - "value": "Line", - "start": 59, - "end": 62 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Line" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Line" - } + "type": "identifier", + "value": "process_http", + "start": 61, + "end": 72 }, - "rhs": { - "type": "GOM_TYPE_STRUCT", - "loc": 66, - "fields": [ - { - "type": "GOM_TYPE_STRUCT_FIELD", - "loc": 72, - "name": { + "args": [ + { + "type": "ARGUMENT_ITEM", + "loc": 74, + "name": { + "type": "TERM", + "loc": 74, + "token": { "type": "identifier", - "value": "p1", - "start": 72, - "end": 73 + "value": "url", + "start": 74, + "end": 76 }, - "fieldType": { - "type": "GOM_TYPE_ID_OR_ARRAY", - "loc": 76, - "id": { + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@url" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@url" + } + }, + "expectedType": { + "type": "TERM", + "loc": 79, + "token": { + "type": "built_in_type", + "value": "str", + "start": 79, + "end": 81 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "str" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "str" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "str" + } + } + ], + "returnType": { + "type": "FUNCTION_RETURN_TYPE", + "loc": 83, + "returnType": { + "type": "GOM_TYPE_ID", + "loc": 85, + "id": { + "type": "TERM", + "loc": 85, + "token": { + "type": "identifier", + "value": "HttpResponse", + "start": 85, + "end": 96 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@HttpResponse" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@HttpResponse" + } + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@HttpResponse" + } + } + }, + "body": [ + { + "type": "IF_STATEMENT", + "loc": 102, + "conditionExpr": { + "type": "EXPR_BRACKETED", + "loc": 104, + "expr": { + "type": "COMPARISON", + "loc": 105, + "lhs": { "type": "TERM", - "loc": 76, + "loc": 105, "token": { "type": "identifier", - "value": "Point", - "start": 76, - "end": 80 + "value": "url", + "start": 105, + "end": 107 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "resolve_type@@url" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "str" } }, - "gomType": { + "op": { + "type": "==", + "value": "==", + "start": 109, + "end": 110 + }, + "rhs": { + "type": "TERM", + "loc": 112, + "token": { + "type": "strliteral", + "value": "\"http://www.example.com\"", + "start": 112, + "end": 135 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "str" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "str" + } + }, + "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "bool" } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "void" } }, - { - "type": "GOM_TYPE_STRUCT_FIELD", - "loc": 87, - "name": { - "type": "identifier", - "value": "p2", - "start": 87, - "end": 88 - }, - "fieldType": { - "type": "GOM_TYPE_ID_OR_ARRAY", - "loc": 91, - "id": { + "body": [ + { + "type": "RETURN_STATEMENT", + "loc": 144, + "expr": { + "type": "TUPLE_LITERAL", + "loc": 151, + "elements": [ + { + "type": "TERM", + "loc": 153, + "token": { + "type": "numliteral", + "value": "200", + "start": 153, + "end": 155 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + { + "type": "TERM", + "loc": 158, + "token": { + "type": "true", + "value": "true", + "start": 158, + "end": 161 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" + } + } + ], + "gomType": { + "kind": "Tuple", + "fields": {} + }, + "resultantType": { + "kind": "Tuple", + "fields": {} + } + } + } + ] + }, + { + "type": "RETURN_STATEMENT", + "loc": 175, + "expr": { + "type": "TUPLE_LITERAL", + "loc": 182, + "elements": [ + { "type": "TERM", - "loc": 91, + "loc": 184, "token": { - "type": "identifier", - "value": "Point", - "start": 91, - "end": 95 + "type": "numliteral", + "value": "401", + "start": 184, + "end": 186 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "int" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "int" } }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + { + "type": "TERM", + "loc": 189, + "token": { + "type": "false", + "value": "false", + "start": 189, + "end": 193 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" + } } + ], + "gomType": { + "kind": "Tuple", + "fields": {} + }, + "resultantType": { + "kind": "Tuple", + "fields": {} } } + } + ], + "resultantType": { + "kind": "Function", + "args": [ + { + "kind": "PrimitiveOrAlias", + "typeString": "str" + } ], - "gomType": { - "kind": "Struct", - "name": "Line", + "returnType": { + "kind": "Tuple", "fields": {} } } - } - ], - "globalVariables": [ + }, { - "type": "LET_STATEMENT", - "loc": 101, - "decls": [ + "type": "FUNCTION_DEFINITION", + "loc": 201, + "name": { + "type": "identifier", + "value": "process_http_retry", + "start": 204, + "end": 221 + }, + "args": [ { - "type": "ASSIGNMENT", - "loc": 105, - "lhs": { + "type": "ARGUMENT_ITEM", + "loc": 223, + "name": { "type": "TERM", - "loc": 105, + "loc": 223, "token": { "type": "identifier", - "value": "GLOBAL", - "start": 105, - "end": 110 + "value": "url", + "start": 223, + "end": 225 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@GLOBAL" + "typeString": "resolve_type@@url" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@url" } }, - "rhs": { + "expectedType": { "type": "TERM", - "loc": 114, + "loc": 228, "token": { - "type": "numliteral", - "value": "1", - "start": 114, - "end": 114 + "type": "built_in_type", + "value": "str", + "start": 228, + "end": 230 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "str" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "str" } }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "void" + "typeString": "str" } - } - ] - } - ], - "functionDeclarations": [ - { - "type": "FUNCTION_DEFINITION", - "loc": 118, - "name": { - "type": "identifier", - "value": "square", - "start": 121, - "end": 126 - }, - "args": [ + }, { "type": "ARGUMENT_ITEM", - "loc": 128, + "loc": 233, "name": { "type": "TERM", - "loc": 128, + "loc": 233, "token": { "type": "identifier", - "value": "x", - "start": 128, - "end": 128 + "value": "retries", + "start": 233, + "end": 239 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@retries" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@retries" } }, "expectedType": { "type": "TERM", - "loc": 131, + "loc": 242, "token": { "type": "built_in_type", "value": "int", - "start": 131, - "end": 133 + "start": 242, + "end": 244 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -335,650 +475,172 @@ ], "returnType": { "type": "FUNCTION_RETURN_TYPE", - "loc": 135, + "loc": 246, "returnType": { - "type": "built_in_type", - "value": "int", - "start": 137, - "end": 139 - } - }, - "body": [ - { - "type": "RETURN_STATEMENT", - "loc": 147, - "expr": { - "type": "QUOT", - "loc": 154, - "lhs": { - "type": "TERM", - "loc": 154, - "token": { - "type": "identifier", - "value": "x", - "start": 154, - "end": 154 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "op": { - "type": "*", - "value": "*", - "start": 156, - "end": 156 - }, - "rhs": { - "type": "TERM", - "loc": 158, - "token": { - "type": "identifier", - "value": "x", - "start": 158, - "end": 158 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - } - ], - "resultantType": { - "kind": "Function", - "args": [ - { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - ], - "returnType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - }, - { - "type": "FUNCTION_DEFINITION", - "loc": 164, - "name": { - "type": "identifier", - "value": "add", - "start": 167, - "end": 169 - }, - "args": [ - { - "type": "ARGUMENT_ITEM", - "loc": 171, - "name": { + "type": "GOM_TYPE_ID", + "loc": 248, + "id": { "type": "TERM", - "loc": 171, + "loc": 248, "token": { "type": "identifier", - "value": "a", - "start": 171, - "end": 171 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@a" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@a" - } - }, - "expectedType": { - "type": "TERM", - "loc": 174, - "token": { - "type": "built_in_type", - "value": "int", - "start": 174, - "end": 176 + "value": "HttpResponse", + "start": 248, + "end": 259 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@HttpResponse" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@HttpResponse" } }, - "resultantType": { + "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - { - "type": "ARGUMENT_ITEM", - "loc": 179, - "name": { - "type": "TERM", - "loc": 179, - "token": { - "type": "identifier", - "value": "b", - "start": 179, - "end": 179 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@b" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@b" - } - }, - "expectedType": { - "type": "TERM", - "loc": 182, - "token": { - "type": "built_in_type", - "value": "int", - "start": 182, - "end": 184 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@HttpResponse" } } - ], - "returnType": { - "type": "FUNCTION_RETURN_TYPE", - "loc": 186, - "returnType": { - "type": "built_in_type", - "value": "int", - "start": 188, - "end": 190 - } }, "body": [ { - "type": "RETURN_STATEMENT", - "loc": 198, - "expr": { - "type": "SUM", - "loc": 205, + "type": "LET_STATEMENT", + "loc": 265, + "decls": [ + { + "type": "ASSIGNMENT", + "loc": 269, + "lhs": { + "type": "TERM", + "loc": 269, + "token": { + "type": "identifier", + "value": "i", + "start": 269, + "end": 269 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@i" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "rhs": { + "type": "TERM", + "loc": 273, + "token": { + "type": "numliteral", + "value": "0", + "start": 273, + "end": 273 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "void" + } + } + ] + }, + { + "type": "FOR_STATEMENT", + "loc": 278, + "initExpr": { + "type": "ASSIGNMENT", + "loc": 282, "lhs": { "type": "TERM", - "loc": 205, + "loc": 282, "token": { "type": "identifier", - "value": "a", - "start": 205, - "end": 205 + "value": "i", + "start": 282, + "end": 282 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@a" + "typeString": "resolve_type@@i" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@i" } }, - "op": { - "type": "+", - "value": "+", - "start": 207, - "end": 207 - }, "rhs": { "type": "TERM", - "loc": 209, + "loc": 286, "token": { "type": "identifier", - "value": "b", - "start": 209, - "end": 209 + "value": "retries", + "start": 286, + "end": 292 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@b" + "typeString": "resolve_type@@retries" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@retries" } }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - } - ], - "resultantType": { - "kind": "Function", - "args": [ - { - "kind": "PrimitiveOrAlias", - "typeString": "int" - }, - { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - ], - "returnType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - }, - { - "type": "FUNCTION_DEFINITION", - "loc": 215, - "name": { - "type": "identifier", - "value": "distance", - "start": 218, - "end": 225 - }, - "args": [ - { - "type": "ARGUMENT_ITEM", - "loc": 227, - "name": { - "type": "TERM", - "loc": 227, - "token": { - "type": "identifier", - "value": "p1", - "start": 227, - "end": 228 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" - } - }, - "expectedType": { - "type": "TERM", - "loc": 231, - "token": { - "type": "identifier", - "value": "Point", - "start": 231, - "end": 235 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" - } - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - { - "type": "ARGUMENT_ITEM", - "loc": 238, - "name": { - "type": "TERM", - "loc": 238, - "token": { - "type": "identifier", - "value": "p2", - "start": 238, - "end": 239 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - } - }, - "expectedType": { - "type": "TERM", - "loc": 242, - "token": { - "type": "identifier", - "value": "Point", - "start": 242, - "end": 246 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "void" } }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - } - ], - "returnType": { - "type": "FUNCTION_RETURN_TYPE", - "loc": 248, - "returnType": { - "type": "built_in_type", - "value": "int", - "start": 250, - "end": 252 - } - }, - "body": [ - { - "type": "RETURN_STATEMENT", - "loc": 260, - "expr": { - "type": "SUM", - "loc": 267, + "conditionExpr": { + "type": "COMPARISON", + "loc": 295, "lhs": { - "type": "CALL", - "loc": 267, - "id": { - "type": "TERM", - "loc": 267, - "token": { - "type": "identifier", - "value": "square", - "start": 267, - "end": 272 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@square" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@square" - } + "type": "TERM", + "loc": 295, + "token": { + "type": "identifier", + "value": "i", + "start": 295, + "end": 295 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@i" }, - "args": [ - { - "type": "SUM", - "loc": 274, - "lhs": { - "type": "ACCESS", - "loc": 274, - "lhs": { - "type": "TERM", - "loc": 274, - "token": { - "type": "identifier", - "value": "p1", - "start": 274, - "end": 275 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - "rhs": { - "type": "TERM", - "loc": 277, - "token": { - "type": "identifier", - "value": "x", - "start": 277, - "end": 277 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "op": { - "type": "-", - "value": "-", - "start": 279, - "end": 279 - }, - "rhs": { - "type": "ACCESS", - "loc": 281, - "lhs": { - "type": "TERM", - "loc": 281, - "token": { - "type": "identifier", - "value": "p2", - "start": 281, - "end": 282 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - "rhs": { - "type": "TERM", - "loc": 284, - "token": { - "type": "identifier", - "value": "x", - "start": 284, - "end": 284 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - ], "resultantType": { "kind": "PrimitiveOrAlias", "typeString": "int" } }, "op": { - "type": "+", - "value": "+", - "start": 287, - "end": 287 + "type": ">", + "value": ">", + "start": 297, + "end": 297 }, "rhs": { - "type": "CALL", - "loc": 289, - "id": { - "type": "TERM", - "loc": 289, - "token": { - "type": "identifier", - "value": "square", - "start": 289, - "end": 294 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@square" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@square" - } - }, - "args": [ - { - "type": "SUM", - "loc": 296, - "lhs": { - "type": "ACCESS", - "loc": 296, - "lhs": { - "type": "TERM", - "loc": 296, - "token": { - "type": "identifier", - "value": "p1", - "start": 296, - "end": 297 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - "rhs": { - "type": "TERM", - "loc": 299, - "token": { - "type": "identifier", - "value": "y", - "start": 299, - "end": 299 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@y" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "op": { - "type": "-", - "value": "-", - "start": 301, - "end": 301 - }, - "rhs": { - "type": "ACCESS", - "loc": 303, - "lhs": { - "type": "TERM", - "loc": 303, - "token": { - "type": "identifier", - "value": "p2", - "start": 303, - "end": 304 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - "rhs": { - "type": "TERM", - "loc": 306, - "token": { - "type": "identifier", - "value": "y", - "start": 306, - "end": 306 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@y" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - ], + "type": "TERM", + "loc": 299, + "token": { + "type": "numliteral", + "value": "0", + "start": 299, + "end": 299 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, "resultantType": { "kind": "PrimitiveOrAlias", "typeString": "int" @@ -986,244 +648,357 @@ }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "bool" } - } - } - ], - "resultantType": { - "kind": "Function", - "args": [ - { - "kind": "Struct", - "name": "Point", - "fields": {} }, - { - "kind": "Struct", - "name": "Point", - "fields": {} - } - ], - "returnType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - } - ], - "exportStatements": [], - "mainFunction": { - "type": "MAIN_FUNCTION", - "loc": 316, - "body": [ - { - "type": "LET_STATEMENT", - "loc": 329, - "decls": [ - { + "updateExpr": { "type": "ASSIGNMENT", - "loc": 333, + "loc": 302, "lhs": { "type": "TERM", - "loc": 333, + "loc": 302, "token": { "type": "identifier", - "value": "p1", - "start": 333, - "end": 334 + "value": "i", + "start": 302, + "end": 302 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" + "typeString": "resolve_type@@i" }, "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@i" } }, "rhs": { - "type": "STRUCT_INIT", - "loc": 338, - "structTypeName": { + "type": "SUM", + "loc": 306, + "lhs": { "type": "TERM", - "loc": 338, + "loc": 306, "token": { "type": "identifier", - "value": "Point", - "start": 338, - "end": 342 + "value": "i", + "start": 306, + "end": 306 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "resolve_type@@i" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" + "typeString": "int" } }, - "fields": [ - [ - { + "op": { + "type": "-", + "value": "-", + "start": 308, + "end": 308 + }, + "rhs": { + "type": "TERM", + "loc": 310, + "token": { + "type": "numliteral", + "value": "1", + "start": 310, + "end": 310 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "void" + } + }, + "body": [ + { + "type": "EXPRESSION_STATEMENT", + "loc": 319, + "expr": { + "type": "ACCESS", + "loc": 319, + "lhs": { + "type": "TERM", + "loc": 319, + "token": { + "type": "identifier", + "value": "io", + "start": 319, + "end": 320 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@io" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@io" + } + }, + "rhs": { + "type": "CALL", + "loc": 322, + "id": { "type": "TERM", - "loc": 346, + "loc": 322, "token": { "type": "identifier", - "value": "x", - "start": 346, - "end": 346 + "value": "log", + "start": 322, + "end": 324 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@log" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@log" } }, - { - "type": "TERM", - "loc": 349, - "token": { - "type": "numliteral", - "value": "1", - "start": 349, - "end": 349 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "args": [ + { + "type": "TERM", + "loc": 326, + "token": { + "type": "strliteral", + "value": "\"Round: \"", + "start": 326, + "end": 334 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "str" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "str" + } }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + { + "type": "SUM", + "loc": 337, + "lhs": { + "type": "SUM", + "loc": 337, + "lhs": { + "type": "TERM", + "loc": 337, + "token": { + "type": "identifier", + "value": "retries", + "start": 337, + "end": 343 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@retries" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "op": { + "type": "-", + "value": "-", + "start": 345, + "end": 345 + }, + "rhs": { + "type": "TERM", + "loc": 347, + "token": { + "type": "identifier", + "value": "i", + "start": 347, + "end": 347 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@i" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "op": { + "type": "+", + "value": "+", + "start": 349, + "end": 349 + }, + "rhs": { + "type": "TERM", + "loc": 351, + "token": { + "type": "numliteral", + "value": "1", + "start": 351, + "end": 351 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } } + ], + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "void" } - ], - [ - { + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "void" + } + } + }, + { + "type": "LET_STATEMENT", + "loc": 359, + "decls": [ + { + "type": "ASSIGNMENT", + "loc": 363, + "lhs": { "type": "TERM", - "loc": 352, + "loc": 363, "token": { "type": "identifier", - "value": "y", - "start": 352, - "end": 352 + "value": "resp", + "start": 363, + "end": 366 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@y" + "typeString": "resolve_type@@resp" }, "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@y" + "kind": "Tuple", + "fields": {} } }, - { - "type": "TERM", - "loc": 355, - "token": { - "type": "numliteral", - "value": "2", - "start": 355, - "end": 355 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "rhs": { + "type": "CALL", + "loc": 370, + "id": { + "type": "TERM", + "loc": 370, + "token": { + "type": "identifier", + "value": "process_http", + "start": 370, + "end": 381 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@process_http" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@process_http" + } }, + "args": [ + { + "type": "TERM", + "loc": 383, + "token": { + "type": "identifier", + "value": "url", + "start": 383, + "end": 385 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@url" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "str" + } + } + ], "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "kind": "Tuple", + "fields": {} } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "void" } - ] - ], - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "void" - } - }, - { - "type": "ASSIGNMENT", - "loc": 360, - "lhs": { - "type": "TERM", - "loc": 360, - "token": { - "type": "identifier", - "value": "p2", - "start": 360, - "end": 361 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - "rhs": { - "type": "STRUCT_INIT", - "loc": 365, - "structTypeName": { - "type": "TERM", - "loc": 365, - "token": { - "type": "identifier", - "value": "Point", - "start": 365, - "end": 369 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Point" } - }, - "fields": [ - [ - { + ] + }, + { + "type": "IF_STATEMENT", + "loc": 393, + "conditionExpr": { + "type": "EXPR_BRACKETED", + "loc": 395, + "expr": { + "type": "ACCESS", + "loc": 396, + "lhs": { "type": "TERM", - "loc": 373, + "loc": 396, "token": { "type": "identifier", - "value": "x", - "start": 373, - "end": 373 + "value": "resp", + "start": 396, + "end": 399 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@resp" }, "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "kind": "Tuple", + "fields": {} } }, - { + "rhs": { "type": "TERM", - "loc": 376, + "loc": 401, "token": { "type": "numliteral", - "value": "3", - "start": 376, - "end": 376 + "value": "1", + "start": 401, + "end": 401 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -1231,151 +1006,212 @@ }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "bool" } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" } - ], - [ - { + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "void" + } + }, + "body": [ + { + "type": "RETURN_STATEMENT", + "loc": 412, + "expr": { "type": "TERM", - "loc": 379, + "loc": 419, "token": { "type": "identifier", - "value": "y", - "start": 379, - "end": 379 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@y" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@y" - } - }, - { - "type": "TERM", - "loc": 382, - "token": { - "type": "numliteral", - "value": "4", - "start": 382, - "end": 382 + "value": "resp", + "start": 419, + "end": 422 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@resp" }, "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "kind": "Tuple", + "fields": {} } } - ] - ], - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} + } + ] + } + ] + }, + { + "type": "RETURN_STATEMENT", + "loc": 438, + "expr": { + "type": "TUPLE_LITERAL", + "loc": 445, + "elements": [ + { + "type": "TERM", + "loc": 447, + "token": { + "type": "numliteral", + "value": "500", + "start": 447, + "end": 449 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + { + "type": "TERM", + "loc": 452, + "token": { + "type": "false", + "value": "false", + "start": 452, + "end": 456 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" + } } + ], + "gomType": { + "kind": "Tuple", + "fields": {} }, "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "void" + "kind": "Tuple", + "fields": {} } } - ] - }, + } + ], + "resultantType": { + "kind": "Function", + "args": [ + { + "kind": "PrimitiveOrAlias", + "typeString": "str" + }, + { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + ], + "returnType": { + "kind": "Tuple", + "fields": {} + } + } + } + ], + "exportStatements": [], + "mainFunction": { + "type": "MAIN_FUNCTION", + "loc": 467, + "body": [ { "type": "LET_STATEMENT", - "loc": 391, + "loc": 478, "decls": [ { "type": "ASSIGNMENT", - "loc": 395, + "loc": 482, "lhs": { "type": "TERM", - "loc": 395, + "loc": 482, "token": { "type": "identifier", - "value": "d", - "start": 395, - "end": 395 + "value": "resp", + "start": 482, + "end": 485 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@d" + "typeString": "resolve_type@@resp" }, "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "kind": "Tuple", + "fields": {} } }, "rhs": { "type": "CALL", - "loc": 399, + "loc": 489, "id": { "type": "TERM", - "loc": 399, + "loc": 489, "token": { "type": "identifier", - "value": "distance", - "start": 399, - "end": 406 + "value": "process_http_retry", + "start": 489, + "end": 506 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@distance" + "typeString": "resolve_type@@process_http_retry" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@distance" + "typeString": "resolve_type@@process_http_retry" } }, "args": [ { "type": "TERM", - "loc": 408, + "loc": 508, "token": { - "type": "identifier", - "value": "p1", - "start": 408, - "end": 409 + "type": "strliteral", + "value": "\"http://www.example.com\"", + "start": 508, + "end": 531 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" + "typeString": "str" }, "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} + "kind": "PrimitiveOrAlias", + "typeString": "str" } }, { "type": "TERM", - "loc": 412, + "loc": 534, "token": { - "type": "identifier", - "value": "p2", - "start": 412, - "end": 413 + "type": "numliteral", + "value": "10", + "start": 534, + "end": 535 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" + "typeString": "int" }, "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} + "kind": "PrimitiveOrAlias", + "typeString": "int" } } ], "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "kind": "Tuple", + "fields": {} } }, "resultantType": { @@ -1387,18 +1223,18 @@ }, { "type": "EXPRESSION_STATEMENT", - "loc": 421, + "loc": 541, "expr": { "type": "ACCESS", - "loc": 421, + "loc": 541, "lhs": { "type": "TERM", - "loc": 421, + "loc": 541, "token": { "type": "identifier", "value": "io", - "start": 421, - "end": 422 + "start": 541, + "end": 542 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -1411,15 +1247,15 @@ }, "rhs": { "type": "CALL", - "loc": 424, + "loc": 544, "id": { "type": "TERM", - "loc": 424, + "loc": 544, "token": { "type": "identifier", "value": "log", - "start": 424, - "end": 426 + "start": 544, + "end": 546 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -1433,12 +1269,12 @@ "args": [ { "type": "TERM", - "loc": 428, + "loc": 548, "token": { "type": "strliteral", - "value": "\"Distance between p1 and p2: \"", - "start": 428, - "end": 457 + "value": "\"Status: \"", + "start": 548, + "end": 557 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -1450,229 +1286,57 @@ } }, { - "type": "TERM", - "loc": 460, - "token": { - "type": "identifier", - "value": "d", - "start": 460, - "end": 460 + "type": "ACCESS", + "loc": 560, + "lhs": { + "type": "TERM", + "loc": 560, + "token": { + "type": "identifier", + "value": "resp", + "start": 560, + "end": 563 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@resp" + }, + "resultantType": { + "kind": "Tuple", + "fields": {} + } }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@d" + "rhs": { + "type": "TERM", + "loc": 565, + "token": { + "type": "numliteral", + "value": "0", + "start": 565, + "end": 565 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } }, "resultantType": { "kind": "PrimitiveOrAlias", "typeString": "int" } - } - ], - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "void" - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "void" - } - } - }, - { - "type": "LET_STATEMENT", - "loc": 469, - "decls": [ - { - "type": "ASSIGNMENT", - "loc": 473, - "lhs": { - "type": "TERM", - "loc": 473, - "token": { - "type": "identifier", - "value": "l", - "start": 473, - "end": 473 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@l" - }, - "resultantType": { - "kind": "Struct", - "name": "Line", - "fields": {} - } - }, - "rhs": { - "type": "STRUCT_INIT", - "loc": 477, - "structTypeName": { - "type": "TERM", - "loc": 477, - "token": { - "type": "identifier", - "value": "Line", - "start": 477, - "end": 480 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Line" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@Line" - } - }, - "fields": [ - [ - { - "type": "TERM", - "loc": 484, - "token": { - "type": "identifier", - "value": "p1", - "start": 484, - "end": 485 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" - } - }, - { - "type": "TERM", - "loc": 488, - "token": { - "type": "identifier", - "value": "p1", - "start": 488, - "end": 489 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - } - ], - [ - { - "type": "TERM", - "loc": 492, - "token": { - "type": "identifier", - "value": "p2", - "start": 492, - "end": 493 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - } - }, - { - "type": "TERM", - "loc": 496, - "token": { - "type": "identifier", - "value": "p2", - "start": 496, - "end": 497 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - } - ] - ], - "resultantType": { - "kind": "Struct", - "name": "Line", - "fields": {} - } - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "void" - } - } - ] - }, - { - "type": "EXPRESSION_STATEMENT", - "loc": 506, - "expr": { - "type": "ACCESS", - "loc": 506, - "lhs": { - "type": "TERM", - "loc": 506, - "token": { - "type": "identifier", - "value": "io", - "start": 506, - "end": 507 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@io" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@io" - } - }, - "rhs": { - "type": "CALL", - "loc": 509, - "id": { - "type": "TERM", - "loc": 509, - "token": { - "type": "identifier", - "value": "log", - "start": 509, - "end": 511 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@log" }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@log" - } - }, - "args": [ { "type": "TERM", - "loc": 513, + "loc": 568, "token": { "type": "strliteral", - "value": "\"Distance between l.p1 and l.p2: \"", - "start": 513, - "end": 546 + "value": "\" Success: \"", + "start": 568, + "end": 579 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -1684,125 +1348,47 @@ } }, { - "type": "CALL", - "loc": 549, - "id": { + "type": "ACCESS", + "loc": 582, + "lhs": { "type": "TERM", - "loc": 549, + "loc": 582, "token": { "type": "identifier", - "value": "distance", - "start": 549, - "end": 556 + "value": "resp", + "start": 582, + "end": 585 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@distance" + "typeString": "resolve_type@@resp" }, "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@distance" + "kind": "Tuple", + "fields": {} } }, - "args": [ - { - "type": "ACCESS", - "loc": 558, - "lhs": { - "type": "TERM", - "loc": 558, - "token": { - "type": "identifier", - "value": "l", - "start": 558, - "end": 558 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@l" - }, - "resultantType": { - "kind": "Struct", - "name": "Line", - "fields": {} - } - }, - "rhs": { - "type": "TERM", - "loc": 560, - "token": { - "type": "identifier", - "value": "p1", - "start": 560, - "end": 561 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p1" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } + "rhs": { + "type": "TERM", + "loc": 587, + "token": { + "type": "numliteral", + "value": "1", + "start": 587, + "end": 587 }, - { - "type": "ACCESS", - "loc": 564, - "lhs": { - "type": "TERM", - "loc": 564, - "token": { - "type": "identifier", - "value": "l", - "start": 564, - "end": 564 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@l" - }, - "resultantType": { - "kind": "Struct", - "name": "Line", - "fields": {} - } - }, - "rhs": { - "type": "TERM", - "loc": 566, - "token": { - "type": "identifier", - "value": "p2", - "start": 566, - "end": 567 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@p2" - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } - }, - "resultantType": { - "kind": "Struct", - "name": "Point", - "fields": {} - } + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "bool" } - ], + }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "bool" } } ],