add (untested) expression parsing
This commit is contained in:
parent
899c015cbe
commit
f9cc734965
3 changed files with 298 additions and 48 deletions
|
@ -1,5 +1,8 @@
|
|||
const (
|
||||
AWOO = 2
|
||||
Cock = 1
|
||||
Ball = 2
|
||||
Deals = 3
|
||||
Businesses = 4
|
||||
)
|
||||
|
||||
fn main(a int) {}
|
||||
|
|
39
src/ast.zig
39
src/ast.zig
|
@ -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 {
|
||||
|
|
302
src/parser.zig
302
src/parser.zig
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue