diff options
| -rw-r--r-- | examples/mathTest.nya | 7 | ||||
| -rw-r--r-- | examples/test.nya | 8 | ||||
| -rw-r--r-- | src/codegen.zig | 54 | ||||
| -rw-r--r-- | src/main.zig | 13 | ||||
| -rw-r--r-- | src/parser.zig | 119 | ||||
| -rw-r--r-- | src/symtable.zig | 8 | ||||
| -rw-r--r-- | src/tokenize.zig | 28 |
7 files changed, 212 insertions, 25 deletions
diff --git a/examples/mathTest.nya b/examples/mathTest.nya index 280d53d..f937b79 100644 --- a/examples/mathTest.nya +++ b/examples/mathTest.nya @@ -8,6 +8,11 @@ fn test() -> i32 { fn main() -> i32 { const: i32 num = 5; const: i32 num2 = test(); - puts("Hello World!"); + if (num2 == test()) { + puts("Hello World!"); + } + if (num2 == 0) { + puts("Shouldn't print"); + } return num2; } diff --git a/examples/test.nya b/examples/test.nya new file mode 100644 index 0000000..0b359aa --- /dev/null +++ b/examples/test.nya @@ -0,0 +1,8 @@ +fn main() -> i32 { + const testval = 6; + var testvar = testval; + testvar = 5 + 3 * 7; + if (1 == 1) return testvar; + + return 7; +} diff --git a/src/codegen.zig b/src/codegen.zig index 8f3160e..7aff0b6 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -81,6 +81,7 @@ pub const Generator = struct { const table = stmt.symtable; const symbol = table.getValue(nodeVar.ident.ident).?; const value = try self.genExpr(nodeVar.expr); + // const ptr = try self.genAlloc(toLLVMtype(nodeVar.expr.typ.?, table).?, nodeVar.ident.ident); const ptr = try self.genAlloc( toLLVMtype( nodeVar.expr.typ orelse try nodeVar.expr.symtable.getValue(nodeVar.ident.ident).?.typ.toTypeIdent(self.allocator), @@ -98,9 +99,11 @@ pub const Generator = struct { const table = stmt.symtable; const symbol = table.getValue(nodeVar.ident.ident).?; + // const ptr = try self.genAlloc(toLLVMtype(nodeVar.expr.typ.?, table), nodeVar.ident.ident); const ptr = try self.genAlloc(toLLVMtype(nodeVar.expr.typ orelse try nodeVar.expr.inferType(self.allocator, table), table, nodeVar.expr), nodeVar.ident.ident); const value = try self.genExpr(nodeVar.expr); _ = core.LLVMBuildStore(self.builder, value, ptr); + std.debug.print("\t\t\tGenerated Value {s}\n", .{nodeVar.ident.ident}); try self.references.put(symbol.id, ptr); } @@ -120,9 +123,9 @@ pub const Generator = struct { return core.LLVMBuildAlloca(builder, typ, str); } - fn asBasicType(typ: symb.SymbType) ?types.LLVMTypeKind { + fn asBasicType(typ: symb.SymbType) ?types.LLVMTypeRef { return switch (typ) { - .Integer => types.LLVMTypeKind.LLVMIntegerTypeKind, + .Integer => core.LLVMInt32Type(), else => null, }; } @@ -186,13 +189,39 @@ pub const Generator = struct { } } + fn genIf(self: *Generator, stmt: parse.NodeStmt) CodegenError!void { + const ifkind = stmt.kind.ifstmt; + const block = ifkind.body; + const expr = ifkind.expr; + + const condition = try self.genExpr(expr); + const func = self.currentFunc.?; + + const then = core.LLVMAppendBasicBlock(func, "then"); + const elsebb = core.LLVMAppendBasicBlock(func, "elsebb"); + const cont = core.LLVMAppendBasicBlock(func, "continue"); + + _ = core.LLVMBuildCondBr(self.builder, condition, then, elsebb); + + _ = core.LLVMPositionBuilderAtEnd(self.builder, then); + try self.genStmt(block.*); + _ = core.LLVMBuildBr(self.builder, cont); + + _ = core.LLVMPositionBuilderAtEnd(self.builder, elsebb); + _ = core.LLVMBuildBr(self.builder, cont); + + _ = core.LLVMPositionBuilderAtEnd(self.builder, cont); + } + fn genStmt(self: *Generator, stmt: parse.NodeStmt) !void { + std.debug.print("======\n\tStmt: {any}\n======\n", .{stmt.kind}); try switch (stmt.kind) { .exit => |expr| self.genExit(expr), .function => self.genFunc(stmt), .defValue => self.genValue(stmt), .defVar => self.genVar(stmt), .assignVar => self.genAssign(stmt), + .ifstmt => self.genIf(stmt), .expr => |expression| { _ = try self.genExpr(expression); }, @@ -230,6 +259,20 @@ pub const Generator = struct { ); }, .intLit => |int| core.LLVMConstInt(core.LLVMInt32TypeInContext(self.context), @intCast(int.intLit), 1), + .binaryOp => |exp| blk: { + const lhs = try self.genExpr(exp.lhs.*); + const rhs = try self.genExpr(exp.rhs.*); + std.debug.print("\n\n\tLHS: {any}\n\tRHS: {any}\n\tOP: {any}\n\n", .{ lhs, rhs, exp.op }); + + break :blk switch (exp.op) { + .plus => core.LLVMBuildAdd(self.builder, lhs, rhs, "add"), + .minus => core.LLVMBuildSub(self.builder, lhs, rhs, "sub"), + .star => core.LLVMBuildMul(self.builder, lhs, rhs, "mul"), + .slash => core.LLVMBuildSDiv(self.builder, lhs, rhs, "div"), + .eqleql => core.LLVMBuildICmp(self.builder, types.LLVMIntPredicate.LLVMIntEQ, lhs, rhs, "eql"), + else => core.LLVMBuildICmp(self.builder, types.LLVMIntPredicate.LLVMIntEQ, lhs, rhs, "eql"), + }; + }, .stringLit => |str| blk: { const vref = core.LLVMAddGlobal( self.module, @@ -254,7 +297,7 @@ pub const Generator = struct { const ident = try self.allocator.dupeZ(u8, call.ident.ident); const function = core.LLVMGetNamedFunction(self.module, ident); var args = std.ArrayList(types.LLVMValueRef).init(self.allocator); - for (call.args, functype.input) |arg, intype| { + for (call.args.items, functype.input) |arg, intype| { if (!std.meta.eql(expr.symtable.getType(arg.typ.?).?, intype)) return CodegenError.IncorrectType; try args.append(try self.genExpr(arg)); } @@ -266,7 +309,7 @@ pub const Generator = struct { funcType, function, @ptrCast(args.items), - @intCast(call.args.len), + @intCast(call.args.items.len), ident, ); // std.debug.print("CALL\n", .{}); @@ -279,8 +322,9 @@ pub const Generator = struct { pub fn generate(self: *Generator) ![]const u8 { try switch (self.root.kind) { .block => |b| { - for (b) |stmt| + for (b) |stmt| { try self.genStmt(stmt); + } }, else => error.InvalidTop, }; diff --git a/src/main.zig b/src/main.zig index 05dde7d..b51b170 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5,6 +5,12 @@ const gen = @import("codegen.zig"); const symb = @import("symtable.zig"); pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const alc = gpa.allocator(); + defer _ = gpa.deinit(); + var arena = std.heap.ArenaAllocator.init(alc); + defer arena.deinit(); + var allocator = arena.allocator(); if (std.os.argv.len < 2) { std.debug.print( \\info: Usage: calico [input file] @@ -13,10 +19,6 @@ pub fn main() !void { return; } - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - var allocator = gpa.allocator(); - defer _ = gpa.deinit(); - var args = std.process.args(); _ = args.skip(); const inputFileName = args.next(); @@ -47,8 +49,7 @@ pub fn main() !void { const tokens = try tokenizer.tokenize(); // Parse - var arena = std.heap.ArenaAllocator.init(allocator); - defer arena.deinit(); + // var arena = std.heap.ArenaAllocator.init(allocator); const symbTable = try initSymbolTable(arena.allocator()); var parser = parse.Parser.init(arena.allocator(), tokens, symbTable); diff --git a/src/parser.zig b/src/parser.zig index f2dba0a..66d02a2 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -68,6 +68,7 @@ pub const NodeExpr = struct { .call => |call| if (table.getValue(call.ident.ident)) |symbol| try symbol.typ.Function.output.toTypeIdent(allocator) else TypeError.UnknownIdentifier, .ident => |id| if (table.getValue(id.ident)) |symbol| try symbol.typ.toTypeIdent(allocator) else TypeError.UnknownIdentifier, .intLit => TypeIdent{ .ident = "i32", .list = false }, + .binaryOp => TypeIdent{ .ident = "i32", .list = false }, .stringLit => TypeIdent{ .ident = "[u8]", .list = true }, }; if (self.typ) |typ| { @@ -107,6 +108,7 @@ pub const NodeStmt = struct { const blockChildren = map(Node, NodeStmt, block, NodeStmt.asNode); for (blockChildren) |child| try childrenArray.append(child); }, + .ifstmt => |ifstmt| try childrenArray.append(ifstmt.body.*.asNode()), .function => |fun| if (fun.block == null) {} else try childrenArray.append(fun.block.?.asNode()), .expr => |expr| try childrenArray.append(expr.asNode()), } @@ -167,9 +169,30 @@ pub const Parser = struct { self.nodes.deinit(); } + fn parseCall(self: *Parser, typ: ?TypeIdent, expr: NodeExpr) ParsingError!NodeExpr { + if (self.tokens.peek().? != .openParen) return expr; + _ = try self.tokens.consume(.openParen); + var args = std.ArrayList(NodeExpr).init(self.allocator); + while (self.tokens.peek().? != .closeParen) { + try args.append(try self.parseExpr()); + if (self.tokens.peek().? != .comma) break; + } + _ = try self.tokens.consume(.closeParen); + + const kind = ExprKind{ .call = .{ .ident = expr.kind.ident, .args = args } }; + return NodeExpr{ + .kind = kind, + .isConst = false, + .typ = typ, + .id = self.reserveId(), + .symtable = self.top, + }; + } + fn parseExpr(self: *Parser) !NodeExpr { var typ: ?TypeIdent = null; - const kind = try blk: { + var isIdent = false; + const kind: ExprKind = try blk: { try switch (self.tokens.peek().?) { .intLit => { typ = TypeIdent{ @@ -179,6 +202,7 @@ pub const Parser = struct { break :blk ExprKind{ .intLit = (try self.tokens.consume(.intLit)).? }; }, .ident => { + isIdent = true; const ident = (try self.tokens.consume(.ident)).?; if (tok.checkType(self.tokens.peek().?, .openParen)) { _ = try self.tokens.consume(.openParen); @@ -195,7 +219,7 @@ pub const Parser = struct { } _ = try self.tokens.consume(.closeParen); - break :innerblk try argExprs.toOwnedSlice(); + break :innerblk try argExprs.clone(); }, }, }; @@ -210,20 +234,66 @@ pub const Parser = struct { }; break :blk ExprKind{ .stringLit = (try self.tokens.consume(.stringLit)).? }; }, - else => break :blk ParsingError.InvalidExpression, + else => |expr| break :blk errorblk: { + std.debug.print("Invalid Expression: {any}\n", .{expr}); + break :errorblk ParsingError.InvalidExpression; + }, }; }; - return NodeExpr{ + + const lhs = NodeExpr{ .id = self.reserveId(), + .isConst = false, .kind = kind, - .isConst = kind.isConstant(), - .typ = typ, .symtable = self.top, + .typ = typ, }; + + const lhsptr = try self.allocator.create(NodeExpr); + lhsptr.* = lhs; + + const precTable: []const []const tok.TokenType = &.{ + &.{ .plus, .minus }, + &.{ .star, .slash }, + &.{.eqleql}, + }; + + return try self.genBinOp(precTable[0], typ, lhsptr) //. + orelse try self.genBinOp(precTable[1], typ, lhsptr) //. + orelse try self.genBinOp(precTable[2], typ, lhsptr) //. + orelse if (isIdent) blk: { + break :blk try self.parseCall(typ, lhsptr.*); + } //. + else lhs; + } + + fn genBinOp(self: *Parser, comptime ops: []const tok.TokenType, typ: ?TypeIdent, lhs: *NodeExpr) ParsingError!?NodeExpr { + for (ops) |op| + if (self.tokens.peek().? == op) { + const oper = self.tokens.next(); + const rhsptr = try self.allocator.create(NodeExpr); + rhsptr.* = try self.parseExpr(); + const kind = ExprKind{ + .binaryOp = .{ + .lhs = lhs, + .rhs = rhsptr, + .op = oper.?, + }, + }; + return NodeExpr{ + .id = self.reserveId(), + .isConst = false, + .kind = kind, + .symtable = self.top, + .typ = typ, + }; + }; + return null; } fn parseStmt(self: *Parser) ParsingError!NodeStmt { return switch (self.tokens.peek().?) { + .ifstmt => try self.parseIf(), .exit => try self.parseExit(), .constant => try self.parseConstant(), .variable => try self.parseVariable(), @@ -232,6 +302,7 @@ pub const Parser = struct { break :blk try self.parseAssign(); break :blk try self.parseExprStmt(); }, + .openBrace => self.parseBlock(), .fun => try self.parseFunc(false), .import => try self.parseFunc(true), else => self.parseExprStmt(), @@ -248,6 +319,28 @@ pub const Parser = struct { }; } + fn parseIf(self: *Parser) ParsingError!NodeStmt { + _ = try self.tokens.consume(.ifstmt); // if + + _ = try self.tokens.consume(.openParen); // ( + const expr = try self.parseExpr(); // EXPR + _ = try self.tokens.consume(.closeParen); // ) + + const body = try self.allocator.create(NodeStmt); + body.* = try self.parseStmt(); + + const kind = StmtKind{ + .ifstmt = .{ + .expr = expr, + .body = body, + }, + }; + return NodeStmt{ + .id = self.reserveId(), + .kind = kind, + .symtable = self.top, + }; + } fn parseFunc(self: *Parser, external: bool) ParsingError!NodeStmt { if (external) _ = try self.tokens.consume(.import); var typ: ?TypeIdent = null; @@ -485,18 +578,25 @@ pub const NodeVar = struct { expr: NodeExpr, }; +pub const NodeIf = struct { + expr: NodeExpr, + body: *NodeStmt, +}; + pub const NodeExit = NodeExpr; pub const NodeIntlit = Token; pub const NodeStringlit = Token; pub const NodeIdent = Token; pub const NodeBlock = []const NodeStmt; +pub const NodeBinOp = Token; pub const NodeCall = struct { ident: Token, - args: []const NodeExpr, + args: std.ArrayList(NodeExpr), }; pub const StmtKind = union(enum) { + ifstmt: NodeIf, function: NodeFunction, exit: NodeExit, defValue: NodeValue, @@ -511,6 +611,11 @@ pub const ExprKind = union(enum) { stringLit: NodeStringlit, ident: NodeIdent, call: NodeCall, + binaryOp: struct { + lhs: *NodeExpr, + rhs: *NodeExpr, + op: NodeBinOp, + }, pub fn isConstant(self: ExprKind) bool { return switch (self) { diff --git a/src/symtable.zig b/src/symtable.zig index 71596e2..3017670 100644 --- a/src/symtable.zig +++ b/src/symtable.zig @@ -204,6 +204,7 @@ pub const Populator = struct { try value.expr.inferType(self.allocator, table), false, ); + std.debug.print("Value: {s}\nSymbol: {any}\n", .{ value.ident.ident, symbol }); if (!try table.insert(value.ident.ident, symbol)) return error.FailedToInsert; }, .block => { @@ -231,8 +232,12 @@ pub const Populator = struct { }, .exit => |exit| _ = try exit.inferType(self.allocator, table), .expr => {}, + .ifstmt => for (try stmt.children(self.allocator)) |c| try self.populateSymtable(&c), - // else => return error.Unimplemented, + // else => |unim| return errorblk: { + // std.debug.print("Error: Unimplemented: {any}\n", .{unim}); + // break :errorblk error.Unimplemented; + // }, } }, else => { @@ -294,7 +299,6 @@ pub const Populator = struct { }; return value.toSymb(); } - // std.debug.print("{s}: ", .{typ.ident}); return error.UnknownType; } }; diff --git a/src/tokenize.zig b/src/tokenize.zig index b578b22..2c536db 100644 --- a/src/tokenize.zig +++ b/src/tokenize.zig @@ -14,6 +14,7 @@ pub const TokenType = enum { intLit, charLit, // Keywords + ifstmt, constant, variable, exit, @@ -26,6 +27,9 @@ pub const TokenType = enum { slash, semiCol, equal, + eqleql, + lessthan, + greaterthan, // Symbols openBrace, closeBrace, @@ -33,9 +37,9 @@ pub const TokenType = enum { closeParen, openBracket, closeBracket, + arrow, colon, comma, - arrow, }; pub const Token = union(TokenType) { @@ -45,6 +49,7 @@ pub const Token = union(TokenType) { intLit: i32, charLit: u8, // Keywords + ifstmt, constant, variable, exit, @@ -57,6 +62,9 @@ pub const Token = union(TokenType) { slash, semiCol, equal, + eqleql, + lessthan, + greaterthan, // Symbols openBrace, closeBrace, @@ -64,12 +72,13 @@ pub const Token = union(TokenType) { closeParen, openBracket, closeBracket, + arrow, colon, comma, - arrow, pub fn fromChar(char: u8) !Token { return switch (char) { + ',' => .comma, '+' => .plus, '-' => .minus, '*' => .star, @@ -80,10 +89,11 @@ pub const Token = union(TokenType) { '}' => .closeBrace, '(' => .openParen, ')' => .closeParen, + '<' => .lessthan, + '>' => .greaterthan, + ':' => .colon, '[' => .openBracket, ']' => .closeBracket, - ':' => .colon, - ',' => .comma, else => { // std.debug.print("{c}: ", .{char}); return TokenizeError.UnknownToken; @@ -97,6 +107,7 @@ pub const Token = union(TokenType) { if (eql(u8, str, "const")) return .constant; if (eql(u8, str, "varbl")) return .variable; if (eql(u8, str, "fn")) return .fun; + if (eql(u8, str, "if")) return .ifstmt; if (eql(u8, str, "import")) return .import; return Token{ .ident = str }; } @@ -186,6 +197,15 @@ pub const Tokenizer = struct { while (self.src.peek()) |char| { try switch (char) { + '=' => { + self.src.skip(); + if (self.src.peek().? != '=') { + try self.toks.append(.equal); + continue; + } + self.src.skip(); + try self.toks.append(.eqleql); + }, '-' => { self.src.skip(); if (self.src.peek().? != '>') { |
