diff options
| -rw-r--r-- | build.zig | 2 | ||||
| -rw-r--r-- | examples/test.nya | 6 | ||||
| -rw-r--r-- | src/codegen.zig | 38 | ||||
| -rw-r--r-- | src/main.zig | 2 | ||||
| -rw-r--r-- | src/parser.zig | 116 | ||||
| -rw-r--r-- | src/tokenize.zig | 49 |
6 files changed, 206 insertions, 7 deletions
@@ -52,6 +52,8 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }); + codegen_unit_tests.root_module.addImport("llvm", llvm.module("llvm")); + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); const run_token_unit_tests = b.addRunArtifact(token_unit_tests); const run_parse_unit_tests = b.addRunArtifact(parse_unit_tests); diff --git a/examples/test.nya b/examples/test.nya index 3088546..0b359aa 100644 --- a/examples/test.nya +++ b/examples/test.nya @@ -1,6 +1,8 @@ fn main() -> i32 { const testval = 6; var testvar = testval; - testvar = 5; - return testvar; + testvar = 5 + 3 * 7; + if (1 == 1) return testvar; + + return 7; } diff --git a/src/codegen.zig b/src/codegen.zig index 59ef03b..51908c1 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -156,6 +156,30 @@ pub const Generator = struct { _ = if (self.currentFuncIsVoid) core.LLVMBuildRetVoid(self.builder); } + fn genIf(self: *Generator, stmt: parse.NodeStmt) error{ OutOfMemory, Immutable }!void { + const ifkind = stmt.kind.ifstmt; + const block = ifkind.body; + const expr = ifkind.expr; + + const condition = 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 { try switch (stmt.kind) { .exit => |expr| self.genExit(expr), @@ -163,6 +187,7 @@ pub const Generator = struct { .defValue => self.genValue(stmt), .defVar => self.genVar(stmt), .assignVar => self.genAssign(stmt), + .ifstmt => self.genIf(stmt), else => {}, }; } @@ -176,6 +201,19 @@ pub const Generator = struct { break :blk core.LLVMBuildLoad2(self.builder, toLLVMtype(expr.typ.?, table), ptr, ""); }, .intLit => |int| core.LLVMConstInt(core.LLVMInt32TypeInContext(self.context), @intCast(int.intLit), 1), + .binaryOp => |exp| blk: { + const lhs = self.genExpr(exp.lhs.*); + const rhs = self.genExpr(exp.rhs.*); + + 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"), + }; + }, }; } diff --git a/src/main.zig b/src/main.zig index 1e54dec..613d8f9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -59,11 +59,11 @@ pub fn main() !void { // Codegen var arena = std.heap.ArenaAllocator.init(allocator); - defer arena.deinit(); var generator = gen.Generator.init(arena.allocator(), tree); defer generator.deinit(); const code = try generator.generate(); try outWriter.writeAll(code); + arena.deinit(); const binFile = try getFileName(allocator, out_name, ""); defer allocator.free(binFile); diff --git a/src/parser.zig b/src/parser.zig index 08f098c..129bf94 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -85,6 +85,7 @@ pub const NodeStmt = struct { for (blockChildren) |child| try childrenArray.append(child); }, .function => |fun| try childrenArray.append(fun.block.*.asNode()), + .ifstmt => |ifstmt| try childrenArray.append(ifstmt.body.*.asNode()), } return try childrenArray.toOwnedSlice(); } @@ -141,9 +142,40 @@ pub const Parser = struct { self.nodes.deinit(); } + // fn parseExpr(self: *Parser) !NodeExpr { + // var typ: ?TypeIdent = null; + // const kind = try blk: { + // try switch (self.tokens.peek().?) { + // .intLit => { + // typ = TypeIdent{ + // .ident = "i32", + // .list = false, + // }; + // break :blk ExprKind{ .intLit = (try self.tokens.consume(.intLit)).? }; + // }, + // .ident => { + // const ident = (try self.tokens.consume(.ident)).?; + // typ = TypeIdent{ + // .ident = "i32", + // .list = false, + // }; + // break :blk ExprKind{ .ident = ident }; + // }, + // else => break :blk ParsingError.InvalidExpression, + // }; + // }; + // return NodeExpr{ + // .id = self.reserveId(), + // .kind = kind, + // .isConst = kind.isConstant(), + // .typ = typ, + // .symtable = self.top, + // }; + // } + fn parseExpr(self: *Parser) !NodeExpr { var typ: ?TypeIdent = null; - const kind = try blk: { + const kind: ExprKind = try blk: { try switch (self.tokens.peek().?) { .intLit => { typ = TypeIdent{ @@ -163,26 +195,90 @@ pub const Parser = struct { else => break :blk 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 genBinOp(self, precTable[0], typ, lhsptr) //. + orelse try genBinOp(self, precTable[1], typ, lhsptr) //. + orelse try genBinOp(self, precTable[2], typ, lhsptr) //. + orelse 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(), .ident => try self.parseAssign(), .fun => try self.parseFunc(), + .openBrace => try self.parseBlock(), else => ParsingError.InvalidStatement, }; } + 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) ParsingError!NodeStmt { var typ: ?TypeIdent = null; _ = try self.tokens.consume(.fun); @@ -338,12 +434,19 @@ pub const NodeVar = struct { expr: NodeExpr, }; +pub const NodeIf = struct { + expr: NodeExpr, + body: *NodeStmt, +}; + pub const NodeExit = NodeExpr; pub const NodeIntlit = Token; pub const NodeIdent = Token; pub const NodeBlock = []const NodeStmt; +pub const NodeBinOp = Token; pub const StmtKind = union(enum) { + ifstmt: NodeIf, function: NodeFunction, exit: NodeExit, defValue: NodeValue, @@ -355,6 +458,11 @@ pub const StmtKind = union(enum) { pub const ExprKind = union(enum) { intLit: NodeIntlit, ident: NodeIdent, + binaryOp: struct { + lhs: *NodeExpr, + rhs: *NodeExpr, + op: NodeBinOp, + }, pub fn isConstant(self: ExprKind) bool { return switch (self) { diff --git a/src/tokenize.zig b/src/tokenize.zig index 770f483..6fc0ebc 100644 --- a/src/tokenize.zig +++ b/src/tokenize.zig @@ -11,6 +11,7 @@ pub const TokenType = enum { ident, intLit, // Keywords + ifstmt, constant, variable, exit, @@ -22,6 +23,9 @@ pub const TokenType = enum { slash, semiCol, equal, + eqleql, + lessthan, + greaterthan, // Symbols openBrace, closeBrace, @@ -35,6 +39,7 @@ pub const Token = union(TokenType) { ident: []const u8, intLit: i32, // Keywords + ifstmt, constant, variable, exit, @@ -46,6 +51,9 @@ pub const Token = union(TokenType) { slash, semiCol, equal, + eqleql, + lessthan, + greaterthan, // Symbols openBrace, closeBrace, @@ -53,6 +61,35 @@ pub const Token = union(TokenType) { closeParen, arrow, + pub fn toTokenType(self: Token) TokenType { + switch (self) { + .ident => .ident, + .intLit => .intLit, + // Keywords + .ifstmt => .ifstmt, + .constant => .constant, + .variable => .variable, + .exit => .exit, + .fun => .fun, + // => Operators .=> + .plus => .plus, + .minus => .minus, + .star => .star, + .slash => .slash, + .semiCol => .semiCol, + .equal => .equal, + .eqleql => .eqleql, + .lessthan => .lessthan, + .greaterthan => .greaterthan, + // => Symbols .=> + .openBrace => .openBrace, + .closeBrace => .closeBrace, + .openParen => .openParen, + .closeParen => .closeParen, + .arrow => .arrow, + } + } + pub fn fromChar(char: u8) !Token { return switch (char) { '+' => .plus, @@ -65,6 +102,8 @@ pub const Token = union(TokenType) { '}' => .closeBrace, '(' => .openParen, ')' => .closeParen, + '<' => .lessthan, + '>' => .greaterthan, else => TokenizeError.UnknownToken, }; } @@ -75,6 +114,7 @@ pub const Token = union(TokenType) { if (eql(u8, str, "const")) return .constant; if (eql(u8, str, "var")) return .variable; if (eql(u8, str, "fn")) return .fun; + if (eql(u8, str, "if")) return .ifstmt; return Token{ .ident = str }; } }; @@ -160,6 +200,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().? != '>') { |
