Compare commits

..

No commits in common. "1ac63cdbef725f202483d5b2f684a2fe3a9404d2" and "013aafa8a436d4b73ad0c3ac61dccccbbda930b9" have entirely different histories.

6 changed files with 81 additions and 168 deletions

View file

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

View file

@ -44,38 +44,20 @@ pub const SingleConst = struct {
expr: *Expr, 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 { pub const BinaryExpr = struct {
left: *Expr, left: *Expr,
op: BinaryOperator, op: Token,
right: *Expr, right: *Expr,
}; };
pub const UnaryOperator = enum { pub const UnaryExpr = struct {
Not, 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, op: Token,
right: *Expr, right: *Expr,
}; };
@ -101,6 +83,7 @@ pub const ExprType = enum {
Binary, Binary,
Unary, Unary,
Logical,
Literal, Literal,
Variable, Variable,
Call, Call,
@ -151,6 +134,7 @@ 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

@ -155,37 +155,8 @@ fn printTwoExprs(expr_a: *const Expr, expr_b: *const Expr) void {
printExpr(expr_b); 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 { fn printBinOp(inner: var) void {
std.debug.warn("({}", binOpToStr(inner.op)); std.debug.warn("({}", inner.op.lexeme);
printTwoExprs(inner.left, inner.right); printTwoExprs(inner.left, inner.right);
std.debug.warn(")"); std.debug.warn(")");
} }
@ -199,6 +170,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), .Binary => |binary| printBinOp(binary),
.Logical => |logical| printBinOp(logical),
.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,22 +10,8 @@ fn sliceify(non_slice: ?[*]const u8) []const u8 {
pub const CompileError = error{ pub const CompileError = error{
LLVMError, LLVMError,
EmitError, 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 { pub const Codegen = struct {
allocator: *std.mem.Allocator, allocator: *std.mem.Allocator,
@ -55,32 +41,20 @@ 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);
return switch (binary.op) { return switch (binary.op.lexeme[0]) {
.Add => llvm.LLVMBuildAdd(builder, left, right, c"addtmp"), // TODO other operators
.Sub => llvm.LLVMBuildSub(builder, left, right, c"subtmp"), '+' => llvm.LLVMBuildAdd(builder, left, right, c"addtmp"),
.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"),
// TODO codegen errors
else => { else => {
std.debug.warn("Unexpected binary operator: '{}'\n", binary.op); std.debug.warn("Unexpected binary operator: '{}'\n", binary.op.lexeme);
return CompileError.EmitError; return CompileError.EmitError;
}, },
}; };
@ -120,24 +94,23 @@ 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 fn_ret_type = decl.return_type.lexeme; //const 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 better type resolution try param_types.append(llvm.LLVMInt32Type());
try param_types.append(try basicTypeToLLVM(param.typ.lexeme));
} }
var llvm_ret_type = llvm.LLVMFunctionType( var ret_type = llvm.LLVMFunctionType(
try basicTypeToLLVM(fn_ret_type), llvm.LLVMInt32Type(),
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, llvm_ret_type); var func = llvm.LLVMAddFunction(mod, name_cstr.ptr, 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

@ -11,10 +11,7 @@ const Scanner = scanners.Scanner;
const Token = tokens.Token; const Token = tokens.Token;
const TokenType = tokens.TokenType; const TokenType = tokens.TokenType;
pub const ParseError = error{ pub const ParseError = error{CompileError};
CompileError,
UnknownOperator,
};
const Node = ast.Node; const Node = ast.Node;
const Expr = ast.Expr; const Expr = ast.Expr;
@ -28,39 +25,6 @@ const FieldState = struct {
mutable_outside: bool = false, 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 { pub const Parser = struct {
allocator: *Allocator, allocator: *Allocator,
scanner: *Scanner, scanner: *Scanner,
@ -254,7 +218,7 @@ pub const Parser = struct {
return expr; 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); var expr = try self.allocator.create(Expr);
expr.* = Expr{ expr.* = Expr{
.Binary = ast.BinaryExpr{ .Binary = ast.BinaryExpr{
@ -267,6 +231,19 @@ 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{
@ -845,41 +822,55 @@ pub const Parser = struct {
} }
fn finishAssignment(self: *@This(), expr: *Expr, mutable: bool) !*Expr { fn finishAssignment(self: *@This(), expr: *Expr, mutable: bool) !*Expr {
var op_tok = self.peek(); var op = self.peek();
_ = try self.nextToken(); _ = try self.nextToken();
var value = try self.parseAssignment(); var value = try self.parseAssignment();
// expr can be a (Variable|Set) // TODO convert binary's op field from Token to
// op_tok can be one of three categories: // something else, maybe enum'd
// - ColonEqual, parses to VarDecl (only when expr = Variable)
// - Equal, parses to (Assign|Set)
// - Inplace (+=, -=, *=, /=), parses to (Assign|Set)
// however, when dealing with inplace operators, we want those to parse const new_op_ttype: TokenType = switch (op.typ) {
// to an assign/set with a binary expression with the undelying operator .ColonEqual => TokenType.ColonEqual,
// instead of the infix operator. .Equal => .Equal,
// e.g 'x += 1' parses down to 'x = x + 1'
// TODO do we add %=? .PlusEqual => .Plus,
const binop: ?ast.BinaryOperator = switch (op_tok.typ) { .MinusEqual => .Minus,
.PlusEqual => ast.BinaryOperator.Add, .StarEqual => .Star,
.MinusEqual => .Sub, .SlashEqual => .Slash,
.StarEqual => .Mul,
.SlashEqual => .Div, else => unreachable,
else => null, };
// 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.*) { switch (expr.*) {
.Variable => { .Variable => {
switch (op_tok.typ) { switch (op.typ) {
.ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable), .ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable),
.Equal => return try self.mkAssign(expr.Variable, value), .Equal => return try self.mkAssign(expr.Variable, value),
.PlusEqual, .MinusEqual, .StarEqual, .SlashEqual => { .PlusEqual, .MinusEqual, .StarEqual, .SlashEqual => {
var new_op = try self.mkToken(new_op_ttype, new_lexeme, op.line);
return try self.mkAssign( return try self.mkAssign(
expr.Variable, 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| { .Get => |get| {
switch (op_tok.typ) { switch (op.typ) {
.ColonEqual => { .ColonEqual => {
return self.doError("can not initialize struct field"); 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), .Equal => return try self.mkSet(get.struc, get.name, value),
.PlusEqual, .MinusEqual, .StarEqual, .SlashEqual => { .PlusEqual, .MinusEqual, .StarEqual, .SlashEqual => {
var new_op = try self.mkToken(new_op_ttype, new_lexeme, op.line);
return try self.mkSet( return try self.mkSet(
get.struc, get.struc,
get.name, 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(); _ = try self.nextToken();
var right = try self.parseAnd(); var right = try self.parseAnd();
expr = try self.mkBinary(expr, try toBinaryOperator(op), right); expr = try self.mkLogical(expr, op, right);
} }
return expr; return expr;
@ -935,7 +927,7 @@ pub const Parser = struct {
_ = try self.nextToken(); _ = try self.nextToken();
var right = try self.parseEquality(); var right = try self.parseEquality();
expr = try self.mkBinary(expr, try toBinaryOperator(op), right); expr = try self.mkLogical(expr, op, right);
} }
return expr; return expr;
@ -949,7 +941,7 @@ pub const Parser = struct {
_ = try self.nextToken(); _ = try self.nextToken();
var right = try self.parseComparison(); var right = try self.parseComparison();
expr = try self.mkBinary(expr, .Equal, right); expr = try self.mkBinary(expr, op, right);
} }
return expr; return expr;
@ -968,7 +960,7 @@ pub const Parser = struct {
_ = try self.nextToken(); _ = try self.nextToken();
var right = try self.parseAddition(); var right = try self.parseAddition();
expr = try self.mkBinary(expr, try toBinaryOperator(op), right); expr = try self.mkBinary(expr, op, right);
} }
return expr; return expr;
@ -984,7 +976,7 @@ pub const Parser = struct {
_ = try self.nextToken(); _ = try self.nextToken();
var right = try self.parseMultiplication(); var right = try self.parseMultiplication();
expr = try self.mkBinary(expr, try toBinaryOperator(op), right); expr = try self.mkBinary(expr, op, right);
} }
return expr; return expr;
@ -1000,7 +992,7 @@ pub const Parser = struct {
_ = try self.nextToken(); _ = try self.nextToken();
var right = try self.parseUnary(); var right = try self.parseUnary();
expr = try self.mkBinary(expr, try toBinaryOperator(op), right); expr = try self.mkBinary(expr, op, right);
} }
return expr; return expr;

View file

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