From 10d7a4b269bfd797f440049982d180ffcb7b2f17 Mon Sep 17 00:00:00 2001 From: spenc Date: Sat, 4 May 2024 13:07:02 -0700 Subject: [PATCH 01/20] created branch --- src/log.zig | 1 + src/sema.zig | 166 ++++++++++++++++++++++++++++----------------------- 2 files changed, 92 insertions(+), 75 deletions(-) diff --git a/src/log.zig b/src/log.zig index 9aaf632..6659682 100644 --- a/src/log.zig +++ b/src/log.zig @@ -31,6 +31,7 @@ fn logInner(level: Level, comptime msg: []const u8, vars: anytype) void { return; }; } + /// Log a message with the `info` level. Fails silently if the message can't be formatted. pub fn info(comptime msg: []const u8, vars: anytype) void { logInner(Level.Info, msg, vars); diff --git a/src/sema.zig b/src/sema.zig index 56af229..a673d3c 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -201,6 +201,7 @@ pub fn typeCheck(ast: *Ast) !void { try typeCheckFunction(ast, func.*); } } + // Done pub fn typeCheckFunction(ast: *Ast, func: Ast.Node) TypeError!void { var fc = func.kind.Function; @@ -208,9 +209,7 @@ pub fn typeCheckFunction(ast: *Ast, func: Ast.Node) TypeError!void { const returnType = fc.getReturnType(ast).?; const fBody = ast.get(fc.body).*; const fstatementsIndex = fBody.kind.FunctionBody.statements; - if(fstatementsIndex == null){ - std.debug.print("wahoo \n",.{}); - } + if (fstatementsIndex == null) { return; } @@ -234,7 +233,7 @@ pub fn typeCheckFunction(ast: *Ast, func: Ast.Node) TypeError!void { return error.FunctionParametersMustNotBeShadowed; } try paramNames.put(ident, true); - iter = ast.findIndexWithin(.TypedIdentifier, iter.?+1, last + 1); + iter = ast.findIndexWithin(.TypedIdentifier, iter.? + 1, last + 1); } paramNames.deinit(); // for each of the parameters check that there is no local declaration with the same name @@ -260,18 +259,42 @@ pub fn typeCheckStatementList(ast: *Ast, statementListn: ?usize, fName: []const pub fn typeCheckStatement(ast: *Ast, statement: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { const kind = statement.kind; _ = switch (kind) { - .Block => { try typeCheckBlock(ast, statement, fName, returnType); return; }, - .Assignment => { try typeCheckAssignment(ast, statement, fName, returnType); return; }, - .Print => { try typeCheckPrint(ast, statement, fName, returnType); return; }, - .ConditionalIf => { try typeCheckConditional(ast, statement, fName, returnType); return; }, - .While => { try typeCheckWhile(ast, statement, fName, returnType); return; }, - .Delete => { try typeCheckDelete(ast, statement, fName, returnType); return; }, - .Return => { try typeCheckReturn(ast, statement, fName, returnType); return; }, - .Invocation => { _ = try getAndCheckInvocation(ast, statement, fName, returnType); return; }, - else => { - utils.todo("Error on statement type checking\n", .{}); - return error.InvalidType; - }, + .Block => { + try typeCheckBlock(ast, statement, fName, returnType); + return; + }, + .Assignment => { + try typeCheckAssignment(ast, statement, fName, returnType); + return; + }, + .Print => { + try typeCheckPrint(ast, statement, fName, returnType); + return; + }, + .ConditionalIf => { + try typeCheckConditional(ast, statement, fName, returnType); + return; + }, + .While => { + try typeCheckWhile(ast, statement, fName, returnType); + return; + }, + .Delete => { + try typeCheckDelete(ast, statement, fName, returnType); + return; + }, + .Return => { + try typeCheckReturn(ast, statement, fName, returnType); + return; + }, + .Invocation => { + _ = try getAndCheckInvocation(ast, statement, fName, returnType); + return; + }, + else => { + utils.todo("Error on statement type checking\n", .{}); + return error.InvalidType; + }, }; return error.InvalidType; } @@ -320,7 +343,7 @@ pub fn typeCheckAssignment(ast: *Ast, assignmentn: Ast.Node, fName: []const u8, // right hand side is an expression const rightExpr = ast.get(right.?).*; const rightType = try getAndCheckTypeExpression(ast, rightExpr, fName, returnType); - if(rightType.isStruct()){ + if (rightType.isStruct()) { std.debug.print("rightType: {s}\n", .{rightType.Struct}); std.debug.print("leftType: {s}\n", .{leftType.?.Struct}); } @@ -445,7 +468,7 @@ pub fn getAndCheckInvocation(ast: *Ast, invocationn: Ast.Node, fName: []const u8 if (funcPList == null) { // return the return type of the function const temp = ast.getFunctionReturnTypeFromName(funcName); - if(temp == null){ + if (temp == null) { return error.NoSuchFunction; } return temp.?; @@ -473,8 +496,8 @@ pub fn getAndCheckInvocation(ast: *Ast, invocationn: Ast.Node, fName: []const u8 while (i < argsList.?.len) { const argType = argsList.?[i]; const paramType = funcPList.?[i]; - if(argType.equals(Ast.Type.Null)){ - if(!paramType.isStruct()){ + if (argType.equals(Ast.Type.Null)) { + if (!paramType.isStruct()) { // print them out std.debug.print("argType: {s}\n", .{@tagName(argType)}); std.debug.print("paramType: {s}\n", .{@tagName(paramType)}); @@ -483,10 +506,10 @@ pub fn getAndCheckInvocation(ast: *Ast, invocationn: Ast.Node, fName: []const u8 } else if (!argType.equals(paramType)) { std.debug.print("argType: {s}\n", .{@tagName(argType)}); std.debug.print("paramType: {s}\n", .{@tagName(paramType)}); - if(argType.isStruct()){ + if (argType.isStruct()) { std.debug.print("argType: {s}\n", .{argType.Struct}); } - if(paramType.isStruct()){ + if (paramType.isStruct()) { std.debug.print("paramType: {s}\n", .{paramType.Struct}); } return error.InvalidFunctionCall; @@ -499,7 +522,7 @@ pub fn getAndCheckInvocation(ast: *Ast, invocationn: Ast.Node, fName: []const u8 // Done pub fn getAndCheckTypeExpression(ast: *Ast, exprn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { - switch(exprn.kind){ + switch (exprn.kind) { .BinaryOperation => { return try getAndCheckBinaryOperation(ast, exprn, fName, returnType); }, @@ -515,19 +538,19 @@ pub fn getAndCheckTypeExpression(ast: *Ast, exprn: Ast.Node, fName: []const u8, const node = ast.get(expr.expr).*; const kind = node.kind; switch (kind) { - .BinaryOperation => { - return try getAndCheckBinaryOperation(ast, node, fName, returnType); - }, - .UnaryOperation => { - return try getAndCheckUnaryOperation(ast, node, fName, returnType); - }, - .Selector => { - return try getAndCheckSelector(ast, node, fName, returnType); - }, - else => { - utils.todo("Error on expression type checking\n", .{}); - return error.InvalidType; - }, + .BinaryOperation => { + return try getAndCheckBinaryOperation(ast, node, fName, returnType); + }, + .UnaryOperation => { + return try getAndCheckUnaryOperation(ast, node, fName, returnType); + }, + .Selector => { + return try getAndCheckSelector(ast, node, fName, returnType); + }, + else => { + utils.todo("Error on expression type checking\n", .{}); + return error.InvalidType; + }, } }, else => { @@ -537,7 +560,6 @@ pub fn getAndCheckTypeExpression(ast: *Ast, exprn: Ast.Node, fName: []const u8, return error.InvalidType; }, } - } // TODO: fix the errors @@ -675,7 +697,7 @@ pub fn getAndCheckLocalIdentifier(ast: *Ast, localId: Ast.Node, fName: []const u const func = ast.getFunctionFromName(fName).?.kind.Function.proto; const param = ast.get(func).*.kind.FunctionProto.parameters; - const funcDecl = ast.getFunctionDeclarationTypeFromName(fName,name ); + const funcDecl = ast.getFunctionDeclarationTypeFromName(fName, name); const funcParam = try ParamatergetParamTypeFromName(param, ast, name); const globalDecl = ast.getDeclarationGlobalFromName(name); const localDecl = funcParam orelse funcDecl orelse globalDecl; @@ -716,7 +738,7 @@ pub fn SelectorChaingetType(this: ?usize, ast: *Ast, ty: Ast.Type) !?Ast.Type { // TODO: add error return error.StructHasNoMember; } - if(field.?.isStruct()){ + if (field.?.isStruct()) { tmpIdent = field.?.Struct; tmpIdent = ast.get(ast.getStructNodeFromName(tmpIdent).?.kind.TypeDeclaration.ident).token._range.getSubStrFromStr(ast.input); } @@ -727,7 +749,6 @@ pub fn SelectorChaingetType(this: ?usize, ast: *Ast, ty: Ast.Type) !?Ast.Type { chain = ast.get(chain.next.?).kind.SelectorChain; } } - } pub fn ParametergetParamTypes(this: ?usize, ast: *Ast) !?[]Ast.Type { if (this == null) { @@ -746,8 +767,8 @@ pub fn ParametergetParamTypes(this: ?usize, ast: *Ast) !?[]Ast.Type { while (iter != null) { const param = ast.get(iter.?).*; // find next TypedIdentifier - iter = ast.findIndexWithin(.TypedIdentifier, iter.?+1,last.? + 1); - const ty = try TypedIdentifergetType(param,ast); + iter = ast.findIndexWithin(.TypedIdentifier, iter.? + 1, last.? + 1); + const ty = try TypedIdentifergetType(param, ast); try list.append(ty); } const res = try list.toOwnedSlice(); @@ -773,10 +794,10 @@ pub fn ParamatergetParamTypeFromName(this: ?usize, ast: *Ast, name: []const u8) const identNode = ast.get(param.kind.TypedIdentifier.ident); const ident = identNode.token._range.getSubStrFromStr(ast.input); if (std.mem.eql(u8, ident, name)) { - return try TypedIdentifergetType(param,ast); + return try TypedIdentifergetType(param, ast); } // find next TypedIdentifier - iter = ast.findIndexWithin(.TypedIdentifier, iter.?+1,last.? + 1); + iter = ast.findIndexWithin(.TypedIdentifier, iter.? + 1, last.? + 1); } return null; } @@ -823,20 +844,20 @@ pub fn ArgumentsgetArgumentTypes(this: ?usize, ast: *Ast, fName: []const u8, ret while (flag and cursor <= last) { const node = ast.get(cursor).*; switch (node.kind) { - .Arguments => depth += 1, - .ArgumentEnd => { - if (depth == 0) { - flag = false; - } - }, - .ArgumentsEnd => { - if (depth > 0) { - depth -= 1; - } else { - return error.InvalidFunctionCall; - } - }, - else => {} + .Arguments => depth += 1, + .ArgumentEnd => { + if (depth == 0) { + flag = false; + } + }, + .ArgumentsEnd => { + if (depth > 0) { + depth -= 1; + } else { + return error.InvalidFunctionCall; + } + }, + else => {}, } cursor += 1; } @@ -882,7 +903,7 @@ pub fn LValuegetType(this: ?usize, ast: *Ast, fName: []const u8) !?Ast.Type { // TODO: add error return error.StructHasNoMember; } - if(field.?.isStruct()){ + if (field.?.isStruct()) { tmpIdent = field.?.Struct; tmpIdent = ast.get(ast.getStructNodeFromName(tmpIdent).?.kind.TypeDeclaration.ident).token._range.getSubStrFromStr(ast.input); } @@ -895,7 +916,6 @@ pub fn LValuegetType(this: ?usize, ast: *Ast, fName: []const u8) !?Ast.Type { } } - pub fn StatemenListgetList(this: ?usize, ast: *Ast) TypeError!?[]usize { if (this == null) { return null; @@ -904,8 +924,8 @@ pub fn StatemenListgetList(this: ?usize, ast: *Ast) TypeError!?[]usize { var list = std.ArrayList(usize).init(ast.allocator); const last = self.lastStatement orelse self.firstStatement + 1; var iter: ?usize = self.firstStatement; - while (iter != null){ - if(iter.? > last){ + while (iter != null) { + if (iter.? > last) { break; } @@ -922,13 +942,9 @@ pub fn StatemenListgetList(this: ?usize, ast: *Ast) TypeError!?[]usize { // TESTS // /////////// - const ting = std.testing; const debugAlloc = std.heap.page_allocator; - - - fn testMe(input: []const u8) !Ast { const tokens = try @import("lexer.zig").Lexer.tokenizeFromStr(input, debugAlloc); const parser = try @import("parser.zig").Parser.parseTokens(tokens, input, debugAlloc); @@ -1031,7 +1047,7 @@ test "sema.get_and_check_invocation_with_args_fail" { try ting.expectError(TypeError.InvalidFunctionCall, typeCheckFunction(&ast, funcLit)); } -test "sema_get_and_check_invocations_with_mul_args_pass"{ +test "sema_get_and_check_invocations_with_mul_args_pass" { const source = "fun foo (int a, bool b) void {} fun main() void {foo(1, true);}"; var ast = try testMe(source); var func = ast.getFunctionFromName("foo"); @@ -1039,7 +1055,7 @@ test "sema_get_and_check_invocations_with_mul_args_pass"{ try typeCheckFunction(&ast, funcLit); } -test "sema_get_and_check_invocations_with_mul_args_fail"{ +test "sema_get_and_check_invocations_with_mul_args_fail" { const source = "fun foo (int a, bool b) void {} fun main() void {foo(1, 1);}"; var ast = try testMe(source); var func = ast.getFunctionFromName("main"); @@ -1047,7 +1063,7 @@ test "sema_get_and_check_invocations_with_mul_args_fail"{ try ting.expectError(TypeError.InvalidFunctionCall, typeCheckFunction(&ast, funcLit)); } -test "sema_get_and_check_invocations_with_mul_args_fail2"{ +test "sema_get_and_check_invocations_with_mul_args_fail2" { const source = "fun foo (int a, bool b) void {} fun main() void {foo(true, true);}"; var ast = try testMe(source); var func = ast.getFunctionFromName("main"); @@ -1287,7 +1303,7 @@ test "sema.check_deep_struct_assignment_fail" { try ting.expectError(TypeError.InvalidAssignmentType, typeCheckFunction(&ast, funcLit)); } -test "sema.check_deep_struct_assignment"{ +test "sema.check_deep_struct_assignment" { const source = "struct S {int a; struct S s;}; fun main() void {struct S s; struct S b; s.s.s.s.s.s.a = 1; b.s.s.s.s.s.s.s =s;}"; var ast = try testMe(source); var func = ast.getFunctionFromName("main"); @@ -1295,7 +1311,7 @@ test "sema.check_deep_struct_assignment"{ try typeCheckFunction(&ast, funcLit); } -test "sema.check_mixed.mini"{ +test "sema.check_mixed.mini" { // load source from file const source = @embedFile("mixed.mini"); var ast = try testMe(source); @@ -1303,7 +1319,7 @@ test "sema.check_mixed.mini"{ var funcLit = func.?.*; try typeCheckFunction(&ast, funcLit); } -test "sema.check_mixed_wrong_new.mini"{ +test "sema.check_mixed_wrong_new.mini" { // load source from file const source = @embedFile("mixed_wrong_new.mini"); var ast = try testMe(source); @@ -1311,7 +1327,7 @@ test "sema.check_mixed_wrong_new.mini"{ try ting.expectError(TypeError.InvalidAssignmentType, typeCheck(&ast)); } // test for InvalidFunctionCallNoDefinedArguments -test "sema.check_invocationwithnoargsbutparams"{ +test "sema.check_invocationwithnoargsbutparams" { const source = "fun foo(int a) void {} fun main() void {foo();}"; var ast = try testMe(source); var func = ast.getFunctionFromName("main"); @@ -1328,10 +1344,10 @@ test "sema.check_binop_mul_bools" { // expect error try ting.expectError(TypeError.InvalidTypeExptectedInt, typeCheckFunction(&ast, funcLit)); } -test "sema.4mini"{ +test "sema.4mini" { // load source from file const source = @embedFile("4.mini"); var ast = try testMe(source); // expect error InvalidAssignmentType try typeCheck(&ast); -} \ No newline at end of file +} From f444f11a23c1210d74630da19f2b7585c75494cc Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 4 May 2024 13:22:47 -0700 Subject: [PATCH 02/20] add justfile from ssa --- Justfile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Justfile diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..2dc97da --- /dev/null +++ b/Justfile @@ -0,0 +1,5 @@ +test path="_": + zig {{ if path == "_" {"build test"} else { "test --main-pkg-path " + join(justfile_directory(), "src") + " " + join(justfile_directory(), "src", replace(parent_directory(path), "src", ""), file_stem(path)) + ".zig"} }} + +watch path="_": + watchexec -e zig -- just test {{path}} From b8d99bc616424251aad251acdccba7dab0dad1b8 Mon Sep 17 00:00:00 2001 From: spenc Date: Sat, 4 May 2024 13:34:47 -0700 Subject: [PATCH 03/20] added to the lexer --- src/lexer.zig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lexer.zig b/src/lexer.zig index 3c8406e..774f374 100644 --- a/src/lexer.zig +++ b/src/lexer.zig @@ -96,6 +96,8 @@ pub const TokenKind = enum { RParen, LCurly, RCurly, + LBracket, + RBracket, Semicolon, Eof, Or, @@ -366,6 +368,8 @@ pub const Lexer = struct { ')' => .RParen, '{' => .LCurly, '}' => .RCurly, + '[' => .LBracket, + ']' => .RBracket, '+' => .Plus, '*' => .Mul, '/' => .Div, @@ -449,6 +453,15 @@ test "add" { defer testAlloc.free(tokens); } +test "brackets" { + const tokens = try expect_results_in_tokens("[]", &[_]TokenKind{ + .LBracket, + .RBracket, + .Eof, + }); + defer testAlloc.free(tokens); +} + test "simple_struct" { const content = "struct SimpleStruct { int x; int y; }"; const tokens = try expect_results_in_tokens(content, &[_]TokenKind{ From 23867f5706c03198727bc8745194b263ac6c7287 Mon Sep 17 00:00:00 2001 From: spenc Date: Sat, 4 May 2024 14:10:18 -0700 Subject: [PATCH 04/20] idk what i changed --- mini.ebnf | 3 ++- src/lexer.zig | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mini.ebnf b/mini.ebnf index 6ceedf7..ef70743 100644 --- a/mini.ebnf +++ b/mini.ebnf @@ -30,6 +30,7 @@ simple -> term {{ '+' | '−' } term}∗ term -> unary {{ '∗' | '/' } unary}∗ unary -> { '!' | '−' }∗ selector selector -> factor {'.' id}∗ -factor -> '(' expression ')' | id {arguments}opt | number | 'true' | 'false' | 'new' id | 'null' +factor -> '(' expression ')' | id {arguments}opt | number | 'true' | + | 'false' | 'new' id | 'null' | 'new' 'int_array' '[' number ']' | arguments -> '(' {expression { ',' expression}∗}opt ')' number -> {'0' | '1' | ... | '9'}{ '0' | '1' | ... | '9'}∗ diff --git a/src/lexer.zig b/src/lexer.zig index 774f374..b67d024 100644 --- a/src/lexer.zig +++ b/src/lexer.zig @@ -120,6 +120,7 @@ pub const TokenKind = enum { KeywordTrue, KeywordVoid, KeywordWhile, + KeywordIntArray, Unset, // NOTE: bool, int, void shouldn't be valid keywords, (valid /type/ names) @@ -144,6 +145,7 @@ pub const TokenKind = enum { .{ "true", TokenKind.KeywordTrue }, .{ "void", TokenKind.KeywordVoid }, .{ "while", TokenKind.KeywordWhile }, + .{ "int_array", TokenKind.KeywordIntArray }, }); pub fn equals(self: TokenKind, other: TokenKind) bool { @@ -355,6 +357,7 @@ pub const Lexer = struct { } fn read_symbol(lxr: *Lexer) !TokenKind { + std.debug.print("read_symbol: {c}\n", .{lxr.ch}); const tok: TokenKind = switch (lxr.ch) { '<' => if (lxr.step_if_next_is('=')) .LtEq else .Lt, '>' => if (lxr.step_if_next_is('=')) .GtEq else .Gt, @@ -454,8 +457,11 @@ test "add" { } test "brackets" { - const tokens = try expect_results_in_tokens("[]", &[_]TokenKind{ + const tokens = try expect_results_in_tokens("new int_array[10]", &[_]TokenKind{ + .KeywordNew, + .KeywordIntArray, .LBracket, + .Number, .RBracket, .Eof, }); From 592b4d61834f86ed418f47571c01886d4277783f Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 4 May 2024 14:19:29 -0700 Subject: [PATCH 05/20] allow underscore only in `int_array` ident --- src/lexer.zig | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lexer.zig b/src/lexer.zig index b67d024..1460ea4 100644 --- a/src/lexer.zig +++ b/src/lexer.zig @@ -254,7 +254,7 @@ pub const Lexer = struct { lxr.skip_whitespace(); const info: TokInfo = switch (lxr.ch) { - 'a'...'z', 'A'...'Z' => lxr.ident_or_builtin(), + 'a'...'z', 'A'...'Z' => try lxr.ident_or_builtin(), '0'...'9' => .{ .kind = TokenKind.Number, .range = try lxr.read_number() }, else => blk: { const pos = lxr.pos; @@ -327,19 +327,29 @@ pub const Lexer = struct { } } - fn read_ident(lxr: *Lexer) Range { + fn read_ident(lxr: *Lexer) !Range { const pos = lxr.pos; // NOTE: no need to check first char is not numeric here // because if first char was numeric we would have called // read_number instead - while (std.ascii.isAlphanumeric(lxr.ch)) { + var hasUnderscore = false; + while (std.ascii.isAlphanumeric(lxr.ch) or lxr.ch == '_') { + hasUnderscore = hasUnderscore or lxr.ch == '_'; lxr.step(); } - return Range{ .start = pos, .end = lxr.pos }; + const range = Range{ .start = pos, .end = lxr.pos }; + if (hasUnderscore) { + const ident = lxr.slice(range); + if (!std.mem.eql(u8, ident, "int_array")) { + log.err("error: only ident allowed to have underscore is `int_array` not {s}\n", .{ident}); + return error.InvalidToken; + } + } + return range; } - fn ident_or_builtin(lxr: *Lexer) TokInfo { - const range = lxr.read_ident(); + fn ident_or_builtin(lxr: *Lexer) !TokInfo { + const range = try lxr.read_ident(); const ident = lxr.slice(range); const kw = TokenKind.keywords.get(ident); if (kw) |kw_kind| { From ac3c27145e7b73cf15bdd694c62ac11a97f3e035 Mon Sep 17 00:00:00 2001 From: spenc Date: Sat, 4 May 2024 14:22:51 -0700 Subject: [PATCH 06/20] finished adding int_array to the lexer --- src/lexer.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lexer.zig b/src/lexer.zig index 1460ea4..d0e844b 100644 --- a/src/lexer.zig +++ b/src/lexer.zig @@ -367,7 +367,6 @@ pub const Lexer = struct { } fn read_symbol(lxr: *Lexer) !TokenKind { - std.debug.print("read_symbol: {c}\n", .{lxr.ch}); const tok: TokenKind = switch (lxr.ch) { '<' => if (lxr.step_if_next_is('=')) .LtEq else .Lt, '>' => if (lxr.step_if_next_is('=')) .GtEq else .Gt, From 360b7f6e8775b1018c0ed94b35476cd394d8da02 Mon Sep 17 00:00:00 2001 From: spenc Date: Sat, 4 May 2024 17:14:47 -0700 Subject: [PATCH 07/20] created branch --- mini.ebnf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mini.ebnf b/mini.ebnf index ef70743..2040aaa 100644 --- a/mini.ebnf +++ b/mini.ebnf @@ -3,7 +3,7 @@ types -> {type-declaration}∗ type-declaration -> 'struct' id '{' nested-decl '}' ';' nested-decl -> decl ';' { decl ';'}∗ decl -> 'type' id -type -> 'int' | 'bool' | 'struct' id +type -> 'int' | 'bool' | 'struct' id | 'int_array' declarations -> {declaration}∗ declaration -> 'type' id-list ';' id-list -> id {',' id}∗ From e165f0aebddfa8a89b707f769644951d2c25296c Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 4 May 2024 17:16:50 -0700 Subject: [PATCH 08/20] add notes for sleepyhead --- src/parser.zig | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/parser.zig b/src/parser.zig index 98d02bf..26e5992 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -446,6 +446,7 @@ pub const Parser = struct { const token = try self.consumeToken(); // Expect int | bool | struct (id) + // FIXME: SPENCER PUT THE ARRAY TYPE HERE AS A VALID TYPE switch (token.kind) { TokenKind.KeywordInt => { const kind = NodeKind.IntType; @@ -1397,9 +1398,9 @@ pub const Parser = struct { const atomIndex = try self.parseSelector(); std.debug.print("\n", .{}); - prettyPrintTokens(self, self.tokens[expr.Atom.start..(expr.Atom.start + expr.Atom.len)]); + prettyPrintTokens(self, self.tokens[expr.Atom.start..(expr.Atom.start + expr.Atom.len)]); std.debug.print("\n", .{}); - prettyPrintTokens(self, self.tokens[expr.Atom.start..self.pos]); + prettyPrintTokens(self, self.tokens[expr.Atom.start..self.pos]); std.debug.print("\n", .{}); // I really should have made this error shorter before the hundredth time I saw it utils.assert(self.pos == (expr.Atom.start + expr.Atom.len), "either didn't skip enough tokens when extracting atom or didn't parse enough when reconstructing tree... either way shits borqed! glhf!!!\n Expected to parse: \n {any} \nBut Parsed: \n {any} \n", .{ self.tokens[expr.Atom.start..(expr.Atom.start + expr.Atom.len)], self.tokens[expr.Atom.start..self.pos] }); @@ -1436,7 +1437,7 @@ pub const Parser = struct { // NOTE: unessary? const node = Node{ - .kind = NodeKind{ .Expression = .{ .expr = treeIndex, .last = last} }, + .kind = NodeKind{ .Expression = .{ .expr = treeIndex, .last = last } }, .token = tok, }; try self.set(expressionIndex, node); @@ -1537,7 +1538,7 @@ pub const Parser = struct { } } const current = try self.currentToken(); - if(current.kind == .Dot){ + if (current.kind == .Dot) { _ = try self.consumeToken(); try self.expectToken(.Identifier); numTokens += 2; @@ -1547,6 +1548,8 @@ pub const Parser = struct { } }, .KeywordNew => { + // FIXME: SPENCER PUT SOME CHECKS HERE TO CHECK FOR THE int_array after new AND EXPECT + // THE BRACKET, NUMBER, BRACKET tokens (making sure to update numTokens accordingly) _ = try self.expectToken(.KeywordNew); // Note - leaving checking if the thing after new is right until it's parsed later... // this is probably a badddd idea (malformed expressions like what! (with the lights on!!??)) @@ -1726,6 +1729,11 @@ pub const Parser = struct { lhsIndex = try self.astAppendNode(nullNode); }, TokenKind.KeywordNew => { + // FIXME: SPENCER HAVE THE SAME EXPECT LOGIC YOU HAD IN `extractAtom` HERE + // BUT ACTUALLY CREATE THE AST NODES THIS TIME. TALK TO ME IF YOU ARE CONFUSED + // MAKE SURE TO RETURN error.InvalidToken IF THERE IS an int_array NOT FOLLOWED BY + // BRACKET NUMBER BRACKET + // Expect new const newToken = try self.expectAndYeildToken(.KeywordNew); const newIndex = try self.reserve(); From 1cabff715f05fd36249d7e386e721d548497a190 Mon Sep 17 00:00:00 2001 From: spenc Date: Wed, 8 May 2024 11:12:26 -0700 Subject: [PATCH 09/20] paused testing for some stuff --- src/ast.zig | 33 ++++++++++++++--------- src/parser.zig | 73 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 82 insertions(+), 24 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index 24924cd..dbe4af1 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -34,19 +34,18 @@ pub fn mapStructs(ast: *Ast) !void { } } -pub fn printAst(self: *Ast) void{ +pub fn printAst(self: *Ast) void { var i: usize = 0; const nodes = self.nodes.items; for (nodes) |node| { const kind = node.kind; const token = node.token; - std.debug.print("{d}: {s} {s}", .{i, @tagName(kind), token._range.getSubStrFromStr(self.input)}); - switch (kind){ + std.debug.print("{d}: {s} {s}", .{ i, @tagName(kind), token._range.getSubStrFromStr(self.input) }); + switch (kind) { .BinaryOperation => { const binOp = node.kind.BinaryOperation; std.debug.print(" lhs: {any}", .{binOp.lhs}); std.debug.print(" rhs: {any}\n", .{binOp.rhs}); - }, else => { std.debug.print("\n", .{}); @@ -111,8 +110,6 @@ pub fn getStructNodeFromName(ast: *Ast, name: []const u8) ?*const Node { return null; } - - pub fn getStructFieldType(ast: *Ast, structName: []const u8, fieldName: []const u8) ?Type { const structNode = ast.getStructNodeFromName(structName); if (structNode == null) { @@ -198,6 +195,7 @@ pub const Node = struct { .BoolType, .IntType, .StructType, + .IntArrayType, }), /// when kind is `StructType` points to the idenfifier /// of the struct @@ -207,6 +205,7 @@ pub const Node = struct { BoolType, IntType, StructType, + IntArrayType, Void, Read, Identifier, @@ -237,8 +236,8 @@ pub const Node = struct { fn getMemberType(self: Self, ast: *Ast, memberName: []const u8) ?Type { const last = self.lastDecl orelse self.firstDecl + 1; var iter: ?usize = self.firstDecl; - while(iter != null){ - if( iter.? > last){ + while (iter != null) { + if (iter.? > last) { break; } const decl = ast.get(iter.?).kind.TypedIdentifier; @@ -246,7 +245,7 @@ pub const Node = struct { if (std.mem.eql(u8, name, memberName)) { return decl.getType(ast); } - iter = ast.findIndexWithin(.TypedIdentifier, iter.?+1, last + 1); + iter = ast.findIndexWithin(.TypedIdentifier, iter.? + 1, last + 1); } return null; } @@ -300,17 +299,17 @@ pub const Node = struct { fn getMemberType(self: Self, ast: *Ast, memberName: []const u8) ?Type { const last = self.lastDecl orelse self.firstDecl + 1; var iter: ?usize = self.firstDecl; - while(iter != null){ - if( iter.? > last){ + while (iter != null) { + if (iter.? > last) { break; } - std.debug.print("iter={d} last={d}\n", .{iter.?, last}); + std.debug.print("iter={d} last={d}\n", .{ iter.?, last }); const decl = ast.get(iter.?).kind.TypedIdentifier; const name = decl.getName(ast); if (std.mem.eql(u8, name, memberName)) { return decl.getType(ast); } - iter = ast.findIndexWithin(.TypedIdentifier, iter.?+1, last + 1); + iter = ast.findIndexWithin(.TypedIdentifier, iter.? + 1, last + 1); } return null; } @@ -448,6 +447,10 @@ pub const Node = struct { /// pointer to the identifier being allocated ident: Ref(.Identifier), }, + NewIntArray: struct { + /// The space to allocate for the array + length: Ref(.Number), + }, /// keyword `null` Null, /// This is a special node that is used to reserve space for the AST @@ -680,6 +683,7 @@ pub const Node = struct { const name = nameToken._range.getSubStrFromStr(ast.input); return .{ .Struct = name }; }, + .IntArrayType => return .IntArray, else => unreachable, } } else { @@ -708,6 +712,7 @@ pub const Node = struct { const name = nameToken._range.getSubStrFromStr(ast.input); return .{ .Struct = name }; }, + .IntArrayType => return .IntArray, else => unreachable, } } @@ -782,6 +787,7 @@ pub const Node = struct { pub const Type = union(enum) { Bool, Int, + IntArray, Null, Void, Struct: []const u8, @@ -826,6 +832,7 @@ const KindTagDupe = enum { BoolType, IntType, StructType, + IntArrayType, Void, Read, Identifier, diff --git a/src/parser.zig b/src/parser.zig index 26e5992..aef4a48 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -459,6 +459,9 @@ pub const Parser = struct { kindIndex = try self.astAppend(NodeKind.StructType, token); structIdentifierIndex = try self.astAppendNode(try self.expectIdentifier()); }, + TokenKind.KeywordIntArray => { + kindIndex = try self.astAppend(NodeKind.IntArrayType, token); + }, else => { // TODO: make this error like the others log.err("Error invalid Token: expected token kind {s} | {s} | {s} but got {s}.\n", .{ @tagName(TokenKind.KeywordInt), @tagName(TokenKind.KeywordBool), @tagName(TokenKind.KeywordStruct), @tagName(token.kind) }); @@ -1554,9 +1557,22 @@ pub const Parser = struct { // Note - leaving checking if the thing after new is right until it's parsed later... // this is probably a badddd idea (malformed expressions like what! (with the lights on!!??)) // FIXME: NOTE: for the introductoin of array_list this will have to be changed - _ = try self.expectToken(.Identifier); - numTokens += 1; - utils.assert(numTokens == 2, "New token has more than 2 tokens\n", .{}); + const nextToken = try self.currentToken(); + + if (nextToken.kind == .Identifier) { + _ = try self.expectToken(.Identifier); + numTokens += 1; + utils.assert(numTokens == 2, "New token has more than 2 tokens\n", .{}); + } else if (nextToken.kind == .KeywordIntArray) { + _ = try self.expectToken(.KeywordIntArray); + _ = try self.expectToken(.LBracket); + _ = try self.expectToken(.Number); + _ = try self.expectToken(.RBracket); + + numTokens += 4; + // log.info("numTokens: {d}\n", .{numTokens}); + utils.assert(numTokens == 5, "New token has more than 4 tokens\n", .{}); + } }, .Dot => { while ((try self.currentToken()).kind == .Dot) { @@ -1716,6 +1732,7 @@ pub const Parser = struct { const falseToken = try self.expectAndYeildToken(TokenKind.KeywordFalse); const falseNode = Node{ .kind = .False, + .token = falseToken, }; lhsIndex = try self.astAppendNode(falseNode); @@ -1738,15 +1755,38 @@ pub const Parser = struct { const newToken = try self.expectAndYeildToken(.KeywordNew); const newIndex = try self.reserve(); - // Expect Identifier - const identIndex = try self.astAppendNode(try self.expectIdentifier()); + // const currentToken = try self.expect(.TypeIntArray); + if ((try self.currentToken()).kind == .KeywordIntArray) { + _ = try self.consumeToken(); - const newNode = Node{ - .kind = .{ .New = .{ .ident = identIndex } }, - .token = newToken, - }; - try self.set(newIndex, newNode); - lhsIndex = newIndex; + _ = try self.expectToken(.LBracket); + const numberToken = try self.expectAndYeildToken(.Number); + _ = try self.expectToken(.RBracket); + + const newNumberNode = Node{ + .kind = .Number, + .token = numberToken, + }; + + const identNewNumberNode = try self.astAppendNode(newNumberNode); + + const newNode = Node{ + .kind = .{ .New = .{ .ident = identNewNumberNode } }, + .token = newToken, + }; + try self.set(newIndex, newNode); + lhsIndex = newIndex; + } else { + // Expect Identifier + const identIndex = try self.astAppendNode(try self.expectIdentifier()); + + const newNode = Node{ + .kind = .{ .New = .{ .ident = identIndex } }, + .token = newToken, + }; + try self.set(newIndex, newNode); + lhsIndex = newIndex; + } }, else => { // TODO: make this error like the others @@ -1873,6 +1913,16 @@ test "program declarations indices null for no types" { } } +test "create int array" { + const source = "new int_array[5]"; + var parser = try testMe(source); + const atom = try parser.extractAtom(); + const start: usize = 0; + const len: usize = 5; + try ting.expectEqual(start, atom.start); + try ting.expectEqual(len, atom.len); +} + test "extractAtom.Num" { var parser = try testMe("123"); const atom = try parser.extractAtom(); @@ -1981,6 +2031,7 @@ test "pratt.simple_pemdas" { } // FIXME: +// test "pratt.funcall" { var parser = try testMe("foo(1, 2, 3)"); const expr = try parser.prattParseExpression(debugAlloc, 0); From d3d70c6c7a6d400ea7197de94b29108095919dfc Mon Sep 17 00:00:00 2001 From: spenc Date: Fri, 10 May 2024 13:35:26 -0700 Subject: [PATCH 10/20] Added my changes but removed comments --- src/ast.zig | 8 +++- src/parser.zig | 100 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index dbe4af1..73f749c 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -408,7 +408,13 @@ pub const Node = struct { }, /// A chain of `.ident` selectors SelectorChain: struct { - ident: Ref(.Identifier), + /// TODO: change ident to something that can be used for array access + /// and struct access + ident: RefOneOf(.{ + .Identifier, + // Expression is used for array access + .Expression, + }), /// Pointer to `SelectorChain` /// null if last in chain next: ?Ref(.SelectorChain) = null, diff --git a/src/parser.zig b/src/parser.zig index aef4a48..e945a0e 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -1509,17 +1509,18 @@ pub const Parser = struct { var startTok = try self.currentToken(); const peekKind = (try self.peekToken()).kind; - if ((startTok.kind == .Identifier) and (peekKind == .LParen or peekKind == .Dot)) { + if ((startTok.kind == .Identifier) and (peekKind == .LParen or peekKind == .Dot or peekKind == .LBracket)) { // skipping all tokens for function call `id '(' {args},* ')'` is functionally the same as skipping all tokens in a parenthized as expression // skipping the id token makes it so they can be handled in the same switch arm in the // following switch statement _ = try self.consumeToken(); startTok = try self.currentToken(); - if (peekKind == .LParen) { + if (peekKind == .LParen or peekKind == .LBracket) { // Dot `numTokens` calculation is harder when we increment // in both cases here numTokens += 1; } + // TODO: SPENCER Possibly do a simmilar thing to the LParen case for LBracket // skipping on `.` however just makes it so identifier is easier in the next switch } switch (startTok.kind) { @@ -1550,6 +1551,34 @@ pub const Parser = struct { utils.assert(final.kind == .RParen, "final token not RParen, is: {}\n", .{final}); } }, + .LBracket => { + // keep "stack" of paren count to find the last one + var count: u32 = 1; + std.debug.print("LBracket I Am HEREERERERERERE\n", .{}); + _ = try self.consumeToken(); + while (count != 0) { + numTokens += 1; + const tok = try self.consumeToken(); + if (tok.kind == .Eof) { + // TODO: handle + return error.NotEnoughTokens; + } + if (tok.kind == .LBracket) { + count += 1; + } else if (tok.kind == .RBracket) { + count -= 1; + } + } + const current = try self.currentToken(); + if (current.kind == .Dot) { + _ = try self.consumeToken(); + try self.expectToken(.Identifier); + numTokens += 2; + } else { + const final = self.tokens[self.pos - 1]; + utils.assert(final.kind == .RBracket, "final token not RBracket, is: {}\n", .{final}); + } + }, .KeywordNew => { // FIXME: SPENCER PUT SOME CHECKS HERE TO CHECK FOR THE int_array after new AND EXPECT // THE BRACKET, NUMBER, BRACKET tokens (making sure to update numTokens accordingly) @@ -1632,18 +1661,37 @@ pub const Parser = struct { var curChainIndex: ?usize = null; // Expect ("." Identifier)* - while ((try self.currentToken()).kind == TokenKind.Dot) { + while ((try self.currentToken()).kind == TokenKind.Dot or (try self.currentToken()).kind == TokenKind.LBracket) { const chainNodeIndex = try self.reserve(); if (chainIndex == null) { chainIndex = chainNodeIndex; } - // Expect . - const dotToken = try self.expectAndYeildToken(TokenKind.Dot); - // Expect Identifier - const identIndex = try self.astAppendNode(try self.expectIdentifier()); + + const curToken = try self.currentToken(); + + const identIndex = switch (curToken.kind) { + TokenKind.Dot => blk: { + // Expect . + _ = try self.expectAndYeildToken(TokenKind.Dot); + // Expect Identifier + const identIndex = try self.astAppendNode(try self.expectIdentifier()); + break :blk identIndex; + }, + TokenKind.LBracket => blk: { + _ = try self.expectAndYeildToken(TokenKind.LBracket); + const expresion = try self.parseExpression(); + _ = try self.expectAndYeildToken(TokenKind.RBracket); + break :blk expresion; + }, + else => { + log.err("Expected a dot or but got {s}.\n", .{@tagName(curToken.kind)}); + return error.InvalidToken; + }, + }; + const chainNode = Node{ .kind = .{ .SelectorChain = .{ .ident = identIndex, .next = null } }, - .token = dotToken, + .token = curToken, }; try self.set(chainNodeIndex, chainNode); @@ -1681,6 +1729,14 @@ pub const Parser = struct { // Expect ) try self.expectToken(TokenKind.RParen); }, + // TokenKind.LBracket => { + // Expect [ + // try self.expectToken(TokenKind.LBracket); + // // Expect Expression + // lhsIndex = try self.parseExpression(); + // // Expect ] + // try self.expectToken(TokenKind.RBracket); + // }, TokenKind.Identifier => { const peekTokenKind = (try self.peekToken()).kind; if (peekTokenKind == .LParen) { @@ -2015,6 +2071,34 @@ test "extractAtom.new_in_fkncall" { try ting.expectEqual(len, atom.len); } +test "extractAtom.access_int_array" { + const source = "foo[1]"; + var parser = try testMe(source); + const atom = try parser.extractAtom(); + const start: usize = 0; + const len: usize = 4; + // std.debug.print("parsed: {any}\n", .{parser.tokens[atom.start..(atom.start + atom.len)]}); + // try parser.prettyPrintAst(); + const tokenKinds = [_]TokenKind{ .Identifier, .LBracket, .Number, .RBracket }; + try expectAtomSliceTokenKinds(&parser, atom, &tokenKinds); + try ting.expectEqual(start, atom.start); + try ting.expectEqual(len, atom.len); +} + +test "extractAtom.access_int_array2" { + const source = "bar[foo(1+2) + 1]"; + var parser = try testMe(source); + const atom = try parser.extractAtom(); + const start: usize = 0; + const len: usize = 11; + // std.debug.print("parsed: {any}\n", .{parser.tokens[atom.start..(atom.start + atom.len)]}); + // try parser.prettyPrintAst(); + // const tokenKinds = [_]TokenKind{ .Identifier, .LBracket, .Number, .RBracket }; + // try expectAtomSliceTokenKinds(&parser, atom, &tokenKinds); + try ting.expectEqual(start, atom.start); + try ting.expectEqual(len, atom.len); +} + test "pratt.simple_pemdas" { var parser = try testMe("1 + 2 * 3"); const expr = try parser.prattParseExpression(debugAlloc, 0); From cb198f730673a218936f3f9711e220fac1976277 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Fri, 10 May 2024 13:39:16 -0700 Subject: [PATCH 11/20] improve ast type comparison --- src/ast.zig | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index 73f749c..c16a43e 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -303,8 +303,7 @@ pub const Node = struct { if (iter.? > last) { break; } - std.debug.print("iter={d} last={d}\n", .{ iter.?, last }); - const decl = ast.get(iter.?).kind.TypedIdentifier; + const decl = ast.get(iterator.?).kind.TypedIdentifier; const name = decl.getName(ast); if (std.mem.eql(u8, name, memberName)) { return decl.getType(ast); @@ -808,13 +807,31 @@ pub const Type = union(enum) { return @intFromEnum(self) == @intFromEnum(other); } pub fn equals(self: Self, other: Self) bool { - const tmp = @intFromEnum(self) ^ @intFromEnum(other); - // if struct - if (std.mem.eql(u8, @tagName(self), @tagName(other)) and std.mem.eql(u8, @tagName(self), "Struct")) { - // memcmp - return std.mem.eql(u8, self.Struct, other.Struct); - } - return tmp == 0; + return switch (self) { + .Struct => switch (other) { + // names equal + .Struct => std.mem.eql(u8, self.Struct, other.Struct), + .Null => true, + else => false, + }, + // I'm not sure if the null == null is necessary but it can't + // hurt right? + // + // right? + .Null => other == .Struct or other == .Null, + else => @intFromEnum(self) == @intFromEnum(other), + }; + // Dylan I see what you were going for here I just don't like it ;) + // also it didn't work and was hard to extend to support null so I made + // it better ;) - Ben + // ... why did copilot just sign my name for me? + // const tmp = @intFromEnum(self) ^ @intFromEnum(other); + // // if struct + // if (std.mem.eql(u8, @tagName(self), @tagName(other)) and std.mem.eql(u8, @tagName(self), "Struct")) { + // // memcmp + // return std.mem.eql(u8, self.Struct, other.Struct); + // } + // return tmp == 0; } }; From 87df3682c7e89655cb26390b0e160944c77fb9f6 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Fri, 10 May 2024 13:39:30 -0700 Subject: [PATCH 12/20] add printNodeLine helper --- src/ast.zig | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/ast.zig b/src/ast.zig index c16a43e..f886901 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -1018,6 +1018,28 @@ pub fn iterFuncs(ast: *const Ast) FuncIter { return FuncIter.new(ast); } +pub fn printNodeLine(ast: *const Ast, node: Node) void { + const input = ast.input; + const tok = node.token; + const tok_start = tok._range.start; + const tok_end = tok._range.end; + var line_start: usize = tok_start; + while (line_start >= 0 and input[line_start] != '\n') : (line_start -= 1) {} + line_start += 1; + var line_end: usize = tok_end; + while (line_end < input.len and input[line_end] != '\n') : (line_end += 1) {} + const line = input[line_start..line_end]; + var line_no: usize = 0; + var i: usize = 0; + while (i < line_start) : (i += 1) { + if (input[i] == '\n') { + line_no += 1; + } + } + const col_no = tok_start - line_start; + std.debug.print("LINE {d}:{d} \"{s}\"\n", .{ line_no, col_no, line }); +} + const ting = std.testing; const debugAlloc = std.heap.page_allocator; From fad5969ea28f3882b50ee703e795011f3fc2ff81 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Fri, 10 May 2024 13:39:50 -0700 Subject: [PATCH 13/20] use printNodeLine instead of whatever dylan was doing --- src/sema.zig | 93 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/src/sema.zig b/src/sema.zig index a673d3c..6d15565 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -23,6 +23,7 @@ const TypeError = error{ InvalidAssignmentNoDeclaration, StructHasNoMember, BinaryOperationTypeMismatch, + InvalidBinaryOperationType, InvalidTypeExptectedInt, InvalidTypeExpectedBool, InvalidFunctionCallNoDefinedArguments, @@ -56,9 +57,9 @@ fn allFunctionsHaveValidReturnPaths(ast: *const Ast) !void { /// note that the ast must be sliced to start at some function for this function /// to work fn allReturnPathsHaveReturnType(ast: *const Ast, func: Ast.Node.Kind.FunctionType) SemaError!void { - // Get the name const funcName = func.getName(ast); + errdefer log.err("Function: {s}\n", .{funcName}); // Get the return type const returnType = func.getReturnType(ast).?; @@ -179,6 +180,7 @@ fn allReturnPathsExistInner(ast: *const Ast, start: usize, end: usize) bool { } fn allReturnPathsExist(ast: *const Ast, func: Ast.Node.Kind.FunctionType) SemaError!void { + errdefer log.err("Function: {s}\n", .{func.getName(ast)}); const returnType = func.getReturnType(ast).?; const statementList = func.getBody(ast).getStatementList(); if (returnType == .Void and statementList == null) { @@ -203,7 +205,8 @@ pub fn typeCheck(ast: *Ast) !void { } // Done -pub fn typeCheckFunction(ast: *Ast, func: Ast.Node) TypeError!void { +pub fn typeCheckFunction(ast: *const Ast, func: Ast.Node) TypeError!void { + errdefer ast.printNodeLine(func); var fc = func.kind.Function; const functionName = fc.getName(ast); const returnType = fc.getReturnType(ast).?; @@ -242,21 +245,22 @@ pub fn typeCheckFunction(ast: *Ast, func: Ast.Node) TypeError!void { } // Done -pub fn typeCheckStatementList(ast: *Ast, statementListn: ?usize, fName: []const u8, returnType: Ast.Type) TypeError!void { - ast.printAst(); - std.debug.print("statementListn: {d}\n", .{statementListn.?}); +pub fn typeCheckStatementList(ast: *const Ast, statementListn: ?usize, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer if (statementListn) |lst| ast.printNodeLine(ast.get(lst).*); + // log.trace("statementListn: {d}\n", .{statementListn.?}); const list = try StatemenListgetList(statementListn, ast); if (list == null) { return; } for (list.?) |statement| { - std.debug.print("Statement {any}\n", .{statement}); + // log.trace("Statement {any}\n", .{statement}); const statNode = ast.get(statement).*; try typeCheckStatement(ast, statNode, fName, returnType); } } -pub fn typeCheckStatement(ast: *Ast, statement: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { +pub fn typeCheckStatement(ast: *const Ast, statement: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer ast.printNodeLine(statement); const kind = statement.kind; _ = switch (kind) { .Block => { @@ -300,7 +304,8 @@ pub fn typeCheckStatement(ast: *Ast, statement: Ast.Node, fName: []const u8, ret } // Done -pub fn typeCheckBlock(ast: *Ast, blockn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { +pub fn typeCheckBlock(ast: *const Ast, blockn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer ast.printNodeLine(blockn); // Block to statement list const block = blockn.kind.Block; const statementIndex = block.statements; @@ -311,7 +316,8 @@ pub fn typeCheckBlock(ast: *Ast, blockn: Ast.Node, fName: []const u8, returnType } // Done -pub fn typeCheckAssignment(ast: *Ast, assignmentn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { +pub fn typeCheckAssignment(ast: *const Ast, assignmentn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer ast.printNodeLine(assignmentn); const assignment = assignmentn.kind.Assignment; const left = assignment.lhs; const right = assignment.rhs; @@ -343,10 +349,6 @@ pub fn typeCheckAssignment(ast: *Ast, assignmentn: Ast.Node, fName: []const u8, // right hand side is an expression const rightExpr = ast.get(right.?).*; const rightType = try getAndCheckTypeExpression(ast, rightExpr, fName, returnType); - if (rightType.isStruct()) { - std.debug.print("rightType: {s}\n", .{rightType.Struct}); - std.debug.print("leftType: {s}\n", .{leftType.?.Struct}); - } if (!leftType.?.equals(rightType)) { // FIXME: add error return error.InvalidAssignmentType; @@ -354,7 +356,8 @@ pub fn typeCheckAssignment(ast: *Ast, assignmentn: Ast.Node, fName: []const u8, } // Done -pub fn typeCheckPrint(ast: *Ast, printn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { +pub fn typeCheckPrint(ast: *const Ast, printn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer ast.printNodeLine(printn); const print = printn.kind.Print; const expr = print.expr; const exprNode = ast.get(expr).*; @@ -366,12 +369,12 @@ pub fn typeCheckPrint(ast: *Ast, printn: Ast.Node, fName: []const u8, returnType } // Done -pub fn typeCheckConditional(ast: *Ast, conditionaln: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { +pub fn typeCheckConditional(ast: *const Ast, conditionaln: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer ast.printNodeLine(conditionaln); // first check if conditional is bool const conditional = conditionaln.kind.ConditionalIf; const cond = conditional.cond; const condNode = ast.get(cond).*; - std.debug.print("condNode: {any}\n", .{cond}); const condType = try getAndCheckTypeExpression(ast, condNode, fName, returnType); if (!condType.equals(Ast.Type.Bool)) { utils.todo("Error on conditional type checking\n", .{}); @@ -392,7 +395,8 @@ pub fn typeCheckConditional(ast: *Ast, conditionaln: Ast.Node, fName: []const u8 } // Done -pub fn typeCheckWhile(ast: *Ast, while_nN: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { +pub fn typeCheckWhile(ast: *const Ast, while_nN: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer ast.printNodeLine(while_nN); // first check if conditional is bool const while_n = while_nN.kind.While; const cond = while_n.cond; @@ -408,7 +412,8 @@ pub fn typeCheckWhile(ast: *Ast, while_nN: Ast.Node, fName: []const u8, returnTy } // Done -pub fn typeCheckDelete(ast: *Ast, deleten: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { +pub fn typeCheckDelete(ast: *const Ast, deleten: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer ast.printNodeLine(deleten); const delete = deleten.kind.Delete; const expr = delete.expr; const exprNode = ast.get(expr).*; @@ -420,7 +425,8 @@ pub fn typeCheckDelete(ast: *Ast, deleten: Ast.Node, fName: []const u8, returnTy } // Done -pub fn typeCheckReturn(ast: *Ast, retn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { +pub fn typeCheckReturn(ast: *const Ast, retn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { + errdefer ast.printNodeLine(retn); const ret = retn.kind.Return; const expr = ret.expr; if (expr == null) { @@ -438,7 +444,8 @@ pub fn typeCheckReturn(ast: *Ast, retn: Ast.Node, fName: []const u8, returnType: } // Done -pub fn getAndCheckInvocation(ast: *Ast, invocationn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { +pub fn getAndCheckInvocation(ast: *const Ast, invocationn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { + errdefer ast.printNodeLine(invocationn); const invocation = invocationn.kind.Invocation; const funcName = ast.get(invocation.funcName).token._range.getSubStrFromStr(ast.input); const func = ast.getFunctionFromName(funcName); @@ -461,8 +468,6 @@ pub fn getAndCheckInvocation(ast: *Ast, invocationn: Ast.Node, fName: []const u8 var argsList = try ArgumentsgetArgumentTypes(args, ast, fName, returnType); var funcPList = try ParametergetParamTypes(funcProto, ast); - std.debug.print("argsList: {any}\n", .{argsList}); - std.debug.print("funcPList: {any}\n", .{funcPList}); if (argsList == null) { if (funcPList == null) { @@ -487,8 +492,6 @@ pub fn getAndCheckInvocation(ast: *Ast, invocationn: Ast.Node, fName: []const u8 argsList = argsList.?; if (argsList.?.len != funcPList.?.len) { // print the position of argslist - std.debug.print("argsList: {d}\n", .{args.?}); - utils.todo("Error on invocation type checking\n", .{}); return error.InvalidFunctionCall; } @@ -521,7 +524,8 @@ pub fn getAndCheckInvocation(ast: *Ast, invocationn: Ast.Node, fName: []const u8 } // Done -pub fn getAndCheckTypeExpression(ast: *Ast, exprn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { +pub fn getAndCheckTypeExpression(ast: *const Ast, exprn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { + errdefer ast.printNodeLine(exprn); switch (exprn.kind) { .BinaryOperation => { return try getAndCheckBinaryOperation(ast, exprn, fName, returnType); @@ -563,7 +567,8 @@ pub fn getAndCheckTypeExpression(ast: *Ast, exprn: Ast.Node, fName: []const u8, } // TODO: fix the errors -pub fn getAndCheckBinaryOperation(ast: *Ast, binaryOp: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { +pub fn getAndCheckBinaryOperation(ast: *const Ast, binaryOp: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { + errdefer ast.printNodeLine(binaryOp); const token = binaryOp.token; switch (token.kind) { .Lt, .Gt, .GtEq, .LtEq, .DoubleEq, .NotEq => { @@ -571,11 +576,14 @@ pub fn getAndCheckBinaryOperation(ast: *Ast, binaryOp: Ast.Node, fName: []const const rhsExpr = ast.get(binaryOp.kind.BinaryOperation.rhs.?).*; const lhsType = try getAndCheckTypeExpression(ast, lhsExpr, fName, returnType); const rhsType = try getAndCheckTypeExpression(ast, rhsExpr, fName, returnType); + // log the types + // log.trace("lhsType: {s}\n", .{@tagName(lhsType)}); + // log.trace("rhsType: {s}\n", .{@tagName(rhsType)}); if (!lhsType.equals(rhsType)) { return error.BinaryOperationTypeMismatch; } - if (!lhsType.equals(Ast.Type.Int)) { - return error.InvalidTypeExptectedInt; + if (lhsType != .Int and lhsType != .Struct and lhsType != .Null) { + return error.InvalidBinaryOperationType; } return Ast.Type.Bool; }, @@ -598,9 +606,8 @@ pub fn getAndCheckBinaryOperation(ast: *Ast, binaryOp: Ast.Node, fName: []const .Plus, .Div, => { - ast.printAst(); - const lhsExpr = ast.get(binaryOp.kind.BinaryOperation.lhs.?).*; - const rhsExpr = ast.get(binaryOp.kind.BinaryOperation.rhs.?).*; + const lhsExpr = ast.get(binaryOp.kind.BinaryOperation.lhs).*; + const rhsExpr = ast.get(binaryOp.kind.BinaryOperation.rhs).*; const lhsType = try getAndCheckTypeExpression(ast, lhsExpr, fName, returnType); const rhsType = try getAndCheckTypeExpression(ast, rhsExpr, fName, returnType); if (!lhsType.equals(rhsType)) { @@ -622,7 +629,8 @@ pub fn getAndCheckBinaryOperation(ast: *Ast, binaryOp: Ast.Node, fName: []const unreachable; } -pub fn getAndCheckUnaryOperation(ast: *Ast, unaryOp: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { +pub fn getAndCheckUnaryOperation(ast: *const Ast, unaryOp: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { + errdefer ast.printNodeLine(unaryOp); const token = unaryOp.token; switch (token.kind) { .Not => { @@ -649,7 +657,8 @@ pub fn getAndCheckUnaryOperation(ast: *Ast, unaryOp: Ast.Node, fName: []const u8 unreachable; } -pub fn getAndCheckSelector(ast: *Ast, selectorn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { +pub fn getAndCheckSelector(ast: *const Ast, selectorn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { + errdefer ast.printNodeLine(selectorn); const selector = selectorn.kind.Selector; const factorNode = ast.get(selector.factor).*; const factorType = try getAndCheckFactor(ast, factorNode, fName, returnType); @@ -660,7 +669,8 @@ pub fn getAndCheckSelector(ast: *Ast, selectorn: Ast.Node, fName: []const u8, re return chainType.?; } -pub fn getAndCheckFactor(ast: *Ast, factorn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { +pub fn getAndCheckFactor(ast: *const Ast, factorn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { + errdefer ast.printNodeLine(factorn); const factor = factorn.kind.Factor; const kind = factor.factor; const node = ast.get(kind).*; @@ -680,7 +690,8 @@ pub fn getAndCheckFactor(ast: *Ast, factorn: Ast.Node, fName: []const u8, return unreachable; } -pub fn getAndCheckNew(ast: *Ast, newn: Ast.Node) TypeError!Ast.Type { +pub fn getAndCheckNew(ast: *const Ast, newn: Ast.Node) TypeError!Ast.Type { + errdefer ast.printNodeLine(newn); const new = newn.kind.New; const name = ast.get(new.ident).token._range.getSubStrFromStr(ast.input); const structType = ast.getStructNodeFromName(name); @@ -691,7 +702,8 @@ pub fn getAndCheckNew(ast: *Ast, newn: Ast.Node) TypeError!Ast.Type { return Ast.Type{ .Struct = name }; } -pub fn getAndCheckLocalIdentifier(ast: *Ast, localId: Ast.Node, fName: []const u8) TypeError!Ast.Type { +pub fn getAndCheckLocalIdentifier(ast: *const Ast, localId: Ast.Node, fName: []const u8) TypeError!Ast.Type { + errdefer ast.printNodeLine(localId); const token = localId.token; const name = token._range.getSubStrFromStr(ast.input); const func = ast.getFunctionFromName(fName).?.kind.Function.proto; @@ -701,7 +713,6 @@ pub fn getAndCheckLocalIdentifier(ast: *Ast, localId: Ast.Node, fName: []const u const funcParam = try ParamatergetParamTypeFromName(param, ast, name); const globalDecl = ast.getDeclarationGlobalFromName(name); const localDecl = funcParam orelse funcDecl orelse globalDecl; - std.debug.print("name: {s}\n", .{name}); if (localDecl == null) { return error.InvalidType; } @@ -802,7 +813,8 @@ pub fn ParamatergetParamTypeFromName(this: ?usize, ast: *Ast, name: []const u8) return null; } -pub fn TypedIdentifergetType(tid: Ast.Node, ast: *Ast) !Ast.Type { +pub fn TypedIdentifergetType(tid: Ast.Node, ast: *const Ast) !Ast.Type { + errdefer ast.printNodeLine(tid); const ty = ast.get(tid.kind.TypedIdentifier.type).*.kind.Type; const ff = ast.get(ty.kind).*.kind; _ = switch (ff) { @@ -825,12 +837,12 @@ pub fn ArgumentsgetArgumentTypes(this: ?usize, ast: *Ast, fName: []const u8, ret if (this == null) { return null; } + errdefer ast.printNodeLine(ast.get(this.?).*); const self = ast.get(this.?).kind.Arguments; var list = std.ArrayList(Ast.Type).init(ast.allocator); const last: usize = self.lastArg orelse self.firstArg + 1; var iter: ?usize = self.firstArg; - ast.printAst(); var depth: usize = 0; while (iter != null) { @@ -874,12 +886,12 @@ pub fn LValuegetType(this: ?usize, ast: *Ast, fName: []const u8) !?Ast.Type { // TODO add error return null; } + errdefer ast.printNodeLine(ast.get(this.?).*); const self = ast.get(this.?).kind.LValue; const identNode = ast.get(self.ident); const ident = identNode.token._range.getSubStrFromStr(ast.input); // const g_decl = ast.getDeclarationGlobalFromName(ident); const f_decl = try getAndCheckLocalIdentifier(ast, identNode.*, fName); - std.debug.print("name {s}\n", .{ident}); var decl = f_decl; // if (decl == null) { // // TODO: add error @@ -920,6 +932,7 @@ pub fn StatemenListgetList(this: ?usize, ast: *Ast) TypeError!?[]usize { if (this == null) { return null; } + errdefer ast.printNodeLine(ast.get(this.?).*); const self = ast.get(this.?).kind.StatementList; var list = std.ArrayList(usize).init(ast.allocator); const last = self.lastStatement orelse self.firstStatement + 1; From 2c1cf1b9010b59abdd551f3f8107a487532d3159 Mon Sep 17 00:00:00 2001 From: spenc Date: Fri, 10 May 2024 18:46:16 -0700 Subject: [PATCH 14/20] did stuff --- src/ast.zig | 26 ++++++++-------- src/lexer.zig | 33 ++++++++++++++++++++ src/parser.zig | 22 ++++++++----- src/sema.zig | 84 +++++++++++++++++++++++++++----------------------- 4 files changed, 107 insertions(+), 58 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index f886901..db481fe 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -34,7 +34,7 @@ pub fn mapStructs(ast: *Ast) !void { } } -pub fn printAst(self: *Ast) void { +pub fn printAst(self: *const Ast) void { var i: usize = 0; const nodes = self.nodes.items; for (nodes) |node| { @@ -72,7 +72,7 @@ pub fn mapFunctions(ast: *Ast) !void { } } -pub fn getFunctionFromName(ast: *Ast, name: []const u8) ?*const Node { +pub fn getFunctionFromName(ast: *const Ast, name: []const u8) ?*const Node { const index = ast.functionMap.get(name); if (index) |i| { return ast.get(i); @@ -80,7 +80,7 @@ pub fn getFunctionFromName(ast: *Ast, name: []const u8) ?*const Node { return null; } -pub fn getFunctionReturnTypeFromName(ast: *Ast, name: []const u8) ?Type { +pub fn getFunctionReturnTypeFromName(ast: *const Ast, name: []const u8) ?Type { const funcNode = ast.getFunctionFromName(name); if (funcNode == null) { return null; @@ -89,7 +89,7 @@ pub fn getFunctionReturnTypeFromName(ast: *Ast, name: []const u8) ?Type { return func.getReturnType(ast); } -pub fn getFunctionDeclarationTypeFromName(ast: *Ast, name: []const u8, memberName: []const u8) ?Type { +pub fn getFunctionDeclarationTypeFromName(ast: *const Ast, name: []const u8, memberName: []const u8) ?Type { const funcNode = ast.getFunctionFromName(name); if (funcNode == null) { return null; @@ -102,7 +102,7 @@ pub fn getFunctionDeclarationTypeFromName(ast: *Ast, name: []const u8, memberNam return declarations.kind.LocalDeclarations.getMemberType(ast, memberName); } -pub fn getStructNodeFromName(ast: *Ast, name: []const u8) ?*const Node { +pub fn getStructNodeFromName(ast: *const Ast, name: []const u8) ?*const Node { const index = ast.structMap.get(name); if (index) |i| { return ast.get(i); @@ -110,17 +110,17 @@ pub fn getStructNodeFromName(ast: *Ast, name: []const u8) ?*const Node { return null; } -pub fn getStructFieldType(ast: *Ast, structName: []const u8, fieldName: []const u8) ?Type { +pub fn getStructFieldType(ast: *const Ast, structName: []const u8, fieldName: []const u8) ?Type { const structNode = ast.getStructNodeFromName(structName); if (structNode == null) { return null; } const decls = ast.get(structNode.?.kind.TypeDeclaration.declarations); - ast.printAst(); + // ast.printAst(); return decls.kind.StructFieldDeclarations.getMemberType(ast, fieldName); } -pub fn getDeclarationGlobalFromName(ast: *Ast, name: []const u8) ?Type { +pub fn getDeclarationGlobalFromName(ast: *const Ast, name: []const u8) ?Type { const nodes = ast.nodes.items; for (nodes) |node| { if (node.kind == .ProgramDeclarations) { @@ -233,7 +233,7 @@ pub const Node = struct { } //Ben you will hate this :D - fn getMemberType(self: Self, ast: *Ast, memberName: []const u8) ?Type { + fn getMemberType(self: Self, ast: *const Ast, memberName: []const u8) ?Type { const last = self.lastDecl orelse self.firstDecl + 1; var iter: ?usize = self.firstDecl; while (iter != null) { @@ -296,14 +296,14 @@ pub const Node = struct { return self.firstDecl == null and self.lastDecl == null; } - fn getMemberType(self: Self, ast: *Ast, memberName: []const u8) ?Type { + fn getMemberType(self: Self, ast: *const Ast, memberName: []const u8) ?Type { const last = self.lastDecl orelse self.firstDecl + 1; var iter: ?usize = self.firstDecl; while (iter != null) { if (iter.? > last) { break; } - const decl = ast.get(iterator.?).kind.TypedIdentifier; + const decl = ast.get(iter.?).kind.TypedIdentifier; const name = decl.getName(ast); if (std.mem.eql(u8, name, memberName)) { return decl.getType(ast); @@ -706,7 +706,7 @@ pub const Node = struct { const Self = @This(); - pub fn getType(self: Self, ast: *Ast) Type { + pub fn getType(self: Self, ast: *const Ast) Type { const tyNode = ast.get(self.type).kind.Type; const kindNode = ast.get(tyNode.kind).kind; switch (kindNode) { @@ -721,7 +721,7 @@ pub const Node = struct { else => unreachable, } } - pub fn getName(self: Self, ast: *Ast) []const u8 { + pub fn getName(self: Self, ast: *const Ast) []const u8 { const idNode = ast.get(self.ident); const token = idNode.token; const name = token._range.getSubStrFromStr(ast.input); diff --git a/src/lexer.zig b/src/lexer.zig index d0e844b..fb580fe 100644 --- a/src/lexer.zig +++ b/src/lexer.zig @@ -580,3 +580,36 @@ test "ident_with_num" { }); defer testAlloc.free(tokens); } + +test "lexer.checkArrayAccess" { + const source = "fun main() void {int_array a; a = new int_array[10]; a[0] = 1;}"; + const tokens = try expect_results_in_tokens(source, &[_]TokenKind{ + .KeywordFun, + .Identifier, + .LParen, + .RParen, + .KeywordVoid, + .LCurly, + .KeywordIntArray, + .Identifier, + .Semicolon, + .Identifier, + .Eq, + .KeywordNew, + .KeywordIntArray, + .LBracket, + .Number, + .RBracket, + .Semicolon, + .Identifier, + .LBracket, + .Number, + .RBracket, + .Eq, + .Number, + .Semicolon, + .RCurly, + .Eof, + }); + defer testAlloc.free(tokens); +} diff --git a/src/parser.zig b/src/parser.zig index e945a0e..5296feb 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -1400,11 +1400,11 @@ pub const Parser = struct { self.readPos = expr.Atom.start + 1; const atomIndex = try self.parseSelector(); - std.debug.print("\n", .{}); - prettyPrintTokens(self, self.tokens[expr.Atom.start..(expr.Atom.start + expr.Atom.len)]); - std.debug.print("\n", .{}); - prettyPrintTokens(self, self.tokens[expr.Atom.start..self.pos]); - std.debug.print("\n", .{}); + // std.debug.print("\n", .{}); + // prettyPrintTokens(self, self.tokens[expr.Atom.start..(expr.Atom.start + expr.Atom.len)]); + // std.debug.print("\n", .{}); + // prettyPrintTokens(self, self.tokens[expr.Atom.start..self.pos]); + // std.debug.print("\n", .{}); // I really should have made this error shorter before the hundredth time I saw it utils.assert(self.pos == (expr.Atom.start + expr.Atom.len), "either didn't skip enough tokens when extracting atom or didn't parse enough when reconstructing tree... either way shits borqed! glhf!!!\n Expected to parse: \n {any} \nBut Parsed: \n {any} \n", .{ self.tokens[expr.Atom.start..(expr.Atom.start + expr.Atom.len)], self.tokens[expr.Atom.start..self.pos] }); @@ -1554,7 +1554,7 @@ pub const Parser = struct { .LBracket => { // keep "stack" of paren count to find the last one var count: u32 = 1; - std.debug.print("LBracket I Am HEREERERERERERE\n", .{}); + // std.debug.print("LBracket I Am HEREERERERERERE\n", .{}); _ = try self.consumeToken(); while (count != 0) { numTokens += 1; @@ -1868,7 +1868,6 @@ pub fn main() !void { const tokens = try Lexer.tokenizeFromStr(source, std.heap.page_allocator); const parser = try Parser.parseTokens(tokens, source, std.heap.page_allocator); log.err("Parsed successfully\n", .{}); - std.debug.print("haha penis", .{}); try parser.prettyPrintAst(); } @@ -2206,3 +2205,12 @@ test "fun.with_locals" { try ting.expect(nodes[funNode.kind.Function.proto].kind == .FunctionProto); // TODO: add more checks for function subtree structure } +test "parser.checkArrayAccess" { + const source = "int_array a; a = new int_array[10];}"; + _ = try parseMe(source); +} + +// test "parser.checkArrayAccess" { +// const source = "fun main() void {int_array a; a = new int_array[10]; a[0] = 1;}"; +// _ = try parseMe(source); +// } diff --git a/src/sema.zig b/src/sema.zig index 6d15565..4755852 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -195,7 +195,7 @@ fn allReturnPathsExist(ast: *const Ast, func: Ast.Node.Kind.FunctionType) SemaEr } } -pub fn typeCheck(ast: *Ast) !void { +pub fn typeCheck(ast: *const Ast) !void { // get all functions out of map var funcsKeys = ast.functionMap.keyIterator(); while (funcsKeys.next()) |key| { @@ -206,7 +206,7 @@ pub fn typeCheck(ast: *Ast) !void { // Done pub fn typeCheckFunction(ast: *const Ast, func: Ast.Node) TypeError!void { - errdefer ast.printNodeLine(func); + // errdefer ast.printNodeLine(func); var fc = func.kind.Function; const functionName = fc.getName(ast); const returnType = fc.getReturnType(ast).?; @@ -246,7 +246,7 @@ pub fn typeCheckFunction(ast: *const Ast, func: Ast.Node) TypeError!void { // Done pub fn typeCheckStatementList(ast: *const Ast, statementListn: ?usize, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer if (statementListn) |lst| ast.printNodeLine(ast.get(lst).*); + // errdefer if (statementListn) |lst| ast.printNodeLine(ast.get(lst).*); // log.trace("statementListn: {d}\n", .{statementListn.?}); const list = try StatemenListgetList(statementListn, ast); if (list == null) { @@ -260,7 +260,7 @@ pub fn typeCheckStatementList(ast: *const Ast, statementListn: ?usize, fName: [] } pub fn typeCheckStatement(ast: *const Ast, statement: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer ast.printNodeLine(statement); + // errdefer ast.printNodeLine(statement); const kind = statement.kind; _ = switch (kind) { .Block => { @@ -305,7 +305,7 @@ pub fn typeCheckStatement(ast: *const Ast, statement: Ast.Node, fName: []const u // Done pub fn typeCheckBlock(ast: *const Ast, blockn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer ast.printNodeLine(blockn); + // errdefer ast.printNodeLine(blockn); // Block to statement list const block = blockn.kind.Block; const statementIndex = block.statements; @@ -317,7 +317,7 @@ pub fn typeCheckBlock(ast: *const Ast, blockn: Ast.Node, fName: []const u8, retu // Done pub fn typeCheckAssignment(ast: *const Ast, assignmentn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer ast.printNodeLine(assignmentn); + // errdefer ast.printNodeLine(assignmentn); const assignment = assignmentn.kind.Assignment; const left = assignment.lhs; const right = assignment.rhs; @@ -357,7 +357,7 @@ pub fn typeCheckAssignment(ast: *const Ast, assignmentn: Ast.Node, fName: []cons // Done pub fn typeCheckPrint(ast: *const Ast, printn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer ast.printNodeLine(printn); + // errdefer ast.printNodeLine(printn); const print = printn.kind.Print; const expr = print.expr; const exprNode = ast.get(expr).*; @@ -370,7 +370,7 @@ pub fn typeCheckPrint(ast: *const Ast, printn: Ast.Node, fName: []const u8, retu // Done pub fn typeCheckConditional(ast: *const Ast, conditionaln: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer ast.printNodeLine(conditionaln); + // errdefer ast.printNodeLine(conditionaln); // first check if conditional is bool const conditional = conditionaln.kind.ConditionalIf; const cond = conditional.cond; @@ -396,7 +396,7 @@ pub fn typeCheckConditional(ast: *const Ast, conditionaln: Ast.Node, fName: []co // Done pub fn typeCheckWhile(ast: *const Ast, while_nN: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer ast.printNodeLine(while_nN); + // errdefer ast.printNodeLine(while_nN); // first check if conditional is bool const while_n = while_nN.kind.While; const cond = while_n.cond; @@ -413,7 +413,7 @@ pub fn typeCheckWhile(ast: *const Ast, while_nN: Ast.Node, fName: []const u8, re // Done pub fn typeCheckDelete(ast: *const Ast, deleten: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer ast.printNodeLine(deleten); + // errdefer ast.printNodeLine(deleten); const delete = deleten.kind.Delete; const expr = delete.expr; const exprNode = ast.get(expr).*; @@ -426,7 +426,7 @@ pub fn typeCheckDelete(ast: *const Ast, deleten: Ast.Node, fName: []const u8, re // Done pub fn typeCheckReturn(ast: *const Ast, retn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!void { - errdefer ast.printNodeLine(retn); + // errdefer ast.printNodeLine(retn); const ret = retn.kind.Return; const expr = ret.expr; if (expr == null) { @@ -445,7 +445,7 @@ pub fn typeCheckReturn(ast: *const Ast, retn: Ast.Node, fName: []const u8, retur // Done pub fn getAndCheckInvocation(ast: *const Ast, invocationn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { - errdefer ast.printNodeLine(invocationn); + // errdefer ast.printNodeLine(invocationn); const invocation = invocationn.kind.Invocation; const funcName = ast.get(invocation.funcName).token._range.getSubStrFromStr(ast.input); const func = ast.getFunctionFromName(funcName); @@ -501,19 +501,20 @@ pub fn getAndCheckInvocation(ast: *const Ast, invocationn: Ast.Node, fName: []co const paramType = funcPList.?[i]; if (argType.equals(Ast.Type.Null)) { if (!paramType.isStruct()) { - // print them out - std.debug.print("argType: {s}\n", .{@tagName(argType)}); - std.debug.print("paramType: {s}\n", .{@tagName(paramType)}); + log.err("argType: {s}\n", .{@tagName(argType)}); + log.err("paramType: {s}\n", .{@tagName(paramType)}); return error.InvalidFunctionCall; } } else if (!argType.equals(paramType)) { - std.debug.print("argType: {s}\n", .{@tagName(argType)}); - std.debug.print("paramType: {s}\n", .{@tagName(paramType)}); + log.err("argType: {s}\n", .{@tagName(argType)}); + log.err("paramType: {s}\n", .{@tagName(paramType)}); if (argType.isStruct()) { - std.debug.print("argType: {s}\n", .{argType.Struct}); + log.err("argType: {s}\n", .{argType.Struct}); + // std.debug.print("argType: {s}\n", .{argType.Struct}); } if (paramType.isStruct()) { - std.debug.print("paramType: {s}\n", .{paramType.Struct}); + log.err("paramType: {s}\n", .{paramType.Struct}); + // std.debug.print("paramType: {s}\n", .{paramType.Struct}); } return error.InvalidFunctionCall; } @@ -525,7 +526,7 @@ pub fn getAndCheckInvocation(ast: *const Ast, invocationn: Ast.Node, fName: []co // Done pub fn getAndCheckTypeExpression(ast: *const Ast, exprn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { - errdefer ast.printNodeLine(exprn); + // errdefer ast.printNodeLine(exprn); switch (exprn.kind) { .BinaryOperation => { return try getAndCheckBinaryOperation(ast, exprn, fName, returnType); @@ -568,7 +569,7 @@ pub fn getAndCheckTypeExpression(ast: *const Ast, exprn: Ast.Node, fName: []cons // TODO: fix the errors pub fn getAndCheckBinaryOperation(ast: *const Ast, binaryOp: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { - errdefer ast.printNodeLine(binaryOp); + // errdefer ast.printNodeLine(binaryOp); const token = binaryOp.token; switch (token.kind) { .Lt, .Gt, .GtEq, .LtEq, .DoubleEq, .NotEq => { @@ -606,8 +607,8 @@ pub fn getAndCheckBinaryOperation(ast: *const Ast, binaryOp: Ast.Node, fName: [] .Plus, .Div, => { - const lhsExpr = ast.get(binaryOp.kind.BinaryOperation.lhs).*; - const rhsExpr = ast.get(binaryOp.kind.BinaryOperation.rhs).*; + const lhsExpr = ast.get(binaryOp.kind.BinaryOperation.lhs.?).*; + const rhsExpr = ast.get(binaryOp.kind.BinaryOperation.rhs.?).*; const lhsType = try getAndCheckTypeExpression(ast, lhsExpr, fName, returnType); const rhsType = try getAndCheckTypeExpression(ast, rhsExpr, fName, returnType); if (!lhsType.equals(rhsType)) { @@ -630,7 +631,7 @@ pub fn getAndCheckBinaryOperation(ast: *const Ast, binaryOp: Ast.Node, fName: [] } pub fn getAndCheckUnaryOperation(ast: *const Ast, unaryOp: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { - errdefer ast.printNodeLine(unaryOp); + // errdefer ast.printNodeLine(unaryOp); const token = unaryOp.token; switch (token.kind) { .Not => { @@ -658,7 +659,7 @@ pub fn getAndCheckUnaryOperation(ast: *const Ast, unaryOp: Ast.Node, fName: []co } pub fn getAndCheckSelector(ast: *const Ast, selectorn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { - errdefer ast.printNodeLine(selectorn); + // errdefer ast.printNodeLine(selectorn); const selector = selectorn.kind.Selector; const factorNode = ast.get(selector.factor).*; const factorType = try getAndCheckFactor(ast, factorNode, fName, returnType); @@ -670,7 +671,7 @@ pub fn getAndCheckSelector(ast: *const Ast, selectorn: Ast.Node, fName: []const } pub fn getAndCheckFactor(ast: *const Ast, factorn: Ast.Node, fName: []const u8, returnType: Ast.Type) TypeError!Ast.Type { - errdefer ast.printNodeLine(factorn); + // errdefer ast.printNodeLine(factorn); const factor = factorn.kind.Factor; const kind = factor.factor; const node = ast.get(kind).*; @@ -691,7 +692,7 @@ pub fn getAndCheckFactor(ast: *const Ast, factorn: Ast.Node, fName: []const u8, } pub fn getAndCheckNew(ast: *const Ast, newn: Ast.Node) TypeError!Ast.Type { - errdefer ast.printNodeLine(newn); + // errdefer ast.printNodeLine(newn); const new = newn.kind.New; const name = ast.get(new.ident).token._range.getSubStrFromStr(ast.input); const structType = ast.getStructNodeFromName(name); @@ -703,7 +704,7 @@ pub fn getAndCheckNew(ast: *const Ast, newn: Ast.Node) TypeError!Ast.Type { } pub fn getAndCheckLocalIdentifier(ast: *const Ast, localId: Ast.Node, fName: []const u8) TypeError!Ast.Type { - errdefer ast.printNodeLine(localId); + // errdefer ast.printNodeLine(localId); const token = localId.token; const name = token._range.getSubStrFromStr(ast.input); const func = ast.getFunctionFromName(fName).?.kind.Function.proto; @@ -719,7 +720,7 @@ pub fn getAndCheckLocalIdentifier(ast: *const Ast, localId: Ast.Node, fName: []c return localDecl.?; } -pub fn SelectorChaingetType(this: ?usize, ast: *Ast, ty: Ast.Type) !?Ast.Type { +pub fn SelectorChaingetType(this: ?usize, ast: *const Ast, ty: Ast.Type) !?Ast.Type { if (this == null) { return null; } @@ -761,7 +762,7 @@ pub fn SelectorChaingetType(this: ?usize, ast: *Ast, ty: Ast.Type) !?Ast.Type { } } } -pub fn ParametergetParamTypes(this: ?usize, ast: *Ast) !?[]Ast.Type { +pub fn ParametergetParamTypes(this: ?usize, ast: *const Ast) !?[]Ast.Type { if (this == null) { return null; } @@ -787,7 +788,7 @@ pub fn ParametergetParamTypes(this: ?usize, ast: *Ast) !?[]Ast.Type { return res; } -pub fn ParamatergetParamTypeFromName(this: ?usize, ast: *Ast, name: []const u8) !?Ast.Type { +pub fn ParamatergetParamTypeFromName(this: ?usize, ast: *const Ast, name: []const u8) !?Ast.Type { if (this == null) { return null; } @@ -814,7 +815,7 @@ pub fn ParamatergetParamTypeFromName(this: ?usize, ast: *Ast, name: []const u8) } pub fn TypedIdentifergetType(tid: Ast.Node, ast: *const Ast) !Ast.Type { - errdefer ast.printNodeLine(tid); + // errdefer ast.printNodeLine(tid); const ty = ast.get(tid.kind.TypedIdentifier.type).*.kind.Type; const ff = ast.get(ty.kind).*.kind; _ = switch (ff) { @@ -833,11 +834,11 @@ pub fn TypedIdentifergetType(tid: Ast.Node, ast: *const Ast) !Ast.Type { }; return error.InvalidType; } -pub fn ArgumentsgetArgumentTypes(this: ?usize, ast: *Ast, fName: []const u8, returnType: Ast.Type) !?[]Ast.Type { +pub fn ArgumentsgetArgumentTypes(this: ?usize, ast: *const Ast, fName: []const u8, returnType: Ast.Type) !?[]Ast.Type { if (this == null) { return null; } - errdefer ast.printNodeLine(ast.get(this.?).*); + // errdefer ast.printNodeLine(ast.get(this.?).*); const self = ast.get(this.?).kind.Arguments; var list = std.ArrayList(Ast.Type).init(ast.allocator); const last: usize = self.lastArg orelse self.firstArg + 1; @@ -881,12 +882,12 @@ pub fn ArgumentsgetArgumentTypes(this: ?usize, ast: *Ast, fName: []const u8, ret list.deinit(); return res; } -pub fn LValuegetType(this: ?usize, ast: *Ast, fName: []const u8) !?Ast.Type { +pub fn LValuegetType(this: ?usize, ast: *const Ast, fName: []const u8) !?Ast.Type { if (this == null) { // TODO add error return null; } - errdefer ast.printNodeLine(ast.get(this.?).*); + // errdefer ast.printNodeLine(ast.get(this.?).*); const self = ast.get(this.?).kind.LValue; const identNode = ast.get(self.ident); const ident = identNode.token._range.getSubStrFromStr(ast.input); @@ -928,11 +929,11 @@ pub fn LValuegetType(this: ?usize, ast: *Ast, fName: []const u8) !?Ast.Type { } } -pub fn StatemenListgetList(this: ?usize, ast: *Ast) TypeError!?[]usize { +pub fn StatemenListgetList(this: ?usize, ast: *const Ast) TypeError!?[]usize { if (this == null) { return null; } - errdefer ast.printNodeLine(ast.get(this.?).*); + // errdefer ast.printNodeLine(ast.get(this.?).*); const self = ast.get(this.?).kind.StatementList; var list = std.ArrayList(usize).init(ast.allocator); const last = self.lastStatement orelse self.firstStatement + 1; @@ -1357,6 +1358,13 @@ test "sema.check_binop_mul_bools" { // expect error try ting.expectError(TypeError.InvalidTypeExptectedInt, typeCheckFunction(&ast, funcLit)); } +test "sema.checkArrayAccess" { + const source = "fun main() void {int_array a; a = new int_array[10]; a[0] = 1;}"; + var ast = try testMe(source); + // var func = ast.getFunctionFromName("main"); + // var funcLit = func.?.*; + try typeCheck(&ast); +} test "sema.4mini" { // load source from file const source = @embedFile("4.mini"); From b414481df528815062b35367667fa939357e9ea7 Mon Sep 17 00:00:00 2001 From: dleiferives Date: Tue, 14 May 2024 11:01:43 -0700 Subject: [PATCH 15/20] Int arrays type check successfully now --- .gitignore | 1 + TODO.dylan | 6 ---- src/ast.zig | 14 ++++++++ src/parser.zig | 26 ++++++++------ src/sema.zig | 96 +++++++++++++++++++++++++++++++++++++++++++++++--- test-suite | 1 + 6 files changed, 122 insertions(+), 22 deletions(-) delete mode 100644 TODO.dylan create mode 160000 test-suite diff --git a/.gitignore b/.gitignore index e94cc28..3fc90cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ zig-cache zig-out /kcov-output/ +TODO.dylan diff --git a/TODO.dylan b/TODO.dylan deleted file mode 100644 index e57867c..0000000 --- a/TODO.dylan +++ /dev/null @@ -1,6 +0,0 @@ -1. All return paths to be valid - Sidequest: To accomplish need to get the get type function to work - A. ITerate through the statment listfor the functions and if they return to be valid then we can assume that this is tre. - when we hit a conditional we check its block, if there is an else we also check that members block. If both paths return we can return true. - otherwise we check if it falls through - diff --git a/src/ast.zig b/src/ast.zig index db481fe..4bf84b1 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -1186,3 +1186,17 @@ test "ast.getGloablStructTypeFromName_notFound" { const ty = ast.getDeclarationGlobalFromName("b"); try ting.expect(ty == null); } + +test "ast.int_array_main" { + errdefer log.print(); + const input = "fun main() void { int_array a; a = new int_array[10]; }"; + var ast = try testMe(input); + _ = ast.getFunctionDeclarationTypeFromName("main", "a"); +} + +test "ast.int_array_access" { + errdefer log.print(); + const input = "fun main() void { int_array a; a = new int_array[10]; a[0] = 1; }"; + var ast = try testMe(input); + _ = ast; +} diff --git a/src/parser.zig b/src/parser.zig index 5296feb..4b7b3fe 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -186,7 +186,7 @@ pub const Parser = struct { pub fn isCurrentTokenAType(self: *Parser) !bool { switch ((try self.currentToken()).kind) { - TokenKind.KeywordInt, TokenKind.KeywordBool, TokenKind.KeywordStruct => { + TokenKind.KeywordInt, TokenKind.KeywordBool, TokenKind.KeywordStruct, TokenKind.KeywordIntArray => { return true; }, else => { @@ -428,7 +428,7 @@ pub const Parser = struct { return declIndex; } - // Type = "int" | "bool" | "struct" Identifier + // Type = "int" | "bool" | "struct" Identifier | "int_array" pub fn parseType(self: *Parser) !usize { errdefer { if (self.showParseTree) { @@ -1595,7 +1595,10 @@ pub const Parser = struct { } else if (nextToken.kind == .KeywordIntArray) { _ = try self.expectToken(.KeywordIntArray); _ = try self.expectToken(.LBracket); - _ = try self.expectToken(.Number); + _ = self.expectToken(.Number) catch { + log.err("Expected a number after new int[]\n", .{}); + return error.InvalidToken; + }; _ = try self.expectToken(.RBracket); numTokens += 4; @@ -1652,7 +1655,7 @@ pub const Parser = struct { } /// Parses a chain of selectors - /// `{ "." Identifier }*` + /// `{ "." Identifier }*{ "[" Expression "]" }?` /// expects caller to parse first item in chain /// i.e. Factor for `Selector` and `Identifier` for `LValue` pub fn parseSelectorChain(self: *Parser) !?usize { @@ -1827,7 +1830,7 @@ pub const Parser = struct { const identNewNumberNode = try self.astAppendNode(newNumberNode); const newNode = Node{ - .kind = .{ .New = .{ .ident = identNewNumberNode } }, + .kind = .{ .NewIntArray = .{ .length = identNewNumberNode } }, .token = newToken, }; try self.set(newIndex, newNode); @@ -2205,12 +2208,13 @@ test "fun.with_locals" { try ting.expect(nodes[funNode.kind.Function.proto].kind == .FunctionProto); // TODO: add more checks for function subtree structure } -test "parser.checkArrayAccess" { - const source = "int_array a; a = new int_array[10];}"; +test "parser.1checkArrayAccess" { + const source = "int_array a; fun main() void{ a = new int_array[10];}"; _ = try parseMe(source); } -// test "parser.checkArrayAccess" { -// const source = "fun main() void {int_array a; a = new int_array[10]; a[0] = 1;}"; -// _ = try parseMe(source); -// } +test "parser.checkArrayAccess" { + const source = "fun main() void {int_array a; a = new int_array[10]; a[0] = 1;}"; + + _ = try parseMe(source); +} diff --git a/src/sema.zig b/src/sema.zig index 4755852..c9af393 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -13,6 +13,7 @@ const SemaError = error{ const TypeError = error{ InvalidType, + InvalidToken, InvalidFunctionCall, OutOfBounds, OutOfMemory, @@ -680,6 +681,7 @@ pub fn getAndCheckFactor(ast: *const Ast, factorn: Ast.Node, fName: []const u8, .True, .False => return Ast.Type.Bool, .Null => return Ast.Type.Null, .New => return try getAndCheckNew(ast, node), + .NewIntArray => return getAndCheckNewIntArray(ast, node), .Invocation => return try getAndCheckInvocation(ast, node, fName, returnType), .Expression => return try getAndCheckTypeExpression(ast, node, fName, returnType), .Identifier => return try getAndCheckLocalIdentifier(ast, node, fName), @@ -703,6 +705,17 @@ pub fn getAndCheckNew(ast: *const Ast, newn: Ast.Node) TypeError!Ast.Type { return Ast.Type{ .Struct = name }; } +pub fn getAndCheckNewIntArray(ast: *const Ast, newn: Ast.Node) TypeError!Ast.Type { + // errdefer ast.printNodeLine(newn); + const new = newn.kind.NewIntArray; + // check that len is a number node + const len = ast.get(new.length).kind; + if (len != .Number) { + utils.todo("Error on newIntArray type checking\n", .{}); + return error.InvalidType; + } + return Ast.Type.IntArray; +} pub fn getAndCheckLocalIdentifier(ast: *const Ast, localId: Ast.Node, fName: []const u8) TypeError!Ast.Type { // errdefer ast.printNodeLine(localId); const token = localId.token; @@ -890,14 +903,25 @@ pub fn LValuegetType(this: ?usize, ast: *const Ast, fName: []const u8) !?Ast.Typ // errdefer ast.printNodeLine(ast.get(this.?).*); const self = ast.get(this.?).kind.LValue; const identNode = ast.get(self.ident); + // check if the ident is an identifier or an expression + switch (identNode.kind) { + .Identifier => {}, + .Expression => { + const exp_I_arr = try getAndCheckTypeExpression(ast, ast.get(identNode.kind.Expression.expr).*, fName, Ast.Type.Int); + if (!exp_I_arr.equals(Ast.Type.Int)) { + return error.InvalidTypeExptectedInt; + } + return Ast.Type.Int; + }, + else => { + utils.todo("Error on lvalue type checking\n", .{}); + return error.InvalidType; + }, + } const ident = identNode.token._range.getSubStrFromStr(ast.input); // const g_decl = ast.getDeclarationGlobalFromName(ident); const f_decl = try getAndCheckLocalIdentifier(ast, identNode.*, fName); var decl = f_decl; - // if (decl == null) { - // // TODO: add error - // return error.InvalidAssignmentNoDeclaration; - // } var result: ?Ast.Type = null; var tmpIdent = ident; @@ -905,12 +929,56 @@ pub fn LValuegetType(this: ?usize, ast: *const Ast, fName: []const u8) !?Ast.Typ if (chaini == null) { return decl; } + // check if type is a struct or an intarray + switch (decl) { + .Struct => {}, + .IntArray => { + // check if the chain is an expression + const chainIdent = ast.get(chaini.?).kind.SelectorChain.ident; + const chainIdentNode = ast.get(chainIdent).kind; + switch (chainIdentNode) { + .Expression => { + const exprI_ARR = try getAndCheckTypeExpression(ast, ast.get(chainIdentNode.Expression.expr).*, fName, Ast.Type.Int); + if (!exprI_ARR.equals(Ast.Type.Int)) { + return error.InvalidTypeExptectedInt; + } + return Ast.Type.Int; + }, + else => { + utils.todo("Error on lvalue type checking, expexcted xpression\n", .{}); + return error.InvalidType; + }, + } + }, + else => { + utils.todo("Error on lvalue type checking\n", .{}); + return error.InvalidType; + }, + } tmpIdent = decl.Struct; tmpIdent = ast.get(ast.getStructNodeFromName(tmpIdent).?.kind.TypeDeclaration.ident).token._range.getSubStrFromStr(ast.input); var chain = ast.get(chaini.?).kind.SelectorChain; while (true) { - const chainIdent = ast.get(chain.ident).token._range.getSubStrFromStr(ast.input); + var chainIdent_K = ast.get(chain.ident); + // check if the ident is an identifier or an expression + switch (chainIdent_K.kind) { + .Identifier => {}, + .Expression => { + const exp_type = try getAndCheckTypeExpression(ast, ast.get(chainIdent_K.kind.Expression.expr).*, fName, Ast.Type.Int); + // assert exp_type.equals(Ast.Type.Int); + if (!exp_type.equals(Ast.Type.Int)) { + return error.InvalidTypeExptectedInt; + } + return Ast.Type.Int; + }, + else => { + utils.todo("Error on lvalue type checking\n", .{}); + return error.InvalidType; + }, + } + + const chainIdent = chainIdent_K.token._range.getSubStrFromStr(ast.input); const field = ast.getStructFieldType(tmpIdent, chainIdent); if (field == null) { // TODO: add error @@ -1372,3 +1440,21 @@ test "sema.4mini" { // expect error InvalidAssignmentType try typeCheck(&ast); } + +test "sema.ia_invalid_access" { + const source = "fun main() void {int_array a; a = new int_array[10]; a[true] = 1;}"; + var ast = try testMe(source); + // expect error + try ting.expectError(TypeError.InvalidTypeExptectedInt, typeCheck(&ast)); +} + +test "sema.ia_invalid_new" { + const source = "fun main() void {int_array a; a = new int_array[true];}"; + _ = try ting.expectError(TypeError.InvalidToken, testMe(source)); +} + +test "sema_ia_lots_of_errors" { + const source = "fun main() void {int_array a; int b; int c; a = new int_array[0]; c = b + a[100000000]; a = new int_array[2000]; a[0] = c;}"; + _ = try testMe(source); + // expect error +} diff --git a/test-suite b/test-suite new file mode 160000 index 0000000..6c55485 --- /dev/null +++ b/test-suite @@ -0,0 +1 @@ +Subproject commit 6c55485068ab874bd626834ce99ca5f0c1c79f09 From d575020e11bac6bc3f7abdb914d9c6a2fb372904 Mon Sep 17 00:00:00 2001 From: dleiferives Date: Tue, 14 May 2024 11:08:17 -0700 Subject: [PATCH 16/20] Added tests that show incorrect logic --- src/sema.zig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/sema.zig b/src/sema.zig index c9af393..7dafca5 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -1458,3 +1458,24 @@ test "sema_ia_lots_of_errors" { _ = try testMe(source); // expect error } + +test "sema_ia.structs" { + const source = "struct S {int a;}; fun main() void {int_array a; struct S b; a = new int_array[10]; b.a = a[0];}"; + var ast = try testMe(source); + // expect error + try typeCheck(&ast); +} + +test "sema.ia_structs_assign_retrive" { + const source = "struct S {int a;}; fun main() void {int_array a; struct S b; a = new int_array[10]; b.a = a[0]; a[0] = b.a;}"; + var ast = try testMe(source); + // expect error + try typeCheck(&ast); +} + +test "sema.ia_int_arryay_member_struct" { + const source = "struct S {int_array a;}; fun main() void {struct S b; b.a = new int_array[10]; b.a[0] = 1;}"; + var ast = try testMe(source); + // expect error + try typeCheck(&ast); +} From e7bcf9853c82a65c2edd9ae81f37de4d7f3d02db Mon Sep 17 00:00:00 2001 From: dleiferives Date: Tue, 14 May 2024 13:01:00 -0700 Subject: [PATCH 17/20] int arrays are now implemented ~= 90% accuracy --- src/parser.zig | 30 ++++++++++++++++++++++++++++ src/sema.zig | 54 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/parser.zig b/src/parser.zig index 4b7b3fe..e9effc0 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -1611,6 +1611,36 @@ pub const Parser = struct { _ = try self.consumeToken(); try self.expectToken(.Identifier); numTokens += 2; + + var nextToken = try self.currentToken(); + if (nextToken.kind == .LBracket) { + numTokens += 1; + var count: u32 = 1; + // std.debug.print("LBracket I Am HEREERERERERERE\n", .{}); + _ = try self.consumeToken(); + while (count != 0) { + numTokens += 1; + const tok = try self.consumeToken(); + if (tok.kind == .Eof) { + // TODO: handle + return error.NotEnoughTokens; + } + if (tok.kind == .LBracket) { + count += 1; + } else if (tok.kind == .RBracket) { + count -= 1; + } + } + const current = try self.currentToken(); + if (current.kind == .Dot) { + _ = try self.consumeToken(); + try self.expectToken(.Identifier); + numTokens += 2; + } else { + const final = self.tokens[self.pos - 1]; + utils.assert(final.kind == .RBracket, "final token not RBracket, is: {}\n", .{final}); + } + } } }, .Number, .KeywordTrue, .KeywordFalse, .KeywordNull, .Identifier => { diff --git a/src/sema.zig b/src/sema.zig index 7dafca5..84602a3 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -664,7 +664,7 @@ pub fn getAndCheckSelector(ast: *const Ast, selectorn: Ast.Node, fName: []const const selector = selectorn.kind.Selector; const factorNode = ast.get(selector.factor).*; const factorType = try getAndCheckFactor(ast, factorNode, fName, returnType); - const chainType = try SelectorChaingetType(selector.chain, ast, factorType); + const chainType = try SelectorChaingetType(selector.chain, ast, factorType, fName, returnType); if (chainType == null) { return factorType; } @@ -733,16 +733,37 @@ pub fn getAndCheckLocalIdentifier(ast: *const Ast, localId: Ast.Node, fName: []c return localDecl.?; } -pub fn SelectorChaingetType(this: ?usize, ast: *const Ast, ty: Ast.Type) !?Ast.Type { +pub fn SelectorChaingetType(this: ?usize, ast: *const Ast, ty: Ast.Type, fName: []const u8, returnType: Ast.Type) !?Ast.Type { if (this == null) { return null; } - // check if type is a struct - if (!ty.isStruct()) { - utils.todo("this must be a struct, do error proper", .{}); - return null; + // check if its int array or struct + switch (ty) { + .IntArray => { + const chain = ast.get(this.?).kind.SelectorChain; + // check if chain.ident is identifier or expression + const ident = ast.get(chain.ident).kind; + switch (ident) { + .Identifier => { + return Ast.Type.IntArray; + }, + .Expression => { + const expr = ident.Expression; + const exprNode = ast.get(expr.expr).*; + return try getAndCheckTypeExpression(ast, exprNode, fName, returnType); + }, + else => { + return error.InvalidType; + }, + } + }, + .Struct => {}, + else => { + return error.InvalidType; + }, } + // get the ident of the struct const ident = ty.Struct; @@ -757,7 +778,20 @@ pub fn SelectorChaingetType(this: ?usize, ast: *const Ast, ty: Ast.Type) !?Ast.T var chain = ast.get(chaini.?).kind.SelectorChain; while (true) { - const chainIdent = ast.get(chain.ident).token._range.getSubStrFromStr(ast.input); + const chainIdent2 = ast.get(chain.ident); + // check if chain.ident is identifier or expression + switch (chainIdent2.kind) { + .Identifier => {}, + .Expression => { + const expr = chainIdent2.kind.Expression; + const exprNode = ast.get(expr.expr).*; + return try getAndCheckTypeExpression(ast, exprNode, fName, returnType); + }, + else => { + return error.InvalidType; + }, + } + const chainIdent = chainIdent2.token._range.getSubStrFromStr(ast.input); const field = ast.getStructFieldType(tmpIdent, chainIdent); if (field == null) { // TODO: add error @@ -1479,3 +1513,9 @@ test "sema.ia_int_arryay_member_struct" { // expect error try typeCheck(&ast); } +test "sema.ia_struct_toself" { + const source = "struct S {int_array a; int b;}; fun main() void {struct S c; c.a = new int_array[100]; c.b = c.a[20];}"; + var ast = try testMe(source); + // expect error + try typeCheck(&ast); +} From 0ae07d592906b3086bcbe5a4b80287469b076238 Mon Sep 17 00:00:00 2001 From: dleiferives Date: Tue, 14 May 2024 13:07:39 -0700 Subject: [PATCH 18/20] More testing --- src/sema.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sema.zig b/src/sema.zig index 84602a3..4d384f3 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -1519,3 +1519,10 @@ test "sema.ia_struct_toself" { // expect error try typeCheck(&ast); } + +test "sema.ia_struct_toself2" { + const source = "struct S {struct S s; int_array a; int b;}; fun main() void {struct S c; c.s.s.s.s.s.s.s.a = new int_array[100]; c.s.s.s.s.s.s.s.b = c.a[20]; c.s.s.s.s.s.s.s.s.s.a[20] = 2;}"; + var ast = try testMe(source); + // expect error + try typeCheck(&ast); +} From 77271af387df150d674df5ea96f953b9a117594d Mon Sep 17 00:00:00 2001 From: dleiferives Date: Tue, 14 May 2024 13:59:49 -0700 Subject: [PATCH 19/20] Merged the int array into main --- src/ir/ir.zig | 1 + src/sema.zig | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ir/ir.zig b/src/ir/ir.zig index f2c4360..eb598c7 100644 --- a/src/ir/ir.zig +++ b/src/ir/ir.zig @@ -78,6 +78,7 @@ pub fn astTypeToIRType(self: *IR, astType: Ast.Type) Type { .Bool => .bool, .Void => .void, .Null => std.debug.panic("FUCK WE HAVE TO HANDLE NULL TYPE\n", .{}), + .IntArray => utils.todo("Handle the array type", .{}), .Struct => |name| blk: { const structID = self.internIdent(name); break :blk .{ .strct = structID }; diff --git a/src/sema.zig b/src/sema.zig index 374604a..346c661 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -357,13 +357,9 @@ pub fn typeCheckAssignment(ast: *const Ast, assignmentn: Ast.Node, fName: []cons // FIXME: add error // chek if left is struct and right is null var lType = leftType.?; + _ = lType; var rType = rightType; - if (lType.equals(Ast.Type.Null) and rType.isStruct()) { - return; - } - if (lType.isStruct() and rType.equals(Ast.Type.Null)) { - return; - } + _ = rType; return error.InvalidAssignmentType; } } @@ -626,8 +622,8 @@ pub fn getAndCheckBinaryOperation(ast: *const Ast, binaryOp: Ast.Node, fName: [] .Plus, .Div, => { - const lhsExpr = ast.get(binaryOp.kind.BinaryOperation.lhs.?).*; - const rhsExpr = ast.get(binaryOp.kind.BinaryOperation.rhs.?).*; + const lhsExpr = ast.get(binaryOp.kind.BinaryOperation.lhs).*; + const rhsExpr = ast.get(binaryOp.kind.BinaryOperation.rhs).*; const lhsType = try getAndCheckTypeExpression(ast, lhsExpr, fName, returnType); const rhsType = try getAndCheckTypeExpression(ast, rhsExpr, fName, returnType); if (!lhsType.equals(rhsType)) { @@ -1544,3 +1540,10 @@ test "sema.ia_struct_toself2" { // expect error try typeCheck(&ast); } + +test "sema.struct_null" { + const source = "struct S {int a;}; fun main() void {struct S b; b = null;}"; + var ast = try testMe(source); + // expect error + try typeCheck(&ast); +} From 632601425458fa76b04f926f11b6e33512ff3d30 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 14 May 2024 14:22:10 -0700 Subject: [PATCH 20/20] fix array test suite names --- Justfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Justfile b/Justfile index 992c2da..a35b483 100644 --- a/Justfile +++ b/Justfile @@ -48,6 +48,7 @@ run-suite-test name: ensure-test-suite echo -e "${BLUE}Building Test Suite Test...${NC}" just build-suite-test {{name}} echo -e "${GREEN}BUILD SUCCESS${NC}" + dir="{{TEST_SUITE}}/{{name}}" bin="$dir/{{name}}" @@ -71,6 +72,8 @@ run-suite-test name: ensure-test-suite build-suite-test name: build #!/usr/bin/env bash set -euxo pipefail + name="{{name}}" + name="${name#array_}" dir="{{TEST_SUITE}}/{{name}}" - {{minipp}} -i "$dir/{{name}}.mini" -o "$dir/{{name}}.ll" + {{minipp}} -i "$dir/${name}.mini" -o "$dir/{{name}}.ll" clang "$dir/{{name}}.ll" -o "$dir/{{name}}"