add (untested) expression parsing

This commit is contained in:
Luna 2019-08-23 22:13:26 -03:00
parent 899c015cbe
commit f9cc734965
3 changed files with 298 additions and 48 deletions

View File

@ -1,5 +1,8 @@
const (
AWOO = 2
Cock = 1
Ball = 2
Deals = 3
Businesses = 4
)
fn main(a int) {}

View File

@ -3,6 +3,7 @@ const tokens = @import("tokens.zig");
const Token = tokens.Token;
pub const NodeList = std.ArrayList(*Node);
pub const ExprList = std.ArrayList(*Expr);
pub const ParamList = std.ArrayList(ParamDecl);
pub const ConstList = std.ArrayList(SingleConst);
@ -10,9 +11,9 @@ pub const ConstList = std.ArrayList(SingleConst);
pub const NodeType = enum {
Root,
FnDecl,
FnCall,
ConstDecl,
String,
Block,
Expr,
};
pub const ParamDecl = struct {
@ -28,11 +29,6 @@ pub const FnDecl = struct {
body: NodeList,
};
pub const FnCall = struct {
func_name: Token,
arguments: NodeList,
};
pub const SingleConst = struct {
name: Token,
@ -40,12 +36,37 @@ pub const SingleConst = struct {
value: Token,
};
pub const BinaryExpr = struct {
left: *Expr,
op: Token,
right: *Expr,
};
pub const UnaryExpr = struct {
op: Token,
right: *Expr,
};
pub const LiteralExpr = union(enum) {
Bool: bool,
Integer: []const u8,
Float: []const u8,
String: []const u8,
};
pub const Expr = union(enum) {
Binary: BinaryExpr,
Unary: UnaryExpr,
Literal: LiteralExpr,
Grouping: *Expr,
};
pub const Node = union(NodeType) {
Root: NodeList,
FnDecl: FnDecl,
ConstDecl: ConstList,
FnCall: FnCall,
String: Token,
Block: ExprList,
Expr: *Expr,
};
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {

View File

@ -10,7 +10,9 @@ const Scanner = scanners.Scanner;
const Token = tokens.Token;
const TokenType = tokens.TokenType;
const Result = main.Result;
const Node = ast.Node;
const Expr = ast.Expr;
pub const Parser = struct {
allocator: *Allocator,
@ -107,6 +109,14 @@ pub const Parser = struct {
return Result.CompileError;
}
fn compareAnyOf(self: *@This(), ttypes: []TokenType) bool {
for (ttypes) |ttype| {
if (self.peek().ttype == ttype) return true;
}
return false;
}
fn mkFnDecl(self: *Parser, name: Token, params: ast.ParamList) !*ast.Node {
var node = try self.allocator.create(Node);
node.* = Node{
@ -127,6 +137,120 @@ pub const Parser = struct {
return node;
}
fn mkBlock(self: *Parser, exprs: ast.ExprList) !*ast.Node {
var node = try self.allocator.create(Node);
node.* = Node{ .Block = exprs };
return node;
}
fn mkExpr(self: *Parser, expr: *Expr) !*ast.Node {
var node = try self.allocator.create(Node);
node.* = Node{ .Expr = expr };
return node;
}
fn mkGrouping(self: *Parser, expr: *Expr) !*ast.Expr {
var grouping = try self.allocator.create(Expr);
grouping.* = Expr{ .Grouping = expr };
return grouping;
}
fn mkUnary(self: *Parser, op: Token, right: *Expr) !*Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{
.Unary = ast.UnaryExpr{
.op = op,
.right = right,
},
};
return expr;
}
fn mkBinary(self: *Parser, left: *Expr, op: Token, right: *Expr) !*Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{
.Binary = ast.BinaryExpr{
.left = left,
.op = op,
.right = right,
},
};
return expr;
}
fn mkBool(self: *Parser, val: bool) !*ast.Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{
.Literal = ast.LiteralExpr{
.Bool = val,
},
};
return expr;
}
fn mkInteger(self: *Parser, val: []const u8) !*ast.Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{
.Literal = ast.LiteralExpr{
.Integer = val,
},
};
return expr;
}
fn mkFloat(self: *Parser, val: []const u8) !*ast.Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{
.Literal = ast.LiteralExpr{
.Float = val,
},
};
return expr;
}
fn mkString(self: *Parser, val: []const u8) !*ast.Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{
.Literal = ast.LiteralExpr{
.String = val,
},
};
return expr;
}
pub fn parse(self: *Parser) !*ast.Node {
self.tokens = try self.allocator.alloc(Token, 0);
var root = try ast.mkRoot(self.allocator);
var token_opt: ?Token = null;
while (true) {
if (token_opt == null) {
token_opt = try self.nextToken();
} else {
token_opt = self.peek();
}
var token = token_opt.?;
if (token.ttype == .EOF) break;
var node = try self.parseTopDecl();
if (node == null) continue;
try root.Root.append(node.?);
}
if (self.hadError) {
return error.ParseError;
}
return root;
}
fn functionDecl(self: *Parser) !*ast.Node {
// function body
@ -164,19 +288,7 @@ pub const Parser = struct {
return node;
}
fn block(self: *Parser) anyerror!*ast.Node {
// while receiving functions, process more
while (self.accept(.Fn)) {
try self.consumeSingle(.LeftParen);
try self.consumeSingle(.RightParen);
var block = try self.block();
}
self.statement();
}
fn fnDecl(self: *@This()) !?*Node {
fn parseFnDecl(self: *@This()) !?*Node {
var param_list = ast.ParamList.init(self.allocator);
errdefer param_list.deinit();
@ -197,15 +309,15 @@ pub const Parser = struct {
_ = try self.consumeSingle(.RightParen);
_ = try self.consumeSingle(.LeftBrace);
// TODO block
_ = try self.consumeSingle(.RightBrace);
// TODO return type
var block = try self.parseBlock();
std.debug.warn("!fn name: {}\n", name);
return try self.mkFnDecl(name, param_list);
}
fn constDecl(self: *@This()) !?*Node {
fn parseConstDecl(self: *@This()) !?*Node {
var consts = ast.ConstList.init(self.allocator);
errdefer consts.deinit();
@ -230,10 +342,10 @@ pub const Parser = struct {
return self.mkConstDecl(consts);
}
fn topDecl(self: *@This()) !?*Node {
fn parseTopDecl(self: *@This()) !?*Node {
return switch (self.peek().ttype) {
.Fn => try self.fnDecl(),
.Const => try self.constDecl(),
.Fn => try self.parseFnDecl(),
.Const => try self.parseConstDecl(),
else => |ttype| blk: {
self.doError("(basic) expected fn/const, got {}\n", ttype);
@ -242,31 +354,145 @@ pub const Parser = struct {
};
}
pub fn parse(self: *Parser) !*ast.Node {
self.tokens = try self.allocator.alloc(Token, 0);
var root = try ast.mkRoot(self.allocator);
fn parseBlock(self: *@This()) !?*Node {
var exprs = ast.ExprList.init(self.allocator);
errdefer exprs.deinit();
_ = try self.consumeSingle(.LeftBrace);
var token_opt: ?Token = null;
while (self.peek().ttype != .RightBrace)
try exprs.append((try self.parseExpr()).Expr);
while (true) {
if (token_opt == null) {
token_opt = try self.nextToken();
} else {
token_opt = self.peek();
}
_ = try self.consumeSingle(.RightBrace);
var token = token_opt.?;
if (token.ttype == .EOF) break;
return try self.mkBlock(exprs);
}
var node = try self.topDecl();
if (node == null) continue;
try root.Root.append(node.?);
fn parseExpr(self: *@This()) anyerror!*Node {
var expr = try self.parseEquality();
return self.mkExpr(expr);
}
fn parseEquality(self: *@This()) !*Expr {
var expr = try self.parseComparison();
while (self.peek().ttype == .EqualEqual) {
var op = self.peek();
var right = try self.parseComparison();
expr.* = ast.Expr{
.Binary = ast.BinaryExpr{
.left = expr,
.op = op,
.right = right,
},
};
}
if (self.hadError) {
return error.ParseError;
return expr;
}
fn parseComparison(self: *@This()) !*Expr {
var expr = try self.parseAddition();
while (self.compareAnyOf(&[_]TokenType{
.Greater,
.GreaterEqual,
.Less,
.LessEqual,
})) {
var op = self.previous();
var right = try self.parseAddition();
expr.* = ast.Expr{
.Binary = ast.BinaryExpr{
.left = expr,
.op = op,
.right = right,
},
};
}
return root;
return expr;
}
fn parseAddition(self: *@This()) !*Expr {
var expr = try self.parseMultiplication();
while (self.compareAnyOf(&[_]TokenType{
.Minus, .Plus,
})) {
var op = self.previous();
var right = try self.parseMultiplication();
expr.* = ast.Expr{
.Binary = ast.BinaryExpr{
.left = expr,
.op = op,
.right = right,
},
};
}
return expr;
}
fn parseMultiplication(self: *@This()) !*Expr {
var expr = try self.parseUnary();
while (self.compareAnyOf(&[_]TokenType{
.Star, .Slash,
})) {
var op = self.previous();
var right = try self.parseUnary();
expr.* = ast.Expr{
.Binary = ast.BinaryExpr{
.left = expr,
.op = op,
.right = right,
},
};
}
return expr;
}
fn parseUnary(self: *@This()) anyerror!*Expr {
if (self.compareAnyOf(&[_]TokenType{ .Bang, .Minus })) {
var op = self.previous();
var right = try self.parseUnary();
return try self.mkUnary(op, right);
}
return try self.parsePrimary();
}
fn parsePrimary(self: *@This()) !*Expr {
const curtype = self.peek().ttype;
const lexeme = self.peek().lexeme;
_ = switch (curtype) {
.False => return try self.mkBool(false),
.True => return try self.mkBool(true),
.Integer => return try self.mkInteger(lexeme),
.Float => return try self.mkFloat(lexeme),
.String => return try self.mkString(lexeme),
.LeftParen => blk: {
var expr = (try self.parseExpr()).Expr;
_ = try self.consume(.RightParen, "Expected ')' after expression");
break :blk try self.mkGrouping(expr);
},
else => blk: {
self.doError("expected false/true/int/float/string/leftparen, got {}", curtype);
return Result.CompileError;
},
};
std.debug.warn("SHOULD NOT HAVE HAPPENED\n");
return Result.CompileError;
}
};