switch BinaryExpr.op to BinaryOperator instead of token
less strings, more fun!
This commit is contained in:
parent
013aafa8a4
commit
f08d613198
4 changed files with 134 additions and 53 deletions
27
src/ast.zig
27
src/ast.zig
|
@ -44,12 +44,37 @@ 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: Token,
|
||||
op: BinaryOperator,
|
||||
right: *Expr,
|
||||
};
|
||||
|
||||
pub const UnaryOperator = enum {
|
||||
Not,
|
||||
};
|
||||
|
||||
pub const UnaryExpr = struct {
|
||||
op: Token,
|
||||
right: *Expr,
|
||||
|
|
|
@ -155,8 +155,41 @@ fn printTwoExprs(expr_a: *const Expr, expr_b: *const Expr) void {
|
|||
printExpr(expr_b);
|
||||
}
|
||||
|
||||
fn printBinOp(inner: var) void {
|
||||
std.debug.warn("({}", inner.op.lexeme);
|
||||
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, comptime is_binop: bool) void {
|
||||
if (is_binop) {
|
||||
std.debug.warn("({}", binOpToStr(inner.op));
|
||||
} else {
|
||||
std.debug.warn("({}", inner.op.lexeme);
|
||||
}
|
||||
printTwoExprs(inner.left, inner.right);
|
||||
std.debug.warn(")");
|
||||
}
|
||||
|
@ -169,8 +202,8 @@ 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),
|
||||
.Binary => |binary| printBinOp(binary, true),
|
||||
.Logical => |logical| printBinOp(logical, false),
|
||||
|
||||
.Unary => |unary| printSingleOp(unary.op.lexeme, unary.right),
|
||||
.Grouping => |expr_ptr| printSingleOp("group", expr_ptr),
|
||||
|
|
|
@ -48,13 +48,15 @@ pub const Codegen = struct {
|
|||
var left = try self.emitExpr(builder, binary.left);
|
||||
var right = try self.emitExpr(builder, binary.right);
|
||||
|
||||
return switch (binary.op.lexeme[0]) {
|
||||
// TODO other operators
|
||||
'+' => llvm.LLVMBuildAdd(builder, left, right, c"addtmp"),
|
||||
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"),
|
||||
|
||||
// TODO codegen errors
|
||||
else => {
|
||||
std.debug.warn("Unexpected binary operator: '{}'\n", binary.op.lexeme);
|
||||
std.debug.warn("Unexpected binary operator: '{}'\n", binary.op);
|
||||
return CompileError.EmitError;
|
||||
},
|
||||
};
|
||||
|
|
107
src/parsers.zig
107
src/parsers.zig
|
@ -11,7 +11,10 @@ const Scanner = scanners.Scanner;
|
|||
const Token = tokens.Token;
|
||||
const TokenType = tokens.TokenType;
|
||||
|
||||
pub const ParseError = error{CompileError};
|
||||
pub const ParseError = error{
|
||||
CompileError,
|
||||
UnknownOperator,
|
||||
};
|
||||
|
||||
const Node = ast.Node;
|
||||
const Expr = ast.Expr;
|
||||
|
@ -25,6 +28,39 @@ 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,
|
||||
|
@ -218,7 +254,7 @@ pub const Parser = struct {
|
|||
return expr;
|
||||
}
|
||||
|
||||
fn mkBinary(self: *Parser, left: *Expr, op: Token, right: *Expr) !*Expr {
|
||||
fn mkBinary(self: *Parser, left: *Expr, op: ast.BinaryOperator, right: *Expr) !*Expr {
|
||||
var expr = try self.allocator.create(Expr);
|
||||
expr.* = Expr{
|
||||
.Binary = ast.BinaryExpr{
|
||||
|
@ -822,55 +858,41 @@ pub const Parser = struct {
|
|||
}
|
||||
|
||||
fn finishAssignment(self: *@This(), expr: *Expr, mutable: bool) !*Expr {
|
||||
var op = self.peek();
|
||||
var op_tok = self.peek();
|
||||
_ = try self.nextToken();
|
||||
|
||||
var value = try self.parseAssignment();
|
||||
|
||||
// TODO convert binary's op field from Token to
|
||||
// something else, maybe enum'd
|
||||
// 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)
|
||||
|
||||
const new_op_ttype: TokenType = switch (op.typ) {
|
||||
.ColonEqual => TokenType.ColonEqual,
|
||||
.Equal => .Equal,
|
||||
// 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'
|
||||
|
||||
.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,
|
||||
// TODO do we add %=?
|
||||
const binop: ?ast.BinaryOperator = switch (op_tok.typ) {
|
||||
.PlusEqual => ast.BinaryOperator.Add,
|
||||
.MinusEqual => .Sub,
|
||||
.StarEqual => .Mul,
|
||||
.SlashEqual => .Div,
|
||||
else => null,
|
||||
};
|
||||
|
||||
switch (expr.*) {
|
||||
.Variable => {
|
||||
switch (op.typ) {
|
||||
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 => {
|
||||
var new_op = try self.mkToken(new_op_ttype, new_lexeme, op.line);
|
||||
return try self.mkAssign(
|
||||
expr.Variable,
|
||||
try self.mkBinary(expr, new_op, value),
|
||||
try self.mkBinary(expr, binop.?, value),
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -879,7 +901,7 @@ pub const Parser = struct {
|
|||
},
|
||||
|
||||
.Get => |get| {
|
||||
switch (op.typ) {
|
||||
switch (op_tok.typ) {
|
||||
.ColonEqual => {
|
||||
return self.doError("can not initialize struct field");
|
||||
},
|
||||
|
@ -887,11 +909,10 @@ 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, new_op, value),
|
||||
try self.mkBinary(expr, binop.?, value),
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -941,7 +962,7 @@ pub const Parser = struct {
|
|||
_ = try self.nextToken();
|
||||
|
||||
var right = try self.parseComparison();
|
||||
expr = try self.mkBinary(expr, op, right);
|
||||
expr = try self.mkBinary(expr, .Equal, right);
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
@ -960,7 +981,7 @@ pub const Parser = struct {
|
|||
_ = try self.nextToken();
|
||||
|
||||
var right = try self.parseAddition();
|
||||
expr = try self.mkBinary(expr, op, right);
|
||||
expr = try self.mkBinary(expr, try toBinaryOperator(op), right);
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
@ -976,7 +997,7 @@ pub const Parser = struct {
|
|||
_ = try self.nextToken();
|
||||
|
||||
var right = try self.parseMultiplication();
|
||||
expr = try self.mkBinary(expr, op, right);
|
||||
expr = try self.mkBinary(expr, try toBinaryOperator(op), right);
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
@ -992,7 +1013,7 @@ pub const Parser = struct {
|
|||
_ = try self.nextToken();
|
||||
var right = try self.parseUnary();
|
||||
|
||||
expr = try self.mkBinary(expr, op, right);
|
||||
expr = try self.mkBinary(expr, try toBinaryOperator(op), right);
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
|
Loading…
Reference in a new issue