diff --git a/examples/hello.ry b/examples/hello.ry index b8aec3a..ca959ab 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -1,6 +1,7 @@ // import std; fn f() i32 { + var a = 2; return 2; } diff --git a/src/ast.zig b/src/ast.zig index c68eefe..cb166d1 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -97,9 +97,6 @@ pub const AssignExpr = struct { pub const ExprType = enum { Assign, - // vardecls as expressions is a hack - VarDecl, - Binary, Unary, Literal, @@ -112,11 +109,6 @@ pub const ExprType = enum { Set, }; -pub const VarDecl = struct { - assign: AssignExpr, - mutable: bool = false, -}; - pub const CallExpr = struct { callee: *Expr, paren: Token, @@ -148,7 +140,6 @@ pub const SetExpr = struct { pub const Expr = union(ExprType) { Assign: AssignExpr, - VarDecl: VarDecl, Binary: BinaryExpr, Unary: UnaryExpr, @@ -181,10 +172,16 @@ pub const ForStmt = struct { block: Block, }; +pub const VarDeclStmt = struct { + name: Token, + value: *Expr, +}; + pub const Stmt = union(enum) { Expr: *Expr, Println: *Expr, + VarDecl: VarDeclStmt, If: IfStmt, Loop: LoopStmt, For: ForStmt, @@ -261,6 +258,18 @@ pub const Stmt = union(enum) { return stmt; } + + pub fn mkVarDecl(allocator: *std.mem.Allocator, name: Token, value: *Expr) !*Stmt { + var stmt = try allocator.create(Stmt); + stmt.* = Stmt{ + .VarDecl = VarDeclStmt{ + .name = name, + .value = value, + }, + }; + + return stmt; + } }; pub const FieldList = std.ArrayList(StructField); diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 0e9b549..82ecfde 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -239,18 +239,6 @@ pub fn printExpr(expr: *const Expr) void { .Variable => |token| std.debug.warn("{}", token.lexeme), - .VarDecl => |decl| { - if (decl.mutable) { - std.debug.warn("(mut "); - } else { - std.debug.warn("("); - } - - std.debug.warn("let {} ", decl.assign.name.lexeme); - printExpr(decl.assign.value); - std.debug.warn(")"); - }, - .Assign => |assign| { std.debug.warn("(set "); std.debug.warn("{} ", assign.name.lexeme); @@ -305,6 +293,12 @@ pub fn printStmt(ident: usize, stmt: *const Stmt) void { .Println => |expr| printSimpleOp("println", expr), .Expr => |expr| printExpr(expr), + .VarDecl => |decl| { + std.debug.warn("(let {} ", decl.name.lexeme); + printExpr(decl.value); + std.debug.warn(")"); + }, + .If => |ifstmt| { std.debug.warn("(if "); printExpr(ifstmt.condition); diff --git a/src/codegen.zig b/src/codegen.zig index 1be2e5a..c92f452 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -79,8 +79,6 @@ pub const Codegen = struct { // TODO VarDecl add things to the symbol table // TODO Assign modify symbol table - - // TODO Calls fetch symbol table, check arity of it at codegen level return switch (expr.*) { // TODO handle all literals, construct llvm values for them @@ -168,7 +166,6 @@ pub const Codegen = struct { .Call => |call| { const name = call.callee.*.Variable.lexeme; - //var sym = try self.ctx.fetchGlobalSymbol(func_name, .Function); var llvm_func = self.llvm_table.get(name); if (llvm_func == null) { @@ -176,7 +173,6 @@ pub const Codegen = struct { return CompileError.EmitError; } - // TODO args var args = LLVMValueList.init(self.allocator); errdefer args.deinit(); @@ -342,7 +338,6 @@ pub const Codegen = struct { llvm.LLVMPositionBuilderAtEnd(builder, entry); for (decl.body.toSlice()) |stmt| { - // TODO custom function context for us try self.emitStmt(builder, &stmt); } diff --git a/src/parsers.zig b/src/parsers.zig index 361fc66..04f9bf1 100644 --- a/src/parsers.zig +++ b/src/parsers.zig @@ -295,21 +295,6 @@ pub const Parser = struct { return expr; } - fn mkVarDecl(self: *@This(), name: Token, value: *Expr, mutable: bool) !*Expr { - var vardecl = try self.allocator.create(Expr); - vardecl.* = Expr{ - .VarDecl = ast.VarDecl{ - .assign = ast.AssignExpr{ - .name = name, - .value = value, - }, - .mutable = mutable, - }, - }; - - return vardecl; - } - fn mkCall(self: *@This(), callee: *Expr, paren: Token, args: ast.ExprList) !*Expr { var expr = try self.allocator.create(Expr); expr.* = Expr{ @@ -716,6 +701,7 @@ pub const Parser = struct { fn parseStmt(self: *@This()) anyerror!*Stmt { return switch (self.peek().typ) { + .Var => try self.parseVarDecl(), .If => try self.parseIfStmt(), .Loop => try self.parseLoop(), .For => try self.parseForStmt(), @@ -725,6 +711,14 @@ pub const Parser = struct { }; } + fn parseVarDecl(self: *@This()) !*Stmt { + _ = try self.consumeSingle(.Var); + var name = try self.consumeSingle(.Identifier); + _ = try self.consumeSingle(.Equal); + var value = try self.parseExpr(); + return try Stmt.mkVarDecl(self.allocator, name, value); + } + /// Parse a list of statements. fn parseBlock(self: *@This()) !*Node { var stmts = try self.parseBlockInternal(ast.StmtList); @@ -840,8 +834,8 @@ pub const Parser = struct { fn parseAssignment(self: *@This()) anyerror!*Expr { // there can be two assignments coming out of this function: - // - a mutable/immutable variable declaration with := - // - an assignment to a variable with =, +=, -= + // - an assignment to a variable with = + // - an update to a variable with +=, -= // one is a statement, other is an expression. since the normal result // of this is an Expr, we wrap variable assignments in an Expr as well. @@ -855,7 +849,7 @@ pub const Parser = struct { var expr = try self.parseOr(); if (self.compareAnyOf(&[_]TokenType{ - .ColonEqual, .Equal, .PlusEqual, .MinusEqual, .StarEqual, + .Equal, .PlusEqual, .MinusEqual, .StarEqual, .SlashEqual, })) { return try self.finishAssignment(expr, mutable); @@ -871,8 +865,7 @@ pub const Parser = struct { var value = try self.parseAssignment(); // expr can be a (Variable|Set) - // op_tok can be one of three categories: - // - ColonEqual, parses to VarDecl (only when expr = Variable) + // op_tok can be one of two categories: // - Equal, parses to (Assign|Set) // - Inplace (+=, -=, *=, /=), parses to (Assign|Set) @@ -893,7 +886,6 @@ pub const Parser = struct { switch (expr.*) { .Variable => { switch (op_tok.typ) { - .ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable), .Equal => return try self.mkAssign(expr.Variable, value), .PlusEqual, .MinusEqual, .StarEqual, .SlashEqual => { @@ -909,6 +901,7 @@ pub const Parser = struct { .Get => |get| { switch (op_tok.typ) { + // TODO remove .ColonEqual from language .ColonEqual => { return self.doError("can not initialize struct field"); }, diff --git a/src/scanners.zig b/src/scanners.zig index 5271235..24f2116 100644 --- a/src/scanners.zig +++ b/src/scanners.zig @@ -54,6 +54,7 @@ const keywords = [_][]const u8{ "pub", "and", "or", + "var", }; const keyword_ttypes = [_]TokenType{ @@ -86,9 +87,12 @@ const keyword_ttypes = [_]TokenType{ .Pub, .And, .Or, + .Var, }; fn getKeyword(keyword: []const u8) ?TokenType { + std.debug.assert(keywords.len == keyword_ttypes.len); + for (keywords) |kw, idx| { if (std.mem.eql(u8, keyword, kw)) { return keyword_ttypes[idx]; diff --git a/src/tokens.zig b/src/tokens.zig index 1df9b37..75aa8f9 100644 --- a/src/tokens.zig +++ b/src/tokens.zig @@ -77,6 +77,7 @@ pub const TokenType = enum { Println, Pub, + Var, EOF, };