add boolean AND and boolean OR

This commit is contained in:
Luna 2019-08-25 13:21:22 -03:00
parent 9b3e9e8139
commit 1ab966b853
5 changed files with 64 additions and 5 deletions

View file

@ -17,4 +17,7 @@ fn main(a int) int {
} else { } else {
println(50) println(50)
} }
a && b
a || b
} }

View file

@ -46,6 +46,13 @@ 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,
@ -66,6 +73,7 @@ pub const ExprType = enum {
Binary, Binary,
Unary, Unary,
Logical,
Literal, Literal,
Variable, Variable,
Grouping, Grouping,
@ -82,6 +90,7 @@ pub const Expr = union(ExprType) {
Binary: BinaryExpr, Binary: BinaryExpr,
Unary: UnaryExpr, Unary: UnaryExpr,
Logical: LogicalExpr,
Literal: LiteralExpr, Literal: LiteralExpr,
Variable: Token, Variable: Token,
@ -239,6 +248,7 @@ fn parenthetize(name: []const u8, exprs: []*Expr) void {
pub fn printExpr(expr: *Expr) void { pub fn printExpr(expr: *Expr) void {
switch (expr.*) { switch (expr.*) {
.Binary => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }), .Binary => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }),
.Logical => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }),
.Unary => |unary| parenthetize(unary.op.lexeme, &[_]*Expr{unary.right}), .Unary => |unary| parenthetize(unary.op.lexeme, &[_]*Expr{unary.right}),
.Grouping => |expr_ptr| parenthetize("group", &[_]*Expr{expr_ptr}), .Grouping => |expr_ptr| parenthetize("group", &[_]*Expr{expr_ptr}),

View file

@ -201,6 +201,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{
@ -518,7 +531,7 @@ pub const Parser = struct {
mutable = true; mutable = true;
} }
var expr = try self.parseEquality(); var expr = try self.parseOr();
std.debug.warn("lvalue: {}, cur: {}\n", expr, self.peek()); std.debug.warn("lvalue: {}, cur: {}\n", expr, self.peek());
var value: *Expr = undefined; var value: *Expr = undefined;
@ -545,10 +558,38 @@ pub const Parser = struct {
return expr; return expr;
} }
fn parseOr(self: *@This()) !*Expr {
var expr = try self.parseAnd();
while (self.check(.Or)) {
var op = self.peek();
_ = try self.nextToken();
var right = try self.parseAnd();
expr = try self.mkLogical(expr, op, right);
}
return expr;
}
fn parseAnd(self: *@This()) !*Expr {
var expr = try self.parseEquality();
while (self.check(.And)) {
var op = self.peek();
_ = try self.nextToken();
var right = try self.parseEquality();
expr = try self.mkLogical(expr, op, right);
}
return expr;
}
fn parseEquality(self: *@This()) !*Expr { fn parseEquality(self: *@This()) !*Expr {
var expr = try self.parseComparison(); var expr = try self.parseComparison();
while (self.peek().ttype == .EqualEqual) { while (self.check(.EqualEqual)) {
var op = self.peek(); var op = self.peek();
_ = try self.nextToken(); _ = try self.nextToken();

View file

@ -288,8 +288,6 @@ pub const Scanner = struct {
'.' => self.makeToken(.Dot), '.' => self.makeToken(.Dot),
';' => self.makeToken(.Semicolon), ';' => self.makeToken(.Semicolon),
',' => self.makeToken(.Comma), ',' => self.makeToken(.Comma),
'&' => self.makeToken(.Ampersand),
'|' => self.makeToken(.Pipe),
'?' => self.makeToken(.QuestionMark), '?' => self.makeToken(.QuestionMark),
'$' => self.makeToken(.DollarSign), '$' => self.makeToken(.DollarSign),
@ -299,6 +297,12 @@ pub const Scanner = struct {
':' => self.makeMatchToken('=', .ColonEqual, .Colon), ':' => self.makeMatchToken('=', .ColonEqual, .Colon),
// we use the existing .And and .Or tokens
// representing the and and or keywords to
// also have || and &&
'&' => self.makeMatchToken('&', .And, .Address),
'|' => self.makeMatchToken('|', .Or, .Pipe),
'!' => self.makeMatchToken('=', .BangEqual, .Bang), '!' => self.makeMatchToken('=', .BangEqual, .Bang),
'=' => self.makeMatchToken('=', .EqualEqual, .Equal), '=' => self.makeMatchToken('=', .EqualEqual, .Equal),
'>' => self.makeMatchToken('=', .GreaterEqual, .Greater), '>' => self.makeMatchToken('=', .GreaterEqual, .Greater),

View file

@ -11,7 +11,7 @@ pub const TokenType = enum {
Semicolon, Semicolon,
Comma, Comma,
Colon, Colon,
Ampersand, Address,
Pipe, Pipe,
QuestionMark, QuestionMark,
DollarSign, DollarSign,
@ -65,6 +65,7 @@ pub const TokenType = enum {
Module, Module,
Mut, Mut,
Or, Or,
And,
Return, Return,
Struct, Struct,
Type, Type,