From be9f0c626c95b28794eec41f6cfffebafdba5983 Mon Sep 17 00:00:00 2001 From: Mohit Karekar Date: Wed, 5 Mar 2025 23:48:20 +0100 Subject: [PATCH 1/2] Working structs --- README.md | 2 +- examples/test_2.gom | 25 +- examples/test_2.ll | 96 ++ gom.ebnf | 2 +- src/codegen/llvm.ts | 160 ++- src/lexer/tokens.ts | 6 - src/parser/rd/index.ts | 46 +- src/parser/rd/modules.ts | 1 - src/parser/rd/nodes/index.ts | 89 +- src/parser/rd/tree.ts | 1 + src/parser/rd/visitor.ts | 14 + src/semantics/index.ts | 220 ++++- src/semantics/scope.ts | 57 +- src/semantics/type.ts | 36 +- test_2.ll | 60 -- tree.json | 1764 +++++++++++++++++++++++++++++----- 16 files changed, 2121 insertions(+), 458 deletions(-) create mode 100644 examples/test_2.ll delete mode 100644 test_2.ll diff --git a/README.md b/README.md index 2326eda..0102e8d 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ type Name = str; | Lexical Analysis | ✅ Done | | Syntactic Analysis (parsing) | ✅ Done | | Semantic Analysis & preliminary type system | ✅ Done | -| C Code Generation | ⚙️ In progress | +| LLVM IR Generation | ⚙️ In progress | | Complex data structures | ⏳ Not started | ## Trying out Gom diff --git a/examples/test_2.gom b/examples/test_2.gom index dfffce4..cd20e9c 100644 --- a/examples/test_2.gom +++ b/examples/test_2.gom @@ -1,10 +1,15 @@ import io; -type Point = struct { +type Point = { x: int, y: int }; +type Line = { + p1: Point, + p2: Point +}; + let GLOBAL = 1; fn square(x: int): int { @@ -15,15 +20,15 @@ fn add(a: int, b: int): int { return a + b; } -fn main() { - let a = 1 + 2, b = 2; - - add(1, (1 + b / 2)); +fn distance(p1: Point, p2: Point): int { + return square(p1.x - p2.x) + square(p1.y - p2.y); +} - a = 2; - let sq = square(a); - let i = 3; - io.log("Sum: ", add(i, 1)); +fn main() { + let p1 = Point { x: 1, y: 2 }, p2 = Point { x: 3, y: 4 }; + let d = distance(p1, p2); + io.log("Distance between p1 and p2: ", d); - i = i + 1; + let l = Line { p1: p1, p2: p2 }; + io.log("Distance between l.p1 and l.p2: ", distance(l.p1, l.p2)); } \ No newline at end of file diff --git a/examples/test_2.ll b/examples/test_2.ll new file mode 100644 index 0000000..0a9489a --- /dev/null +++ b/examples/test_2.ll @@ -0,0 +1,96 @@ +; ModuleID = 'mod' +source_filename = "mod" + +%Point = type { i32, i32 } +%Line = type { %Point, %Point } + +@GLOBAL = external global i32 +@.strliteral = private unnamed_addr constant [29 x i8] c"Distance between p1 and p2: \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.1 = private unnamed_addr constant [33 x i8] c"Distance between l.p1 and l.p2: \00", align 1 + +define i32 @square(i32 %0) { +entry: + %1 = alloca i32, align 4 + store i32 %0, i32* %1, align 4 + %x.load = load i32, i32* %1, align 4 + %x.load1 = load i32, i32* %1, align 4 + %multmp = mul i32 %x.load, %x.load1 + ret i32 %multmp +} + +define i32 @add(i32 %0, i32 %1) { +entry: + %2 = alloca i32, align 4 + store i32 %0, i32* %2, align 4 + %3 = alloca i32, align 4 + store i32 %1, i32* %3, align 4 + %a.load = load i32, i32* %2, align 4 + %b.load = load i32, i32* %3, align 4 + %addtmp = add i32 %a.load, %b.load + ret i32 %addtmp +} + +define i32 @distance(%Point %0, %Point %1) { +entry: + %2 = alloca %Point, align 8 + store %Point %0, %Point* %2, align 4 + %3 = alloca %Point, align 8 + store %Point %1, %Point* %3, align 4 + %fieldptr = getelementptr %Point, %Point* %2, i32 0, i32 0 + %fieldload = load i32, i32* %fieldptr, align 4 + %fieldptr1 = getelementptr %Point, %Point* %3, i32 0, i32 0 + %fieldload2 = load i32, i32* %fieldptr1, align 4 + %subtmp = sub i32 %fieldload, %fieldload2 + %calltmp = call i32 @square(i32 %subtmp) + %fieldptr3 = getelementptr %Point, %Point* %2, i32 0, i32 1 + %fieldload4 = load i32, i32* %fieldptr3, align 4 + %fieldptr5 = getelementptr %Point, %Point* %3, i32 0, i32 1 + %fieldload6 = load i32, i32* %fieldptr5, align 4 + %subtmp7 = sub i32 %fieldload4, %fieldload6 + %calltmp8 = call i32 @square(i32 %subtmp7) + %addtmp = add i32 %calltmp, %calltmp8 + ret i32 %addtmp +} + +define void @main() { +entry: + %p1 = alloca %Point, align 8 + %fieldptr = getelementptr %Point, %Point* %p1, i32 0, i32 0 + store i32 1, i32* %fieldptr, align 4 + %fieldptr1 = getelementptr %Point, %Point* %p1, i32 0, i32 1 + store i32 2, i32* %fieldptr1, align 4 + %p2 = alloca %Point, align 8 + %fieldptr2 = getelementptr %Point, %Point* %p2, i32 0, i32 0 + store i32 3, i32* %fieldptr2, align 4 + %fieldptr3 = getelementptr %Point, %Point* %p2, i32 0, i32 1 + store i32 4, i32* %fieldptr3, align 4 + %d = alloca i32, align 4 + %p1.load = load %Point, %Point* %p1, align 4 + %p2.load = load %Point, %Point* %p2, align 4 + %calltmp = call i32 @distance(%Point %p1.load, %Point %p2.load) + store i32 %calltmp, i32* %d, align 4 + %d.load = load i32, i32* %d, align 4 + %calltmp0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @.strliteral, 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 %d.load) + %newline = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @newline, i32 0, i32 0)) + %l = alloca %Line, align 8 + %p1.load4 = load %Point, %Point* %p1, align 4 + %fieldptr5 = getelementptr %Line, %Line* %l, i32 0, i32 0 + store %Point %p1.load4, %Point* %fieldptr5, align 4 + %p2.load6 = load %Point, %Point* %p2, align 4 + %fieldptr7 = getelementptr %Line, %Line* %l, i32 0, i32 1 + store %Point %p2.load6, %Point* %fieldptr7, align 4 + %fieldptr8 = getelementptr %Line, %Line* %l, i32 0, i32 0 + %fieldload = load %Point, %Point* %fieldptr8, align 4 + %fieldptr9 = getelementptr %Line, %Line* %l, i32 0, i32 1 + %fieldload10 = load %Point, %Point* %fieldptr9, align 4 + %calltmp11 = call i32 @distance(%Point %fieldload, %Point %fieldload10) + %calltmp012 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([33 x i8], [33 x i8]* @.strliteral.1, i32 0, i32 0)) + %calltmp113 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @fmt.int, i32 0, i32 0), i32 %calltmp11) + %newline14 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @newline, i32 0, i32 0)) + ret void +} + +declare i32 @printf(i8*, ...) diff --git a/gom.ebnf b/gom.ebnf index 30758fd..9ae0716 100644 --- a/gom.ebnf +++ b/gom.ebnf @@ -32,7 +32,7 @@ gomType = typeIdOrArray | structType; typeIdOrArray = typeId ("[" , numLiteral , "]")?; -structType = "struct" , "{" , structTypeItem+ , "}"; +structType = "{" , structTypeItem+ , "}"; structTypeItem = identifier , ":" , gomType , ","?; diff --git a/src/codegen/llvm.ts b/src/codegen/llvm.ts index ce005dc..1250d9c 100644 --- a/src/codegen/llvm.ts +++ b/src/codegen/llvm.ts @@ -10,18 +10,24 @@ import { NodeExpressionStatement, NodeForStatement, NodeFunctionDefinition, + NodeGomTypeStruct, NodeIfStatement, NodeLetStatement, NodeMainFunction, NodeProgram, NodeReturnStatement, + NodeStructInit, NodeTerm, + NodeTypeDefinition, } from "../parser/rd/nodes"; import { ScopeManager } from "../semantics/scope"; import { + GomFunctionType, GomPrimitiveTypeOrAlias, GomPrimitiveTypeOrAliasValue, + GomStructType, GomType, + GomTypeKind, } from "../semantics/type"; import { GomToken } from "../lexer/tokens"; import { GomErrorManager } from "../util/error"; @@ -47,6 +53,8 @@ export class CodeGenerator extends BaseCodeGenerator { private formatStrings: Record = {}; private globalStringPtrs: Record = {}; + private structTypes: Record = {}; + constructor({ ast, scopeManager, @@ -88,7 +96,7 @@ export class CodeGenerator extends BaseCodeGenerator { }); } - private mapGomTypeToLLVMType(type: GomPrimitiveTypeOrAlias) { + private mapGomPrimitiveTypeToLLVMType(type: GomPrimitiveTypeOrAlias) { switch (type.typeString) { case "int": return llvm.Type.getInt32Ty(this.context); @@ -101,24 +109,23 @@ export class CodeGenerator extends BaseCodeGenerator { } } - private getExpressionLLVMType(node: NodeExpr): llvm.Type { - let type: GomType | null = null; - if ( - node instanceof NodeTerm || - node instanceof NodeCall || - node instanceof NodeBinaryOp || - node instanceof NodeAccess - ) { - type = node.resultantType; - } else if (node instanceof NodeExprBracketed) { - return this.getExpressionLLVMType(node.expr); + private mapGomStructTypeToLLVMType(type: GomStructType) { + const structType = this.structTypes[type.name]; + if (!structType) { + throw new Error("Unknown type: " + type.name); } - if (type === null) { - throw new Error("Unknown expression type"); + return structType; + } + + private mapGomTypeToLLVMType(type: GomType) { + if (type instanceof GomPrimitiveTypeOrAlias) { + return this.mapGomPrimitiveTypeToLLVMType(type); + } else if (type instanceof GomStructType) { + return this.mapGomStructTypeToLLVMType(type); } - return this.mapGomTypeToLLVMType(type as GomPrimitiveTypeOrAlias); + throw new Error("Unknown type: " + type.toStr()); } private transformStringLiteral(value: string): string { @@ -164,7 +171,6 @@ export class CodeGenerator extends BaseCodeGenerator { } private writeGlobalFunctions(): void { - console.log("Writing global functions..."); const printFnType = llvm.FunctionType.get( this.builder.getInt32Ty(), [llvm.Type.getInt8PtrTy(this.context)], @@ -188,13 +194,36 @@ export class CodeGenerator extends BaseCodeGenerator { return this.module.print(); } + visitTypeDefinition(node: NodeTypeDefinition): void { + if (node.rhs instanceof NodeGomTypeStruct) { + const type = this.symbolTableReader.getType(node.name.token.value); + if (!type) { + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Unknown type: " + node.name.token.value, + }); + } + const structType = llvm.StructType.create( + this.context, + node.name.token.value + ); + const gomType = type.gomType as GomStructType; + const fields = Array.from(gomType.fields).map(([_key, fieldType]) => { + return this.mapGomTypeToLLVMType(fieldType); + }); + structType.setBody(fields); + + this.structTypes[type.name] = structType; + } + } + visitFunctionDefinition(node: NodeFunctionDefinition): void { this.symbolTableReader.enterScope(node.name.value); this.irScopeManager.enterScope(node.name.value); const returnType = this.mapGomTypeToLLVMType( - node.gomType.returnType as GomPrimitiveTypeOrAlias + (node.resultantType as GomFunctionType).returnType ); - const argsType = node.gomType.args.map((arg) => + const argsType = (node.resultantType as GomFunctionType).args.map((arg) => this.mapGomTypeToLLVMType(arg as GomPrimitiveTypeOrAlias) ); @@ -280,9 +309,7 @@ export class CodeGenerator extends BaseCodeGenerator { this.builder.SetInsertPoint(this.currentFunctionEntry); - const type = this.mapGomTypeToLLVMType( - decl.lhs.resultantType as GomPrimitiveTypeOrAlias - ); + const type = this.mapGomTypeToLLVMType(decl.lhs.resultantType); const alloca = this.builder.CreateAlloca( type, null, @@ -294,19 +321,11 @@ export class CodeGenerator extends BaseCodeGenerator { id.allocaInst = alloca; } - const rhsValue = this.visitExpression(decl.rhs); - - const allocaType = alloca.getAllocatedType(); - const rhsType = rhsValue.getType(); + const rhsValue = this.visitExpression(decl.rhs, decl.lhs); - if (allocaType.getTypeID() !== rhsType.getTypeID()) { - this.errorManager.throwCodegenError({ - loc: decl.loc, - message: `Type mismatch: ${allocaType} and ${rhsType}`, - }); + if (!type.isStructTy()) { + this.builder.CreateStore(rhsValue, alloca); } - - this.builder.CreateStore(rhsValue, alloca); } } @@ -454,7 +473,7 @@ export class CodeGenerator extends BaseCodeGenerator { } } - visitExpression(expr: NodeExpr): llvm.Value { + visitExpression(expr: NodeExpr, declLhs?: NodeTerm): llvm.Value { if (expr instanceof NodeAccess) { return this.visitAccess(expr); } else if (expr instanceof NodeBinaryOp) { @@ -465,6 +484,8 @@ export class CodeGenerator extends BaseCodeGenerator { return this.visitTerm(expr); } else if (expr instanceof NodeAssignment) { return this.visitAssignment(expr); + } else if (expr instanceof NodeStructInit) { + return this.visitStructInit(expr, declLhs); } else if (expr instanceof NodeExprBracketed) { return this.visitExpression(expr.expr); } @@ -486,6 +507,43 @@ export class CodeGenerator extends BaseCodeGenerator { return rhsValue; } + visitStructInit(node: NodeStructInit, declLhs?: NodeTerm): llvm.Value { + if (!declLhs) { + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Struct init without declaration", + }); + } + const structId = this.symbolTableReader.getIdentifier(declLhs.token.value); + if (!structId) { + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Unknown struct: " + node.structTypeName.token.value, + }); + } + + if (!structId.allocaInst) { + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Struct not allocated: " + node.structTypeName.token.value, + }); + } + const structAlloca = structId.allocaInst; + const structType = this.mapGomTypeToLLVMType(node.resultantType); + const index0 = this.builder.getInt32(0); + node.fields.forEach((field, i) => { + const fieldVal = this.visitExpression(field[1]); + const fieldPtr = this.builder.CreateGEP( + structType, + structAlloca, + [index0, this.builder.getInt32(i)], + "fieldptr" + ); + this.builder.CreateStore(fieldVal, fieldPtr); + }); + return structAlloca; + } + visitAccess(node: NodeAccess): llvm.Value { const idName = node.lhs.token.value; if (idName === "io" && node.rhs instanceof NodeCall) { @@ -523,6 +581,42 @@ export class CodeGenerator extends BaseCodeGenerator { const newline = this.globalStringPtrs["newline"]; this.builder.CreateCall(fn, [newline], "newline"); return this.builder.getInt32(0); + } else if ( + node.lhs.resultantType instanceof GomStructType && + node.rhs instanceof NodeTerm + ) { + const type = node.lhs.resultantType as GomStructType; + const structType = this.mapGomTypeToLLVMType(node.lhs.resultantType); + const struct = this.symbolTableReader.getIdentifier(idName); + if (!struct) { + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Unknown struct: " + idName, + }); + } + + if (!struct.allocaInst) { + this.errorManager.throwCodegenError({ + loc: node.loc, + message: "Struct not allocated: " + idName, + }); + } + + const index = this.builder.getInt32( + Array.from(type.fields.keys()).indexOf(node.rhs.token.value) + ); + + const ptr = this.builder.CreateGEP( + structType, + struct.allocaInst, + [this.builder.getInt32(0), index], + "fieldptr" + ); + return this.builder.CreateLoad( + this.mapGomTypeToLLVMType(node.rhs.resultantType), + ptr, + "fieldload" + ); } return this.builder.getInt32(0); diff --git a/src/lexer/tokens.ts b/src/lexer/tokens.ts index e89a15d..56d9ce5 100644 --- a/src/lexer/tokens.ts +++ b/src/lexer/tokens.ts @@ -17,9 +17,6 @@ export enum GomToken { // Primitive type BUILT_IN_TYPE = "built_in_type", - // Complex types - STRUCT = "struct", - // Symbols LPAREN = "(", RPAREN = ")", @@ -70,7 +67,6 @@ export const GOM_KEYWORDS = new Set([ "main", "true", "false", - "struct", ]); export const getKeywordType = (value: string): GomToken => { @@ -101,8 +97,6 @@ export const getKeywordType = (value: string): GomToken => { return GomToken.TRUE; case "false": return GomToken.FALSE; - case "struct": - return GomToken.STRUCT; default: return GomToken.IDENTIFIER; } diff --git a/src/parser/rd/index.ts b/src/parser/rd/index.ts index 4c89c2f..3e536aa 100644 --- a/src/parser/rd/index.ts +++ b/src/parser/rd/index.ts @@ -25,6 +25,7 @@ import { NodeProgram, NodeReturnStatement, NodeStatement, + NodeStructInit, NodeTerm, NodeTypeDefinition, } from "./nodes"; @@ -183,9 +184,9 @@ export class RecursiveDescentParser { parseTypeDefinition() { const loc = this.token.start; this.match(GomToken.TYPE); - const name = this.match(GomToken.IDENTIFIER); + const name = this.parseTerm(); this.match(GomToken.EQ); - const rhs = this.parseGomType(); + const rhs = this.parseGomType(name); this.match(GomToken.SEMICOLON); return new NodeTypeDefinition({ @@ -195,9 +196,9 @@ export class RecursiveDescentParser { }); } - parseGomType() { - if (this.peek(GomToken.STRUCT)) { - return this.parseStructType(); + parseGomType(typeName: NodeTerm) { + if (this.peek(GomToken.LBRACE)) { + return this.parseStructType(typeName); } else if ( this.peek(GomToken.IDENTIFIER) || this.peek(GomToken.BUILT_IN_TYPE) @@ -208,14 +209,13 @@ export class RecursiveDescentParser { throw new Error(`Unexpected token: ${this.token.value}`); } - parseStructType() { + parseStructType(typeName: NodeTerm) { const loc = this.token.start; - this.match(GomToken.STRUCT); this.match(GomToken.LBRACE); const fields = this.parseOneOrMore(this.parseStructTypeField); this.match(GomToken.RBRACE); - return new NodeGomTypeStruct({ fields, loc }); + return new NodeGomTypeStruct({ name: typeName, fields, loc }); } parseStructTypeField() { @@ -234,17 +234,17 @@ export class RecursiveDescentParser { const baseType = this.parseTerm() as NodeTerm; if (this.accept(GomToken.LBRACKET)) { - const size = this.match(GomToken.NUMLITERAL); + const size = this.parseTerm(); this.match(GomToken.RBRACKET); return new NodeGomTypeIdOrArray({ - id: baseType.token, + id: baseType, arrSize: size, loc: baseType.token.start, }); } return new NodeGomTypeIdOrArray({ - id: baseType.token, + id: baseType, loc: baseType.token.start, }); } @@ -274,7 +274,7 @@ export class RecursiveDescentParser { const loc = this.token.start; const name = this.parseTerm() as NodeTerm; this.match(GomToken.COLON); - const expectedType = this.match(GomToken.BUILT_IN_TYPE); // can be custom type + const expectedType = this.parseTerm(); this.matchOneOrNone(GomToken.COMMA); return new NodeArgumentItem({ @@ -429,7 +429,7 @@ export class RecursiveDescentParser { if (this.buffer[1].type === GomToken.EQ) { return this.parseAssignment(); } else { - return this.parseComparison(); + return this.parseStructInit(); } } else { return this.parseComparison(); @@ -454,6 +454,26 @@ export class RecursiveDescentParser { return new NodeAccess({ lhs, rhs, loc }); } + parseStructInit(): NodeExpr { + if (this.buffer[1].type === GomToken.LBRACE) { + const loc = this.token.start; + const structTypeName = this.parseTerm(); + this.match(GomToken.LBRACE); + const fields: [NodeTerm, NodeExpr][] = this.parseOneOrMore(() => { + const name = this.parseTerm(); + this.match(GomToken.COLON); + const value = this.parseExpression(); + if (!this.peek(GomToken.RBRACE)) this.match(GomToken.COMMA); + return [name, value]; + }); + this.match(GomToken.RBRACE); + + return new NodeStructInit({ structTypeName, fields, loc }); + } + + return this.parseComparison(); + } + parseComparison(): NodeExpr { const loc = this.token.start; let lhs = this.parseSum(); diff --git a/src/parser/rd/modules.ts b/src/parser/rd/modules.ts index 1f1c81f..d9fa069 100644 --- a/src/parser/rd/modules.ts +++ b/src/parser/rd/modules.ts @@ -54,7 +54,6 @@ export class GomModule { } private parseModule(): NodeProgram { - console.log("Parsing module...", this.src); const lexer = new Lexer(this.src, this.errorManager); const parser = new ModuleParser(lexer); diff --git a/src/parser/rd/nodes/index.ts b/src/parser/rd/nodes/index.ts index 199e849..65559f3 100644 --- a/src/parser/rd/nodes/index.ts +++ b/src/parser/rd/nodes/index.ts @@ -1,8 +1,10 @@ import { Token } from "../../../lexer"; import { GomToken } from "../../../lexer/tokens"; import { + GomArrayType, GomFunctionType, GomPrimitiveTypeOrAlias, + GomStructType, GomType, } from "../../../semantics/type"; import { AbstractNode, Node, NodeType } from "../tree"; @@ -81,7 +83,7 @@ export class NodeImportDeclaration extends AbstractNode { export class NodeTypeDefinition extends AbstractNode { type: NodeType; - name: Token; + name: NodeTerm; rhs: NodeGomType; children: Node[]; @@ -90,7 +92,7 @@ export class NodeTypeDefinition extends AbstractNode { rhs, loc, }: { - name: Token; + name: NodeTerm; rhs: NodeGomType; loc: number; }) { @@ -110,7 +112,7 @@ export class NodeFunctionDefinition extends AbstractNode { args: NodeArgumentItem[]; returnType?: NodeFunctionReturnType; body: NodeStatement[]; - gomType: GomFunctionType; + resultantType: GomType; constructor({ loc, @@ -133,12 +135,7 @@ export class NodeFunctionDefinition extends AbstractNode { this.returnType = returnType; this.body = body; this.children = formChildrenArray(args, returnType, body); - this.gomType = new GomFunctionType( - args.map((arg) => arg.gomType), - returnType - ? new GomPrimitiveTypeOrAlias(returnType.returnType.value) - : new GomPrimitiveTypeOrAlias("void") - ); + this.resultantType = new GomPrimitiveTypeOrAlias("void"); } } @@ -312,9 +309,9 @@ export class NodeExpressionStatement extends AbstractNode { export class NodeArgumentItem extends AbstractNode { type: NodeType; name: NodeTerm; - expectedType: Token; + expectedType: NodeTerm; children: Node[]; - gomType: GomType; + resultantType: GomType; constructor({ name, @@ -322,7 +319,7 @@ export class NodeArgumentItem extends AbstractNode { loc, }: { name: NodeTerm; - expectedType: Token; + expectedType: NodeTerm; loc: number; }) { super(); @@ -331,7 +328,7 @@ export class NodeArgumentItem extends AbstractNode { this.name = name; this.expectedType = expectedType; this.children = []; - this.gomType = new GomPrimitiveTypeOrAlias(expectedType.value); + this.resultantType = new GomPrimitiveTypeOrAlias("void"); } } @@ -352,8 +349,9 @@ export class NodeFunctionReturnType extends AbstractNode { export type NodeGomType = NodeGomTypeIdOrArray | NodeGomTypeStruct; export class NodeGomTypeIdOrArray extends AbstractNode { type: NodeType; - id: Token; - arrSize?: Token; + id: NodeTerm; + arrSize?: NodeTerm; + gomType: GomType; children: Node[]; constructor({ @@ -361,8 +359,8 @@ export class NodeGomTypeIdOrArray extends AbstractNode { arrSize, loc, }: { - id: Token; - arrSize?: Token; + id: NodeTerm; + arrSize?: NodeTerm; loc: number; }) { super(); @@ -370,6 +368,9 @@ export class NodeGomTypeIdOrArray extends AbstractNode { this.loc = loc; this.id = id; this.arrSize = arrSize; + this.gomType = arrSize + ? new GomArrayType(id.resultantType, Number(arrSize.token.value)) + : id.resultantType; this.children = []; } } @@ -377,11 +378,14 @@ export class NodeGomTypeIdOrArray extends AbstractNode { export class NodeGomTypeStruct extends AbstractNode { type: NodeType; fields: NodeGomTypeStructField[]; + gomType: GomStructType; constructor({ + name, fields, loc, }: { + name: NodeTerm; fields: NodeGomTypeStructField[]; loc: number; }) { @@ -389,6 +393,13 @@ export class NodeGomTypeStruct extends AbstractNode { this.type = NodeType.GOM_TYPE_STRUCT; this.loc = loc; this.fields = fields; + this.gomType = new GomStructType( + name.token.value, + fields.reduce((acc, field) => { + acc.set(field.name.value, field.fieldType.gomType); + return acc; + }, new Map()) + ); this.children = formChildrenArray(fields); } } @@ -396,7 +407,7 @@ export class NodeGomTypeStruct extends AbstractNode { export class NodeGomTypeStructField extends AbstractNode { type: NodeType; name: Token; - fieldType: NodeGomTypeIdOrArray; + fieldType: NodeGomType; children: Node[]; constructor({ @@ -405,7 +416,7 @@ export class NodeGomTypeStructField extends AbstractNode { loc, }: { name: Token; - fieldType: NodeGomTypeIdOrArray; + fieldType: NodeGomType; loc: number; }) { super(); @@ -421,6 +432,7 @@ export type NodeExpr = NodeExprBasic | NodeExprBracketed; export type NodeExprBasic = | NodeAssignment + | NodeStructInit | NodeAccess | NodeCall | NodeBinaryOp @@ -451,6 +463,37 @@ export class NodeAssignment extends AbstractNode { } } +export class NodeStructInit extends AbstractNode { + type: NodeType; + structTypeName: NodeTerm; + fields: [NodeTerm, NodeExpr][]; + resultantType: GomStructType; + + constructor({ + structTypeName, + fields, + loc, + }: { + structTypeName: NodeTerm; + fields: [NodeTerm, NodeExpr][]; + loc: number; + }) { + super(); + this.type = NodeType.STRUCT_INIT; + this.loc = loc; + this.structTypeName = structTypeName; + this.fields = fields; + this.resultantType = new GomStructType( + structTypeName.token.value, + fields.reduce((acc, [field, expr]) => { + acc.set(field.token.value, expr.resultantType); + return acc; + }, new Map()) + ); + this.children = formChildrenArray(fields.map(([, expr]) => expr)); + } +} + export class NodeBinaryOp extends AbstractNode { type: NodeType; lhs: NodeExpr; @@ -538,7 +581,7 @@ export class NodeExprBracketed extends AbstractNode { type: NodeType; expr: NodeExpr; children: Node[]; - resultantType: GomPrimitiveTypeOrAlias; + resultantType: GomType; constructor({ expr, loc }: { expr: NodeExpr; loc: number }) { super(); @@ -554,8 +597,8 @@ export class NodeTerm extends AbstractNode { type: NodeType; token: Token; children: Node[]; - gomType: GomPrimitiveTypeOrAlias; - resultantType: GomPrimitiveTypeOrAlias; + gomType: GomType; + resultantType: GomType; constructor(token: Token) { super(); @@ -579,7 +622,7 @@ export class NodeTerm extends AbstractNode { ) { return new GomPrimitiveTypeOrAlias("bool"); } else if (this.token.type === GomToken.BUILT_IN_TYPE) { - return new GomPrimitiveTypeOrAlias(`primitive_type@@${this.token.value}`); + return new GomPrimitiveTypeOrAlias(this.token.value); } throw new Error(`Cannot determine type for token: ${this.token.type}`); diff --git a/src/parser/rd/tree.ts b/src/parser/rd/tree.ts index 7cd1482..42ce60c 100644 --- a/src/parser/rd/tree.ts +++ b/src/parser/rd/tree.ts @@ -48,6 +48,7 @@ export enum NodeType { EXPR_BASIC = "EXPR_BASIC", EXPR_BRACKETED = "EXPR_BRACKETED", ASSIGNMENT = "ASSIGNMENT", + STRUCT_INIT = "STRUCT_INIT", ACCESS = "ACCESS", CALL = "CALL", COMPARISON = "COMPARISON", diff --git a/src/parser/rd/visitor.ts b/src/parser/rd/visitor.ts index 8ae9f7c..249a538 100644 --- a/src/parser/rd/visitor.ts +++ b/src/parser/rd/visitor.ts @@ -9,12 +9,14 @@ import { NodeForStatement, NodeFunctionDefinition, NodeFunctionReturnType, + NodeGomTypeStructField, NodeIfStatement, NodeImportDeclaration, NodeLetStatement, NodeMainFunction, NodeProgram, NodeReturnStatement, + NodeStructInit, NodeTerm, NodeTypeDefinition, } from "./nodes"; @@ -89,6 +91,12 @@ export class SimpleVisitor implements Visitor { case NodeType.ASSIGNMENT: this.visitAssignment(node as NodeAssignment); return; + case NodeType.STRUCT_INIT: + this.visitStructInit(node as NodeStructInit); + return; + case NodeType.GOM_TYPE_STRUCT_FIELD: + this.visitStructField(node as NodeGomTypeStructField); + return; case NodeType.COMPARISON: case NodeType.SUM: case NodeType.QUOT: @@ -155,6 +163,12 @@ export class SimpleVisitor implements Visitor { visitAssignment(node: NodeAssignment) { this.visitChildren(node); } + visitStructInit(node: NodeStructInit) { + this.visitChildren(node); + } + visitStructField(node: NodeGomTypeStructField) { + this.visitChildren(node); + } visitBinaryOp(node: NodeBinaryOp) { this.visitChildren(node); } diff --git a/src/semantics/index.ts b/src/semantics/index.ts index 26d78b7..78524cb 100644 --- a/src/semantics/index.ts +++ b/src/semantics/index.ts @@ -5,17 +5,25 @@ import { NodeExpr, NodeForStatement, NodeFunctionDefinition, + NodeGomTypeStruct, + NodeGomTypeStructField, NodeIfStatement, NodeImportDeclaration, NodeLetStatement, NodeMainFunction, NodeProgram, + NodeStructInit, NodeTerm, NodeTypeDefinition, } from "../parser/rd/nodes"; import { ScopeManager, SymbolTableReader } from "./scope"; import { SimpleVisitor } from "../parser/rd/visitor"; -import { GomFunctionType, GomPrimitiveTypeOrAlias, GomType } from "./type"; +import { + GomFunctionType, + GomPrimitiveTypeOrAlias, + GomStructType, + GomType, +} from "./type"; import { GomErrorManager } from "../util/error"; import { GomToken } from "../lexer/tokens"; import { GomModule } from "../parser/rd/modules"; @@ -54,9 +62,9 @@ export class SemanticAnalyzer extends SimpleVisitor { module.getAllExports().forEach((exp) => { if (exp instanceof NodeFunctionDefinition) { - this.scopeManager.putIdentifier(exp.name.value, exp, exp.gomType); + this.scopeManager.putIdentifier(exp.name.value, exp, exp.resultantType); } else if (exp instanceof NodeTypeDefinition) { - this.scopeManager.putType(exp.name.value, exp); + this.scopeManager.putType(exp.name.token.value, exp); } else if (exp instanceof NodeLetStatement) { exp.decls.forEach((decl) => { this.scopeManager.putIdentifier( @@ -71,13 +79,44 @@ export class SemanticAnalyzer extends SimpleVisitor { } visitFunctionDefinition(node: NodeFunctionDefinition): void { - this.scopeManager.putIdentifier(node.name.value, node, node.gomType); + let returnType: GomType; + + 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, + }); + } + + returnType = type.gomType; + } else { + returnType = new GomPrimitiveTypeOrAlias("void"); + } + + let argTypes: GomType[] = []; + node.args.forEach((arg) => { + const argType = this.scopeManager.getType(arg.expectedType.token.value); + if (!argType) { + this.errorManager.throwTypeError({ + message: `Type ${arg.expectedType.token.value} not found`, + loc: arg.expectedType.loc, + }); + } + arg.resultantType = argType.gomType; + argTypes.push(argType.gomType); + }); + + const fnType = new GomFunctionType(argTypes, returnType); + node.resultantType = fnType; + this.scopeManager.putIdentifier(node.name.value, node, fnType); this.scopeManager.beginScope(node.name.value); node.args.forEach((arg) => { this.scopeManager.putIdentifier( arg.name.token.value, arg.name, - arg.gomType + arg.resultantType ); }); node.body.forEach((stmt) => this.visit(stmt)); @@ -171,7 +210,9 @@ export class SemanticAnalyzer extends SimpleVisitor { } visitTypeDefinition(node: NodeTypeDefinition): void { - this.scopeManager.putType(node.name.value, node); + this.scopeManager.putType(node.name.token.value, node); + const typeResolver = new TypeResolver(this.scopeManager, this.errorManager); + node.accept(typeResolver); } } @@ -194,11 +235,128 @@ class TypeResolver extends SimpleVisitor { return this.currentType; } + visitStructInit(node: NodeStructInit): void { + const structType = this.symbolTableReader.getType( + node.structTypeName.token.value + ); + if (!structType) { + this.errorManager.throwTypeError({ + message: `Type ${node.structTypeName.token.value} not found`, + loc: node.loc, + }); + } + const gomType = structType.gomType; + if (!(gomType instanceof GomStructType)) { + this.errorManager.throwTypeError({ + message: `Type ${node.structTypeName.token.value} cannot be initialized as a struct`, + loc: node.loc, + }); + } + + if (node.fields.length !== gomType.fields.size) { + this.errorManager.throwTypeError({ + message: `Field count mismatch: expected ${gomType.fields.size}, got ${node.fields.length}`, + loc: node.loc, + }); + } + + for (let i = 0; i < node.fields.length; i++) { + const field = node.fields[i]; + const fieldName = field[0], + fieldExpr = field[1]; + if (!gomType.fields.has(fieldName.token.value)) { + this.errorManager.throwTypeError({ + message: `Field ${fieldName.token.value} not found in struct ${node.structTypeName.token.value}`, + loc: fieldName.loc, + }); + } + + this.visit(fieldExpr); + const fieldType = this.currentType; + if (!fieldType?.isEqual(gomType.fields.get(fieldName.token.value)!)) { + this.errorManager.throwTypeError({ + message: `Type mismatch: expected ${gomType.fields + .get(fieldName.token.value)! + .toStr()}, got ${fieldType?.toStr()}`, + loc: fieldExpr.loc, + }); + } + + gomType.fields.set(fieldName.token.value, fieldType); + } + + node.resultantType = gomType; + + this.currentType = gomType; + } + + visitTypeDefinition(node: NodeTypeDefinition): void { + const type = this.symbolTableReader.getType(node.name.token.value); + if (!type) { + this.errorManager.throwTypeError({ + message: `Type ${node.name.token.value} not found`, + loc: node.loc, + }); + } + + const gomType = type.gomType; + if (gomType instanceof GomStructType) { + Array.from(gomType.fields.entries()).forEach(([key, field]) => { + const _field = field as GomPrimitiveTypeOrAlias; + if (_field.typeString.startsWith("resolve_type@@")) { + const idName = _field.toStr().replace("resolve_type@@", ""); + const id = this.symbolTableReader.getType(idName); + if (id) { + gomType.fields.set(key, id.gomType); + } else { + this.errorManager.throwTypeError({ + message: `Type ${idName} not found`, + loc: node.loc, + }); + } + } + }); + } else if (gomType instanceof GomPrimitiveTypeOrAlias) { + if (gomType.typeString.startsWith("resolve_type@@")) { + const idName = gomType.typeString.replace("resolve_type@@", ""); + const id = this.symbolTableReader.getType(idName); + if (id) { + node.rhs.gomType = id.gomType; + } else { + this.errorManager.throwTypeError({ + message: `Type ${idName} not found`, + loc: node.loc, + }); + } + } + } + } + visitAccess(node: NodeAccess): void { const idName = node.lhs.token.value; const id = this.symbolTableReader.getIdentifier(idName); if (id && !id.isFunction()) { - this.visit(node.rhs); + // ensure that node.lhs is a struct + // only support member access for structs for now + if (id.type instanceof GomStructType) { + node.lhs.resultantType = id.type; + if (node.rhs instanceof NodeTerm) { + const structType = id.type; + const field = structType.fields.get(node.rhs.token.value); + if (field) { + node.rhs.resultantType = field; + node.resultantType = field; + this.currentType = field; + } else { + this.errorManager.throwTypeError({ + message: `Field ${node.rhs.token.value} not found in struct ${idName}`, + loc: node.rhs.loc, + }); + } + } + } else { + this.visit(node.rhs); + } } else { if (idName === "io") { // skip for now until modules are implemented @@ -273,32 +431,34 @@ class TypeResolver extends SimpleVisitor { visitCall(node: NodeCall): void { const fnName = (node.id as NodeTerm).token.value; const fn = this.symbolTableReader.getFunction(fnName); - if (fn && fn.node.gomType instanceof GomFunctionType) { + if (fn && fn.node.resultantType instanceof GomFunctionType) { const args = node.args.map((arg) => this.resolveType(arg)); - if (args.length !== fn.node.gomType.args.length) { + if (args.length !== fn.node.resultantType.args.length) { this.errorManager.throwTypeError({ message: `Argument count mismatch: expected ${ - fn.node.gomType.args.length + fn.node.resultantType.args.length }, got ${ args.length - } for function ${fnName} of type ${fn.node.gomType.toStr()}`, + } for function ${fnName} of type ${fn.node.resultantType.toStr()}`, loc: node.loc, }); } for (let i = 0; i < args.length; i++) { - if (!args[i]?.isEqual(fn.node.gomType.args[i])) { + if (!args[i]?.isEqual(fn.node.resultantType.args[i])) { this.errorManager.throwTypeError({ - message: `Type mismatch: expected ${fn.node.gomType.args[i]}, got ${ + message: `Type mismatch: expected ${ + fn.node.resultantType.args[i] + }, got ${ args[i] - } for argument ${i} of function ${fnName} of type ${fn.node.gomType.toStr()}`, + } for argument ${i} of function ${fnName} of type ${fn.node.resultantType.toStr()}`, loc: node.loc, }); } } - node.resultantType = fn.node.gomType.returnType; - this.currentType = fn.node.gomType.returnType; + node.resultantType = fn.node.resultantType.returnType; + this.currentType = fn.node.resultantType.returnType; } else { if (fnName === "log") { // skip for now until modules are implemented @@ -317,21 +477,23 @@ class TypeResolver extends SimpleVisitor { visitTerm(node: NodeTerm): void { const type = node.gomType; - if (type.typeString.startsWith("resolve_type@@")) { - const idName = type.typeString.replace("resolve_type@@", ""); - const id = this.symbolTableReader.getIdentifier(idName); - if (id && !id.isFunction()) { - node.resultantType = id.type as GomPrimitiveTypeOrAlias; - this.currentType = id.type; + if (type instanceof GomPrimitiveTypeOrAlias) { + if (type.typeString.startsWith("resolve_type@@")) { + const idName = type.typeString.replace("resolve_type@@", ""); + const id = this.symbolTableReader.getIdentifier(idName); + if (id && !id.isFunction()) { + node.resultantType = id.type; + this.currentType = id.type; + } else { + this.errorManager.throwTypeError({ + message: `Identifier ${idName} not found`, + loc: node.loc, + }); + } } else { - this.errorManager.throwTypeError({ - message: `Identifier ${idName} not found`, - loc: node.loc, - }); + node.resultantType = type; + this.currentType = type; } - } else { - node.resultantType = type; - this.currentType = type; } } } diff --git a/src/semantics/scope.ts b/src/semantics/scope.ts index 9bedfce..49b2ae9 100644 --- a/src/semantics/scope.ts +++ b/src/semantics/scope.ts @@ -2,17 +2,19 @@ import llvm from "llvm-bindings"; import { NodeExpr, NodeFunctionDefinition, + NodeGomTypeIdOrArray, NodeGomTypeStruct, NodeTerm, NodeTypeDefinition, } from "../parser/rd/nodes"; import { GomInternalError, SyntaxError } from "../util/error"; import { - GomArrayType, GomPrimitiveTypeOrAlias, + GomPrimitiveTypeOrAliasValue, GomStructType, GomType, } from "./type"; +import { GOM_BUILT_IN_TYPES, GomToken } from "../lexer/tokens"; class SymbolTableNode { private children: SymbolTableNode[] = []; @@ -47,7 +49,7 @@ class SymbolTableNode { class TypeEntry { name: string; node: NodeTypeDefinition; - gomType: GomPrimitiveTypeOrAlias | GomStructType; + gomType: GomType; constructor(name: string, node: NodeTypeDefinition) { this.name = name; @@ -55,22 +57,19 @@ class TypeEntry { this.gomType = node.rhs instanceof NodeGomTypeStruct ? new GomStructType( + name, node.rhs.fields.reduce((acc, field) => { - const arrSize = field.fieldType.arrSize; - if (arrSize) { - acc[field.name.value] = new GomArrayType( - new GomPrimitiveTypeOrAlias(field.fieldType.id.value), - Number(arrSize.value) - ); - } else { - acc[field.name.value] = new GomPrimitiveTypeOrAlias( - field.fieldType.id.value - ); + 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; - }, {} as Record) + }, new Map()) ) - : new GomPrimitiveTypeOrAlias(node.name.value); + : new GomPrimitiveTypeOrAlias(node.name.token.value); } getValue() { @@ -199,9 +198,36 @@ export class Scope { export class ScopeManager { private currentSymbolTableNode: SymbolTableNode; + private primitiveTypes: Record = {}; constructor() { this.currentSymbolTableNode = new SymbolTableNode("root", new Scope()); + this.setPrimitiveTypes(); + } + + private setPrimitiveTypes() { + GOM_BUILT_IN_TYPES.forEach((type) => { + const fakeNode = new NodeTypeDefinition({ + name: new NodeTerm({ + value: type, + start: 0, + end: 0, + type: GomToken.BUILT_IN_TYPE, + }), + rhs: new NodeGomTypeIdOrArray({ + id: new NodeTerm({ + value: type, + start: 0, + end: 0, + type: GomToken.BUILT_IN_TYPE, + }), + arrSize: undefined, + loc: 0, + }), + loc: 0, + }); + this.primitiveTypes[type] = new TypeEntry(type, fakeNode); + }); } beginScope(name: string) { @@ -251,6 +277,9 @@ export class ScopeManager { } getType(name: string) { + if (this.primitiveTypes[name]) { + return this.primitiveTypes[name]; + } return this.getCurrentScope().getType(name); } diff --git a/src/semantics/type.ts b/src/semantics/type.ts index 00cea14..397bb42 100644 --- a/src/semantics/type.ts +++ b/src/semantics/type.ts @@ -1,7 +1,7 @@ /** * Gom type can be: * - Primitive, e.g. int, bool, float, str, void - * - Struct e.g. struct { x: int, y: int } + * - Struct e.g. { x: int, y: int } * - Custom, e.g. type Number = int * - Function, e.g. fn add(a: int, b: int): int * @@ -15,10 +15,14 @@ export enum GomTypeKind { Function = "Function", } -export interface GomType { - kind: GomTypeKind; - toStr(): string; - isEqual(other: GomType): boolean; +export class GomType { + kind: GomTypeKind = GomTypeKind.PrimitiveOrAlias; + toStr(): string { + return "gomType"; + } + isEqual(other: GomType): boolean { + return false; + } } export type GomPrimitiveTypeOrAliasValue = @@ -29,11 +33,12 @@ export type GomPrimitiveTypeOrAliasValue = | "void" | string; -export class GomPrimitiveTypeOrAlias implements GomType { +export class GomPrimitiveTypeOrAlias extends GomType { kind: GomTypeKind; typeString: GomPrimitiveTypeOrAliasValue; constructor(typeString: GomPrimitiveTypeOrAliasValue) { + super(); this.kind = GomTypeKind.PrimitiveOrAlias; this.typeString = typeString; } @@ -50,12 +55,13 @@ export class GomPrimitiveTypeOrAlias implements GomType { } } -export class GomArrayType implements GomType { +export class GomArrayType extends GomType { kind: GomTypeKind; elementType: GomType; size: number; constructor(elementType: GomType, size: number) { + super(); this.kind = GomTypeKind.Array; this.elementType = elementType; this.size = size; @@ -75,11 +81,14 @@ export class GomArrayType implements GomType { } } -export class GomStructType implements GomType { +export class GomStructType extends GomType { kind: GomTypeKind; - fields: Record; + name: string; + fields: Map; - constructor(fields: Record) { + constructor(name: string, fields: Map) { + super(); + this.name = name; this.kind = GomTypeKind.Struct; this.fields = fields; } @@ -91,12 +100,12 @@ export class GomStructType implements GomType { } isEqual(other: GomStructType): boolean { - if (Object.keys(this.fields).length !== Object.keys(other.fields).length) { + if (this.fields.size !== other.fields.size) { return false; } for (const [name, type] of Object.entries(this.fields)) { - if (!other.fields[name] || !type.isEqual(other.fields[name])) { + if (!other.fields.has(name) || !type.isEqual(other.fields.get(name))) { return false; } } @@ -105,12 +114,13 @@ export class GomStructType implements GomType { } } -export class GomFunctionType implements GomType { +export class GomFunctionType extends GomType { kind: GomTypeKind; args: GomType[]; returnType: GomType; constructor(args: GomType[], returnType: GomType) { + super(); this.kind = GomTypeKind.Function; this.args = args; this.returnType = returnType; diff --git a/test_2.ll b/test_2.ll deleted file mode 100644 index 42ecd48..0000000 --- a/test_2.ll +++ /dev/null @@ -1,60 +0,0 @@ -; ModuleID = 'mod' -source_filename = "mod" - -@GLOBAL = external global i32 -@fmt.int = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 -@fmt.float = private unnamed_addr constant [4 x i8] c"%f\0A\00", align 1 -@fmt.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 -@fmt.bool = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 -@calltmp0 = private unnamed_addr constant [6 x i8] c"Sum: \00", align 1 - -define i32 @square(i32 %0) { -entry: - %1 = alloca i32, align 4 - store i32 %0, i32* %1, align 4 - %x.load = load i32, i32* %1, align 4 - %x.load1 = load i32, i32* %1, align 4 - %multmp = mul i32 %x.load, %x.load1 - ret i32 %multmp -} - -define i32 @add(i32 %0, i32 %1) { -entry: - %2 = alloca i32, align 4 - store i32 %0, i32* %2, align 4 - %3 = alloca i32, align 4 - store i32 %1, i32* %3, align 4 - %a.load = load i32, i32* %2, align 4 - %b.load = load i32, i32* %3, align 4 - %addtmp = add i32 %a.load, %b.load - ret i32 %addtmp -} - -define void @main() { -entry: - %a = alloca i32, align 4 - store i32 3, i32* %a, align 4 - %b = alloca i32, align 4 - store i32 2, i32* %b, align 4 - %b.load = load i32, i32* %b, align 4 - %divtmp = sdiv i32 %b.load, 2 - %addtmp = add i32 1, %divtmp - %calltmp = call i32 @add(i32 1, i32 %addtmp) - store i32 2, i32* %a, align 4 - %sq = alloca i32, align 4 - %a.load = load i32, i32* %a, align 4 - %calltmp1 = call i32 @square(i32 %a.load) - store i32 %calltmp1, i32* %sq, align 4 - %i = alloca i32, align 4 - store i32 3, i32* %i, align 4 - %i.load = load i32, i32* %i, align 4 - %calltmp2 = call i32 @add(i32 %i.load, i32 1) - %calltmp0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @calltmp0, i32 0, i32 0)) - %calltmp13 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @fmt.int, i32 0, i32 0), i32 %calltmp2) - %i.load4 = load i32, i32* %i, align 4 - %addtmp5 = add i32 %i.load4, 1 - store i32 %addtmp5, i32* %i, align 4 - ret void -} - -declare i32 @printf(i8*, ...) diff --git a/tree.json b/tree.json index 8ab1764..42ed419 100644 --- a/tree.json +++ b/tree.json @@ -13,299 +13,1363 @@ } } ], - "typeDefinitions": [], - "globalVariables": [], + "typeDefinitions": [ + { + "type": "TYPE_DEFINITION", + "loc": 12, + "name": { + "type": "TERM", + "loc": 17, + "token": { + "type": "identifier", + "value": "Point", + "start": 17, + "end": 21 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + } + }, + "rhs": { + "type": "GOM_TYPE_STRUCT", + "loc": 25, + "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" + } + }, + "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" + } + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + } + } + ], + "gomType": { + "kind": "Struct", + "name": "Point", + "fields": {} + } + } + }, + { + "type": "TYPE_DEFINITION", + "loc": 54, + "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" + } + }, + "rhs": { + "type": "GOM_TYPE_STRUCT", + "loc": 66, + "fields": [ + { + "type": "GOM_TYPE_STRUCT_FIELD", + "loc": 72, + "name": { + "type": "identifier", + "value": "p1", + "start": 72, + "end": 73 + }, + "fieldType": { + "type": "GOM_TYPE_ID_OR_ARRAY", + "loc": 76, + "id": { + "type": "TERM", + "loc": 76, + "token": { + "type": "identifier", + "value": "Point", + "start": 76, + "end": 80 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + } + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + } + } + }, + { + "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": { + "type": "TERM", + "loc": 91, + "token": { + "type": "identifier", + "value": "Point", + "start": 91, + "end": 95 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + } + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + } + } + } + ], + "gomType": { + "kind": "Struct", + "name": "Line", + "fields": {} + } + } + } + ], + "globalVariables": [ + { + "type": "LET_STATEMENT", + "loc": 101, + "decls": [ + { + "type": "ASSIGNMENT", + "loc": 105, + "lhs": { + "type": "TERM", + "loc": 105, + "token": { + "type": "identifier", + "value": "GLOBAL", + "start": 105, + "end": 110 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@GLOBAL" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "rhs": { + "type": "TERM", + "loc": 114, + "token": { + "type": "numliteral", + "value": "1", + "start": 114, + "end": 114 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "void" + } + } + ] + } + ], "functionDeclarations": [ { "type": "FUNCTION_DEFINITION", - "loc": 12, + "loc": 118, "name": { "type": "identifier", - "value": "power_n", - "start": 15, - "end": 21 + "value": "square", + "start": 121, + "end": 126 }, "args": [ { "type": "ARGUMENT_ITEM", - "loc": 23, + "loc": 128, "name": { "type": "TERM", - "loc": 23, + "loc": 128, + "token": { + "type": "identifier", + "value": "x", + "start": 128, + "end": 128 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@x" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@x" + } + }, + "expectedType": { + "type": "TERM", + "loc": 131, + "token": { + "type": "built_in_type", + "value": "int", + "start": 131, + "end": 133 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + } + ], + "returnType": { + "type": "FUNCTION_RETURN_TYPE", + "loc": 135, + "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": "TERM", + "loc": 171, + "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 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "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" + } + } + ], + "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, + "lhs": { + "type": "TERM", + "loc": 205, + "token": { + "type": "identifier", + "value": "a", + "start": 205, + "end": 205 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@a" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "op": { + "type": "+", + "value": "+", + "start": 207, + "end": 207 + }, + "rhs": { + "type": "TERM", + "loc": 209, + "token": { + "type": "identifier", + "value": "b", + "start": 209, + "end": 209 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@b" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "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": "x", - "start": 23, - "end": 23 + "value": "Point", + "start": 231, + "end": 235 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@Point" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@Point" } }, - "expectedType": { - "type": "built_in_type", - "value": "int", - "start": 26, - "end": 28 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "resultantType": { + "kind": "Struct", + "name": "Point", + "fields": {} } }, { "type": "ARGUMENT_ITEM", - "loc": 31, + "loc": 238, "name": { "type": "TERM", - "loc": 31, + "loc": 238, "token": { "type": "identifier", - "value": "n", - "start": 31, - "end": 31 + "value": "p2", + "start": 238, + "end": 239 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@n" + "typeString": "resolve_type@@p2" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@n" + "typeString": "resolve_type@@p2" } }, "expectedType": { - "type": "built_in_type", - "value": "int", - "start": 34, - "end": 36 + "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" + } }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "resultantType": { + "kind": "Struct", + "name": "Point", + "fields": {} } } ], "returnType": { "type": "FUNCTION_RETURN_TYPE", - "loc": 38, + "loc": 248, "returnType": { "type": "built_in_type", "value": "int", - "start": 40, - "end": 42 + "start": 250, + "end": 252 } }, "body": [ { - "type": "IF_STATEMENT", - "loc": 50, - "conditionExpr": { - "type": "EXPR_BRACKETED", - "loc": 53, - "expr": { - "type": "COMPARISON", - "loc": 54, - "lhs": { + "type": "RETURN_STATEMENT", + "loc": 260, + "expr": { + "type": "SUM", + "loc": 267, + "lhs": { + "type": "CALL", + "loc": 267, + "id": { "type": "TERM", - "loc": 54, + "loc": 267, "token": { "type": "identifier", - "value": "n", - "start": 54, - "end": 54 + "value": "square", + "start": 267, + "end": 272 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@n" + "typeString": "resolve_type@@square" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@square" + } + }, + "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 + }, + "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" + } + } + ], + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + } + } + ], + "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": [ + { + "type": "ASSIGNMENT", + "loc": 333, + "lhs": { + "type": "TERM", + "loc": 333, + "token": { + "type": "identifier", + "value": "p1", + "start": 333, + "end": 334 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@p1" + }, + "resultantType": { + "kind": "Struct", + "name": "Point", + "fields": {} + } + }, + "rhs": { + "type": "STRUCT_INIT", + "loc": 338, + "structTypeName": { + "type": "TERM", + "loc": 338, + "token": { + "type": "identifier", + "value": "Point", + "start": 338, + "end": 342 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@Point" } }, - "op": { - "type": "==", - "value": "==", - "start": 56, - "end": 57 + "fields": [ + [ + { + "type": "TERM", + "loc": 346, + "token": { + "type": "identifier", + "value": "x", + "start": 346, + "end": 346 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@x" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@x" + } + }, + { + "type": "TERM", + "loc": 349, + "token": { + "type": "numliteral", + "value": "1", + "start": 349, + "end": 349 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + } + ], + [ + { + "type": "TERM", + "loc": 352, + "token": { + "type": "identifier", + "value": "y", + "start": 352, + "end": 352 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@y" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@y" + } + }, + { + "type": "TERM", + "loc": 355, + "token": { + "type": "numliteral", + "value": "2", + "start": 355, + "end": 355 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + } + ] + ], + "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" }, - "rhs": { + "resultantType": { + "kind": "Struct", + "name": "Point", + "fields": {} + } + }, + "rhs": { + "type": "STRUCT_INIT", + "loc": 365, + "structTypeName": { "type": "TERM", - "loc": 59, + "loc": 365, "token": { - "type": "numliteral", - "value": "0", - "start": 59, - "end": 59 + "type": "identifier", + "value": "Point", + "start": 365, + "end": 369 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@Point" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "resolve_type@@Point" } }, + "fields": [ + [ + { + "type": "TERM", + "loc": 373, + "token": { + "type": "identifier", + "value": "x", + "start": 373, + "end": 373 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@x" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@x" + } + }, + { + "type": "TERM", + "loc": 376, + "token": { + "type": "numliteral", + "value": "3", + "start": 376, + "end": 376 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + } + ], + [ + { + "type": "TERM", + "loc": 379, + "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 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } + } + ] + ], "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "bool" + "kind": "Struct", + "name": "Point", + "fields": {} } }, "resultantType": { "kind": "PrimitiveOrAlias", "typeString": "void" } - }, - "body": [ - { - "type": "RETURN_STATEMENT", - "loc": 72, - "expr": { - "type": "TERM", - "loc": 79, - "token": { - "type": "numliteral", - "value": "1", - "start": 79, - "end": 79 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - } - ] - }, - { - "type": "RETURN_STATEMENT", - "loc": 92, - "expr": { - "type": "QUOT", - "loc": 99, + } + ] + }, + { + "type": "LET_STATEMENT", + "loc": 391, + "decls": [ + { + "type": "ASSIGNMENT", + "loc": 395, "lhs": { "type": "TERM", - "loc": 99, + "loc": 395, "token": { "type": "identifier", - "value": "x", - "start": 99, - "end": 99 + "value": "d", + "start": 395, + "end": 395 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@d" }, "resultantType": { "kind": "PrimitiveOrAlias", "typeString": "int" } }, - "op": { - "type": "*", - "value": "*", - "start": 101, - "end": 101 - }, "rhs": { "type": "CALL", - "loc": 103, + "loc": 399, "id": { "type": "TERM", - "loc": 103, + "loc": 399, "token": { "type": "identifier", - "value": "power_n", - "start": 103, - "end": 109 + "value": "distance", + "start": 399, + "end": 406 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@power_n" + "typeString": "resolve_type@@distance" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@power_n" + "typeString": "resolve_type@@distance" } }, "args": [ { "type": "TERM", - "loc": 111, + "loc": 408, "token": { "type": "identifier", - "value": "x", - "start": 111, - "end": 111 + "value": "p1", + "start": 408, + "end": 409 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@x" + "typeString": "resolve_type@@p1" }, "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "kind": "Struct", + "name": "Point", + "fields": {} } }, { - "type": "SUM", - "loc": 114, - "lhs": { - "type": "TERM", - "loc": 114, - "token": { - "type": "identifier", - "value": "n", - "start": 114, - "end": 114 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@n" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - }, - "op": { - "type": "-", - "value": "-", - "start": 116, - "end": 116 + "type": "TERM", + "loc": 412, + "token": { + "type": "identifier", + "value": "p2", + "start": 412, + "end": 413 }, - "rhs": { - "type": "TERM", - "loc": 118, - "token": { - "type": "numliteral", - "value": "1", - "start": 118, - "end": 118 - }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - }, - "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@p2" }, "resultantType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "kind": "Struct", + "name": "Point", + "fields": {} } } ], @@ -316,49 +1380,25 @@ }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "int" + "typeString": "void" } } - } - ], - "gomType": { - "kind": "Function", - "args": [ - { - "kind": "PrimitiveOrAlias", - "typeString": "int" - }, - { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - ], - "returnType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" - } - } - } - ], - "exportStatements": [], - "mainFunction": { - "type": "MAIN_FUNCTION", - "loc": 128, - "body": [ + ] + }, { "type": "EXPRESSION_STATEMENT", - "loc": 141, + "loc": 421, "expr": { "type": "ACCESS", - "loc": 141, + "loc": 421, "lhs": { "type": "TERM", - "loc": 141, + "loc": 421, "token": { "type": "identifier", "value": "io", - "start": 141, - "end": 142 + "start": 421, + "end": 422 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -371,15 +1411,15 @@ }, "rhs": { "type": "CALL", - "loc": 144, + "loc": 424, "id": { "type": "TERM", - "loc": 144, + "loc": 424, "token": { "type": "identifier", "value": "log", - "start": 144, - "end": 146 + "start": 424, + "end": 426 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -393,12 +1433,12 @@ "args": [ { "type": "TERM", - "loc": 148, + "loc": 428, "token": { "type": "strliteral", - "value": "\"Hello, World!\"", - "start": 148, - "end": 162 + "value": "\"Distance between p1 and p2: \"", + "start": 428, + "end": 457 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -408,6 +1448,24 @@ "kind": "PrimitiveOrAlias", "typeString": "str" } + }, + { + "type": "TERM", + "loc": 460, + "token": { + "type": "identifier", + "value": "d", + "start": 460, + "end": 460 + }, + "gomType": { + "kind": "PrimitiveOrAlias", + "typeString": "resolve_type@@d" + }, + "resultantType": { + "kind": "PrimitiveOrAlias", + "typeString": "int" + } } ], "resultantType": { @@ -421,20 +1479,160 @@ } } }, + { + "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": 170, + "loc": 506, "expr": { "type": "ACCESS", - "loc": 170, + "loc": 506, "lhs": { "type": "TERM", - "loc": 170, + "loc": 506, "token": { "type": "identifier", "value": "io", - "start": 170, - "end": 171 + "start": 506, + "end": 507 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -447,15 +1645,15 @@ }, "rhs": { "type": "CALL", - "loc": 173, + "loc": 509, "id": { "type": "TERM", - "loc": 173, + "loc": 509, "token": { "type": "identifier", "value": "log", - "start": 173, - "end": 175 + "start": 509, + "end": 511 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -469,12 +1667,12 @@ "args": [ { "type": "TERM", - "loc": 177, + "loc": 513, "token": { "type": "strliteral", - "value": "\"2^3 = \"", - "start": 177, - "end": 184 + "value": "\"Distance between l.p1 and l.p2: \"", + "start": 513, + "end": 546 }, "gomType": { "kind": "PrimitiveOrAlias", @@ -487,60 +1685,118 @@ }, { "type": "CALL", - "loc": 187, + "loc": 549, "id": { "type": "TERM", - "loc": 187, + "loc": 549, "token": { "type": "identifier", - "value": "power_n", - "start": 187, - "end": 193 + "value": "distance", + "start": 549, + "end": 556 }, "gomType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@power_n" + "typeString": "resolve_type@@distance" }, "resultantType": { "kind": "PrimitiveOrAlias", - "typeString": "resolve_type@@power_n" + "typeString": "resolve_type@@distance" } }, "args": [ { - "type": "TERM", - "loc": 195, - "token": { - "type": "numliteral", - "value": "2", - "start": 195, - "end": 195 + "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": {} + } }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "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": "PrimitiveOrAlias", - "typeString": "int" + "kind": "Struct", + "name": "Point", + "fields": {} } }, { - "type": "TERM", - "loc": 198, - "token": { - "type": "numliteral", - "value": "3", - "start": 198, - "end": 198 + "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": {} + } }, - "gomType": { - "kind": "PrimitiveOrAlias", - "typeString": "int" + "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": "PrimitiveOrAlias", - "typeString": "int" + "kind": "Struct", + "name": "Point", + "fields": {} } } ], From 97b9908b2ce76643b15d05234c2973fe3e2c77b0 Mon Sep 17 00:00:00 2001 From: Mohit Karekar Date: Wed, 5 Mar 2025 23:54:49 +0100 Subject: [PATCH 2/2] Update readme --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0102e8d..f3622d3 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ Defining complex data structures is possible via the `struct` notation (like `st ```gom import io; -type ArrInt = int[10]; // int | int[10] | struct {} | Temp[10] +type ArrInt = int[10]; // int | int[10] | {} | Temp[10] -type Temperature = struct { +type Temperature = { high: int, low: int, avg: int @@ -70,8 +70,10 @@ type Name = str; | Lexical Analysis | ✅ Done | | Syntactic Analysis (parsing) | ✅ Done | | Semantic Analysis & preliminary type system | ✅ Done | -| LLVM IR Generation | ⚙️ In progress | -| Complex data structures | ⏳ Not started | +| LLVM IR Generation | ✅ Done | +| Complex data structures - structs | ✅ Done | +| Modules | ⚙️ In progress | +| Complex data structures - arrays | ⏳ Not started | ## Trying out Gom