diff --git a/examples/hello.ry b/examples/hello.ry index 43b93a2..debd7e6 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -1,11 +1,7 @@ // import std; -fn add(a: i32, b: i32) i32 { - return 69 + 69; -} - -fn and_fn() bool { - return true and false; +fn add() i32 { + return 1 + 1; } // type is void by default diff --git a/src/ast.zig b/src/ast.zig index 6663958..95d59c0 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -44,38 +44,20 @@ pub const SingleConst = struct { expr: *Expr, }; -pub const BinaryOperator = enum { - - // numeric - Add, - Sub, - Mul, - Div, - Mod, - - // numeric -> bool - Greater, - GreaterEqual, - Less, - LessEqual, - - // booleans - Equal, - And, - Or, -}; - pub const BinaryExpr = struct { left: *Expr, - op: BinaryOperator, + op: Token, right: *Expr, }; -pub const UnaryOperator = enum { - Not, +pub const UnaryExpr = struct { + op: Token, + right: *Expr, }; -pub const UnaryExpr = struct { +// looks like a BinaryExpr, but is not a BinaryExpr +pub const LogicalExpr = struct { + left: *Expr, op: Token, right: *Expr, }; @@ -101,6 +83,7 @@ pub const ExprType = enum { Binary, Unary, + Logical, Literal, Variable, Call, @@ -151,6 +134,7 @@ pub const Expr = union(ExprType) { Binary: BinaryExpr, Unary: UnaryExpr, + Logical: LogicalExpr, Literal: LiteralExpr, Struct: StructExpr, diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 4f9ced9..e818c00 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -155,37 +155,8 @@ fn printTwoExprs(expr_a: *const Expr, expr_b: *const Expr) void { printExpr(expr_b); } -const operator_tokens = [_][]const u8{ - "+", "-", "*", "/", "%", ">", ">=", "<", "<=", "==", "&&", "||", -}; - -const operator_values = [_]BinaryOperator{ - .Add, - .Sub, - .Mul, - .Div, - .Mod, - - .Greater, - .GreaterEqual, - .Less, - .LessEqual, - - .Equal, - .And, - .Or, -}; - -fn binOpToStr(op: BinaryOperator) ?[]const u8 { - inline for (operator_values) |val, idx| { - if (val == op) return operator_tokens[idx]; - } - - return null; -} - fn printBinOp(inner: var) void { - std.debug.warn("({}", binOpToStr(inner.op)); + std.debug.warn("({}", inner.op.lexeme); printTwoExprs(inner.left, inner.right); std.debug.warn(")"); } @@ -199,6 +170,7 @@ fn printSingleOp(tok: []const u8, applied: *const Expr) void { pub fn printExpr(expr: *const Expr) void { switch (expr.*) { .Binary => |binary| printBinOp(binary), + .Logical => |logical| printBinOp(logical), .Unary => |unary| printSingleOp(unary.op.lexeme, unary.right), .Grouping => |expr_ptr| printSingleOp("group", expr_ptr), diff --git a/src/codegen.zig b/src/codegen.zig index 384fd9a..583a699 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -10,22 +10,8 @@ fn sliceify(non_slice: ?[*]const u8) []const u8 { pub const CompileError = error{ LLVMError, EmitError, - TypeError, }; -/// Does not account for custom types e.g structs, better type resolution -/// should be found -fn basicTypeToLLVM(ret_type: []const u8) !llvm.LLVMTypeRef { - if (std.mem.eql(u8, ret_type, "i32")) { - return llvm.LLVMInt32Type(); - } else if (std.mem.eql(u8, ret_type, "bool")) { - return llvm.LLVMInt1Type(); - } else { - std.debug.warn("Invalid return type: {}\n", ret_type); - return CompileError.TypeError; - } -} - pub const Codegen = struct { allocator: *std.mem.Allocator, @@ -55,32 +41,20 @@ pub const Codegen = struct { var val_cstr = try std.cstr.addNullByte(self.allocator, val); break :blk2 llvm.LLVMConstRealOfString(llvm.LLVMDoubleType(), val_cstr.ptr); }, - .Bool => |val| blk2: { - if (val) { - break :blk2 llvm.LLVMConstInt(llvm.LLVMInt1Type(), 1, 1); - } else { - break :blk2 llvm.LLVMConstInt(llvm.LLVMInt1Type(), 0, 1); - } - }, else => unreachable, }; }, - .Binary => |binary| { var left = try self.emitExpr(builder, binary.left); var right = try self.emitExpr(builder, binary.right); - return switch (binary.op) { - .Add => llvm.LLVMBuildAdd(builder, left, right, c"addtmp"), - .Sub => llvm.LLVMBuildSub(builder, left, right, c"subtmp"), - .Mul => llvm.LLVMBuildMul(builder, left, right, c"multmp"), - - //.Div => llvm.LLVMBuildDiv(builder, left, right, c"divtmp"), - .And => llvm.LLVMBuildAnd(builder, left, right, c"andtmp"), - .Or => llvm.LLVMBuildOr(builder, left, right, c"ortmp"), + return switch (binary.op.lexeme[0]) { + // TODO other operators + '+' => llvm.LLVMBuildAdd(builder, left, right, c"addtmp"), + // TODO codegen errors else => { - std.debug.warn("Unexpected binary operator: '{}'\n", binary.op); + std.debug.warn("Unexpected binary operator: '{}'\n", binary.op.lexeme); return CompileError.EmitError; }, }; @@ -120,24 +94,23 @@ pub const Codegen = struct { const name_cstr = try std.cstr.addNullByte(self.allocator, name); errdefer self.allocator.free(name_cstr); - const fn_ret_type = decl.return_type.lexeme; + //const ret_type = decl.return_type.lexeme; var param_types = llvm.LLVMTypeList.init(self.allocator); errdefer param_types.deinit(); for (decl.params.toSlice()) |param| { - // TODO better type resolution - try param_types.append(try basicTypeToLLVM(param.typ.lexeme)); + try param_types.append(llvm.LLVMInt32Type()); } - var llvm_ret_type = llvm.LLVMFunctionType( - try basicTypeToLLVM(fn_ret_type), + var ret_type = llvm.LLVMFunctionType( + llvm.LLVMInt32Type(), param_types.toSlice().ptr, @intCast(c_uint, param_types.len), 0, ); - var func = llvm.LLVMAddFunction(mod, name_cstr.ptr, llvm_ret_type); + var func = llvm.LLVMAddFunction(mod, name_cstr.ptr, ret_type); var entry = llvm.LLVMAppendBasicBlock(func, c"entry"); var builder = llvm.LLVMCreateBuilder(); diff --git a/src/parsers.zig b/src/parsers.zig index 0a192e1..d31c611 100644 --- a/src/parsers.zig +++ b/src/parsers.zig @@ -11,10 +11,7 @@ const Scanner = scanners.Scanner; const Token = tokens.Token; const TokenType = tokens.TokenType; -pub const ParseError = error{ - CompileError, - UnknownOperator, -}; +pub const ParseError = error{CompileError}; const Node = ast.Node; const Expr = ast.Expr; @@ -28,39 +25,6 @@ const FieldState = struct { mutable_outside: bool = false, }; -const operator_tokens = [_][]const u8{ - "+", "-", "*", "/", "%", ">", ">=", "<", "<=", "==", -}; - -const operator_values = [_]ast.BinaryOperator{ - .Add, - .Sub, - .Mul, - .Div, - .Mod, - - .Greater, - .GreaterEqual, - .Less, - .LessEqual, - - .Equal, -}; - -fn toBinaryOperator(op: Token) !ast.BinaryOperator { - const lex = op.lexeme; - - inline for (operator_tokens) |op_str, idx| { - if (std.mem.eql(u8, lex, op_str)) return operator_values[idx]; - } - - // special cases: && + and => .And and || + or => .Or - if (std.mem.eql(u8, lex, "&&") or std.mem.eql(u8, lex, "and")) return .And; - if (std.mem.eql(u8, lex, "||") or std.mem.eql(u8, lex, "or")) return .Or; - - return ParseError.UnknownOperator; -} - pub const Parser = struct { allocator: *Allocator, scanner: *Scanner, @@ -254,7 +218,7 @@ pub const Parser = struct { return expr; } - fn mkBinary(self: *Parser, left: *Expr, op: ast.BinaryOperator, right: *Expr) !*Expr { + fn mkBinary(self: *Parser, left: *Expr, op: Token, right: *Expr) !*Expr { var expr = try self.allocator.create(Expr); expr.* = Expr{ .Binary = ast.BinaryExpr{ @@ -267,6 +231,19 @@ pub const Parser = struct { return expr; } + fn mkLogical(self: *Parser, left: *Expr, op: Token, right: *Expr) !*Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Logical = ast.LogicalExpr{ + .left = left, + .op = op, + .right = right, + }, + }; + + return expr; + } + fn mkAssign(self: *Parser, name: Token, value: *Expr) !*Expr { var expr = try self.allocator.create(Expr); expr.* = Expr{ @@ -845,41 +822,55 @@ pub const Parser = struct { } fn finishAssignment(self: *@This(), expr: *Expr, mutable: bool) !*Expr { - var op_tok = self.peek(); + var op = self.peek(); _ = try self.nextToken(); - 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) - // - Equal, parses to (Assign|Set) - // - Inplace (+=, -=, *=, /=), parses to (Assign|Set) + // TODO convert binary's op field from Token to + // something else, maybe enum'd - // however, when dealing with inplace operators, we want those to parse - // to an assign/set with a binary expression with the undelying operator - // instead of the infix operator. - // e.g 'x += 1' parses down to 'x = x + 1' + const new_op_ttype: TokenType = switch (op.typ) { + .ColonEqual => TokenType.ColonEqual, + .Equal => .Equal, - // TODO do we add %=? - const binop: ?ast.BinaryOperator = switch (op_tok.typ) { - .PlusEqual => ast.BinaryOperator.Add, - .MinusEqual => .Sub, - .StarEqual => .Mul, - .SlashEqual => .Div, - else => null, + .PlusEqual => .Plus, + .MinusEqual => .Minus, + .StarEqual => .Star, + .SlashEqual => .Slash, + + else => unreachable, + }; + + // we create new_lexeme so that + // the AST printer properly prints + // x += 1 + // as + // (set x (+ x 1)) + // and not + // (set x (+= x 1)) + const new_lexeme: []const u8 = switch (op.typ) { + .ColonEqual => ":=", + .Equal => "=", + + .PlusEqual => "+", + .MinusEqual => "-", + .StarEqual => "*", + .SlashEqual => "/", + + else => unreachable, }; switch (expr.*) { .Variable => { - switch (op_tok.typ) { + switch (op.typ) { .ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable), .Equal => return try self.mkAssign(expr.Variable, value), .PlusEqual, .MinusEqual, .StarEqual, .SlashEqual => { + var new_op = try self.mkToken(new_op_ttype, new_lexeme, op.line); return try self.mkAssign( expr.Variable, - try self.mkBinary(expr, binop.?, value), + try self.mkBinary(expr, new_op, value), ); }, @@ -888,7 +879,7 @@ pub const Parser = struct { }, .Get => |get| { - switch (op_tok.typ) { + switch (op.typ) { .ColonEqual => { return self.doError("can not initialize struct field"); }, @@ -896,10 +887,11 @@ pub const Parser = struct { .Equal => return try self.mkSet(get.struc, get.name, value), .PlusEqual, .MinusEqual, .StarEqual, .SlashEqual => { + var new_op = try self.mkToken(new_op_ttype, new_lexeme, op.line); return try self.mkSet( get.struc, get.name, - try self.mkBinary(expr, binop.?, value), + try self.mkBinary(expr, new_op, value), ); }, @@ -921,7 +913,7 @@ pub const Parser = struct { _ = try self.nextToken(); var right = try self.parseAnd(); - expr = try self.mkBinary(expr, try toBinaryOperator(op), right); + expr = try self.mkLogical(expr, op, right); } return expr; @@ -935,7 +927,7 @@ pub const Parser = struct { _ = try self.nextToken(); var right = try self.parseEquality(); - expr = try self.mkBinary(expr, try toBinaryOperator(op), right); + expr = try self.mkLogical(expr, op, right); } return expr; @@ -949,7 +941,7 @@ pub const Parser = struct { _ = try self.nextToken(); var right = try self.parseComparison(); - expr = try self.mkBinary(expr, .Equal, right); + expr = try self.mkBinary(expr, op, right); } return expr; @@ -968,7 +960,7 @@ pub const Parser = struct { _ = try self.nextToken(); var right = try self.parseAddition(); - expr = try self.mkBinary(expr, try toBinaryOperator(op), right); + expr = try self.mkBinary(expr, op, right); } return expr; @@ -984,7 +976,7 @@ pub const Parser = struct { _ = try self.nextToken(); var right = try self.parseMultiplication(); - expr = try self.mkBinary(expr, try toBinaryOperator(op), right); + expr = try self.mkBinary(expr, op, right); } return expr; @@ -1000,7 +992,7 @@ pub const Parser = struct { _ = try self.nextToken(); var right = try self.parseUnary(); - expr = try self.mkBinary(expr, try toBinaryOperator(op), right); + expr = try self.mkBinary(expr, op, right); } return expr; diff --git a/src/scanners.zig b/src/scanners.zig index 5271235..ced1da8 100644 --- a/src/scanners.zig +++ b/src/scanners.zig @@ -52,8 +52,6 @@ const keywords = [_][]const u8{ "println", "loop", "pub", - "and", - "or", }; const keyword_ttypes = [_]TokenType{ @@ -84,8 +82,6 @@ const keyword_ttypes = [_]TokenType{ .Println, .Loop, .Pub, - .And, - .Or, }; fn getKeyword(keyword: []const u8) ?TokenType {