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 (
|
const (
|
||||||
AWOO = 2
|
Cock = 1
|
||||||
|
Ball = 2
|
||||||
|
Deals = 3
|
||||||
|
Businesses = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
fn main(a int) {}
|
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;
|
const Token = tokens.Token;
|
||||||
|
|
||||||
pub const NodeList = std.ArrayList(*Node);
|
pub const NodeList = std.ArrayList(*Node);
|
||||||
|
pub const ExprList = std.ArrayList(*Expr);
|
||||||
pub const ParamList = std.ArrayList(ParamDecl);
|
pub const ParamList = std.ArrayList(ParamDecl);
|
||||||
pub const ConstList = std.ArrayList(SingleConst);
|
pub const ConstList = std.ArrayList(SingleConst);
|
||||||
|
|
||||||
|
@ -10,9 +11,9 @@ pub const ConstList = std.ArrayList(SingleConst);
|
||||||
pub const NodeType = enum {
|
pub const NodeType = enum {
|
||||||
Root,
|
Root,
|
||||||
FnDecl,
|
FnDecl,
|
||||||
FnCall,
|
|
||||||
ConstDecl,
|
ConstDecl,
|
||||||
String,
|
Block,
|
||||||
|
Expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ParamDecl = struct {
|
pub const ParamDecl = struct {
|
||||||
|
@ -28,11 +29,6 @@ pub const FnDecl = struct {
|
||||||
body: NodeList,
|
body: NodeList,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const FnCall = struct {
|
|
||||||
func_name: Token,
|
|
||||||
arguments: NodeList,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const SingleConst = struct {
|
pub const SingleConst = struct {
|
||||||
name: Token,
|
name: Token,
|
||||||
|
|
||||||
|
@ -40,12 +36,37 @@ pub const SingleConst = struct {
|
||||||
value: Token,
|
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) {
|
pub const Node = union(NodeType) {
|
||||||
Root: NodeList,
|
Root: NodeList,
|
||||||
FnDecl: FnDecl,
|
FnDecl: FnDecl,
|
||||||
ConstDecl: ConstList,
|
ConstDecl: ConstList,
|
||||||
FnCall: FnCall,
|
Block: ExprList,
|
||||||
String: Token,
|
Expr: *Expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {
|
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 Token = tokens.Token;
|
||||||
const TokenType = tokens.TokenType;
|
const TokenType = tokens.TokenType;
|
||||||
const Result = main.Result;
|
const Result = main.Result;
|
||||||
|
|
||||||
const Node = ast.Node;
|
const Node = ast.Node;
|
||||||
|
const Expr = ast.Expr;
|
||||||
|
|
||||||
pub const Parser = struct {
|
pub const Parser = struct {
|
||||||
allocator: *Allocator,
|
allocator: *Allocator,
|
||||||
|
@ -107,6 +109,14 @@ pub const Parser = struct {
|
||||||
return Result.CompileError;
|
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 {
|
fn mkFnDecl(self: *Parser, name: Token, params: ast.ParamList) !*ast.Node {
|
||||||
var node = try self.allocator.create(Node);
|
var node = try self.allocator.create(Node);
|
||||||
node.* = Node{
|
node.* = Node{
|
||||||
|
@ -127,6 +137,120 @@ pub const Parser = struct {
|
||||||
return node;
|
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 {
|
fn functionDecl(self: *Parser) !*ast.Node {
|
||||||
|
|
||||||
// function body
|
// function body
|
||||||
|
@ -164,19 +288,7 @@ pub const Parser = struct {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(self: *Parser) anyerror!*ast.Node {
|
fn parseFnDecl(self: *@This()) !?*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 {
|
|
||||||
var param_list = ast.ParamList.init(self.allocator);
|
var param_list = ast.ParamList.init(self.allocator);
|
||||||
errdefer param_list.deinit();
|
errdefer param_list.deinit();
|
||||||
|
|
||||||
|
@ -197,15 +309,15 @@ pub const Parser = struct {
|
||||||
|
|
||||||
_ = try self.consumeSingle(.RightParen);
|
_ = try self.consumeSingle(.RightParen);
|
||||||
|
|
||||||
_ = try self.consumeSingle(.LeftBrace);
|
// TODO return type
|
||||||
// TODO block
|
|
||||||
_ = try self.consumeSingle(.RightBrace);
|
var block = try self.parseBlock();
|
||||||
|
|
||||||
std.debug.warn("!fn name: {}\n", name);
|
std.debug.warn("!fn name: {}\n", name);
|
||||||
return try self.mkFnDecl(name, param_list);
|
return try self.mkFnDecl(name, param_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constDecl(self: *@This()) !?*Node {
|
fn parseConstDecl(self: *@This()) !?*Node {
|
||||||
var consts = ast.ConstList.init(self.allocator);
|
var consts = ast.ConstList.init(self.allocator);
|
||||||
errdefer consts.deinit();
|
errdefer consts.deinit();
|
||||||
|
|
||||||
|
@ -230,10 +342,10 @@ pub const Parser = struct {
|
||||||
return self.mkConstDecl(consts);
|
return self.mkConstDecl(consts);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn topDecl(self: *@This()) !?*Node {
|
fn parseTopDecl(self: *@This()) !?*Node {
|
||||||
return switch (self.peek().ttype) {
|
return switch (self.peek().ttype) {
|
||||||
.Fn => try self.fnDecl(),
|
.Fn => try self.parseFnDecl(),
|
||||||
.Const => try self.constDecl(),
|
.Const => try self.parseConstDecl(),
|
||||||
|
|
||||||
else => |ttype| blk: {
|
else => |ttype| blk: {
|
||||||
self.doError("(basic) expected fn/const, got {}\n", ttype);
|
self.doError("(basic) expected fn/const, got {}\n", ttype);
|
||||||
|
@ -242,31 +354,145 @@ pub const Parser = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(self: *Parser) !*ast.Node {
|
fn parseBlock(self: *@This()) !?*Node {
|
||||||
self.tokens = try self.allocator.alloc(Token, 0);
|
var exprs = ast.ExprList.init(self.allocator);
|
||||||
var root = try ast.mkRoot(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) {
|
_ = try self.consumeSingle(.RightBrace);
|
||||||
if (token_opt == null) {
|
|
||||||
token_opt = try self.nextToken();
|
|
||||||
} else {
|
|
||||||
token_opt = self.peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
var token = token_opt.?;
|
return try self.mkBlock(exprs);
|
||||||
if (token.ttype == .EOF) break;
|
}
|
||||||
|
|
||||||
var node = try self.topDecl();
|
fn parseExpr(self: *@This()) anyerror!*Node {
|
||||||
if (node == null) continue;
|
var expr = try self.parseEquality();
|
||||||
try root.Root.append(node.?);
|
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 expr;
|
||||||
return error.ParseError;
|
}
|
||||||
|
|
||||||
|
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