fix boolean operators

- remove Logical expressions
 - add basic token return type to LLVMTypeRef converter
 - add codegen for Bool literals
 - fix "and" and "or" being identified as identifiers
This commit is contained in:
Luna 2019-09-24 13:23:23 -03:00
parent f08d613198
commit e25621350a
6 changed files with 41 additions and 37 deletions

View File

@ -1,7 +1,11 @@
// import std; // import std;
fn add() i32 { fn add() i32 {
return 1 + 1; return 69 + 69;
}
fn and_fn() bool {
return true and false;
} }
// type is void by default // type is void by default

View File

@ -80,13 +80,6 @@ pub const UnaryExpr = struct {
right: *Expr, right: *Expr,
}; };
// looks like a BinaryExpr, but is not a BinaryExpr
pub const LogicalExpr = struct {
left: *Expr,
op: Token,
right: *Expr,
};
pub const LiteralExpr = union(enum) { pub const LiteralExpr = union(enum) {
Bool: bool, Bool: bool,
Integer: []const u8, Integer: []const u8,
@ -108,7 +101,6 @@ pub const ExprType = enum {
Binary, Binary,
Unary, Unary,
Logical,
Literal, Literal,
Variable, Variable,
Call, Call,
@ -159,7 +151,6 @@ pub const Expr = union(ExprType) {
Binary: BinaryExpr, Binary: BinaryExpr,
Unary: UnaryExpr, Unary: UnaryExpr,
Logical: LogicalExpr,
Literal: LiteralExpr, Literal: LiteralExpr,
Struct: StructExpr, Struct: StructExpr,

View File

@ -184,12 +184,8 @@ fn binOpToStr(op: BinaryOperator) ?[]const u8 {
return null; return null;
} }
fn printBinOp(inner: var, comptime is_binop: bool) void { fn printBinOp(inner: var) void {
if (is_binop) { std.debug.warn("({}", binOpToStr(inner.op));
std.debug.warn("({}", binOpToStr(inner.op));
} else {
std.debug.warn("({}", inner.op.lexeme);
}
printTwoExprs(inner.left, inner.right); printTwoExprs(inner.left, inner.right);
std.debug.warn(")"); std.debug.warn(")");
} }
@ -202,8 +198,7 @@ fn printSingleOp(tok: []const u8, applied: *const Expr) void {
pub fn printExpr(expr: *const Expr) void { pub fn printExpr(expr: *const Expr) void {
switch (expr.*) { switch (expr.*) {
.Binary => |binary| printBinOp(binary, true), .Binary => |binary| printBinOp(binary),
.Logical => |logical| printBinOp(logical, false),
.Unary => |unary| printSingleOp(unary.op.lexeme, unary.right), .Unary => |unary| printSingleOp(unary.op.lexeme, unary.right),
.Grouping => |expr_ptr| printSingleOp("group", expr_ptr), .Grouping => |expr_ptr| printSingleOp("group", expr_ptr),

View File

@ -10,8 +10,20 @@ fn sliceify(non_slice: ?[*]const u8) []const u8 {
pub const CompileError = error{ pub const CompileError = error{
LLVMError, LLVMError,
EmitError, EmitError,
TypeError,
}; };
fn retTypeToLLVM(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 { pub const Codegen = struct {
allocator: *std.mem.Allocator, allocator: *std.mem.Allocator,
@ -41,9 +53,17 @@ pub const Codegen = struct {
var val_cstr = try std.cstr.addNullByte(self.allocator, val); var val_cstr = try std.cstr.addNullByte(self.allocator, val);
break :blk2 llvm.LLVMConstRealOfString(llvm.LLVMDoubleType(), val_cstr.ptr); 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, else => unreachable,
}; };
}, },
.Binary => |binary| { .Binary => |binary| {
var left = try self.emitExpr(builder, binary.left); var left = try self.emitExpr(builder, binary.left);
var right = try self.emitExpr(builder, binary.right); var right = try self.emitExpr(builder, binary.right);
@ -54,6 +74,8 @@ pub const Codegen = struct {
.Mul => llvm.LLVMBuildMul(builder, left, right, c"multmp"), .Mul => llvm.LLVMBuildMul(builder, left, right, c"multmp"),
//.Div => llvm.LLVMBuildDiv(builder, left, right, c"divtmp"), //.Div => llvm.LLVMBuildDiv(builder, left, right, c"divtmp"),
.And => llvm.LLVMBuildAnd(builder, left, right, c"andtmp"),
.Or => llvm.LLVMBuildOr(builder, left, right, c"ortmp"),
else => { else => {
std.debug.warn("Unexpected binary operator: '{}'\n", binary.op); std.debug.warn("Unexpected binary operator: '{}'\n", binary.op);
@ -96,23 +118,24 @@ pub const Codegen = struct {
const name_cstr = try std.cstr.addNullByte(self.allocator, name); const name_cstr = try std.cstr.addNullByte(self.allocator, name);
errdefer self.allocator.free(name_cstr); errdefer self.allocator.free(name_cstr);
//const ret_type = decl.return_type.lexeme; const fn_ret_type = decl.return_type.lexeme;
var param_types = llvm.LLVMTypeList.init(self.allocator); var param_types = llvm.LLVMTypeList.init(self.allocator);
errdefer param_types.deinit(); errdefer param_types.deinit();
for (decl.params.toSlice()) |param| { for (decl.params.toSlice()) |param| {
// TODO solve type with cute enums etc
try param_types.append(llvm.LLVMInt32Type()); try param_types.append(llvm.LLVMInt32Type());
} }
var ret_type = llvm.LLVMFunctionType( var llvm_ret_type = llvm.LLVMFunctionType(
llvm.LLVMInt32Type(), try retTypeToLLVM(fn_ret_type),
param_types.toSlice().ptr, param_types.toSlice().ptr,
@intCast(c_uint, param_types.len), @intCast(c_uint, param_types.len),
0, 0,
); );
var func = llvm.LLVMAddFunction(mod, name_cstr.ptr, ret_type); var func = llvm.LLVMAddFunction(mod, name_cstr.ptr, llvm_ret_type);
var entry = llvm.LLVMAppendBasicBlock(func, c"entry"); var entry = llvm.LLVMAppendBasicBlock(func, c"entry");
var builder = llvm.LLVMCreateBuilder(); var builder = llvm.LLVMCreateBuilder();

View File

@ -267,19 +267,6 @@ pub const Parser = struct {
return expr; 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 { fn mkAssign(self: *Parser, name: Token, value: *Expr) !*Expr {
var expr = try self.allocator.create(Expr); var expr = try self.allocator.create(Expr);
expr.* = Expr{ expr.* = Expr{
@ -934,7 +921,7 @@ pub const Parser = struct {
_ = try self.nextToken(); _ = try self.nextToken();
var right = try self.parseAnd(); var right = try self.parseAnd();
expr = try self.mkLogical(expr, op, right); expr = try self.mkBinary(expr, try toBinaryOperator(op), right);
} }
return expr; return expr;
@ -948,7 +935,7 @@ pub const Parser = struct {
_ = try self.nextToken(); _ = try self.nextToken();
var right = try self.parseEquality(); var right = try self.parseEquality();
expr = try self.mkLogical(expr, op, right); expr = try self.mkBinary(expr, try toBinaryOperator(op), right);
} }
return expr; return expr;

View File

@ -52,6 +52,8 @@ const keywords = [_][]const u8{
"println", "println",
"loop", "loop",
"pub", "pub",
"and",
"or",
}; };
const keyword_ttypes = [_]TokenType{ const keyword_ttypes = [_]TokenType{
@ -82,6 +84,8 @@ const keyword_ttypes = [_]TokenType{
.Println, .Println,
.Loop, .Loop,
.Pub, .Pub,
.And,
.Or,
}; };
fn getKeyword(keyword: []const u8) ?TokenType { fn getKeyword(keyword: []const u8) ?TokenType {