vig/src/ast.zig

168 lines
3.8 KiB
Zig

const std = @import("std");
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);
// TODO convert FnCall to something like PrefixOp / InfixOp / SuffixOp
pub const NodeType = enum {
Root,
FnDecl,
ConstDecl,
Block,
Expr,
};
pub const ParamDecl = struct {
name: Token,
// TODO types
typ: Token,
};
pub const FnDecl = struct {
func_name: Token,
params: ParamList,
body: ExprList,
};
pub const SingleConst = struct {
name: Token,
// TODO expr
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,
// TODO StmtList
Block: ExprList,
Expr: *Expr,
};
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {
var node = try allocator.create(Node);
node.* = Node{ .Root = NodeList.init(allocator) };
return node;
}
fn printIdent(ident: usize) void {
var i: usize = 0;
while (i < ident) : (i += 1) {
std.debug.warn("\t");
}
}
fn print(ident: usize, comptime fmt: []const u8, args: ...) void {
printIdent(ident);
std.debug.warn(fmt, args);
}
pub fn printNode(node: *Node, ident: usize) void {
switch (node.*) {
.FnDecl => |decl| {
print(ident, "FnDecl name='{}'\n", decl.func_name.lexeme);
for (decl.params.toSlice()) |param| {
print(
ident + 1,
"param: '{}' {}\n",
param.name.lexeme,
param.typ.lexeme,
);
}
for (decl.body.toSlice()) |expr| {
printIdent(ident + 1);
printExpr(expr);
std.debug.warn("\n");
}
},
.ConstDecl => |consts| {
print(ident, "ConstDecl ({} consts)\n", consts.len);
for (consts.toSlice()) |const_decl| {
print(
ident + 1,
"'{}' = '{}'\n",
const_decl.name.lexeme,
const_decl.value.lexeme,
);
}
},
.Root => {
for (node.Root.toSlice()) |child| {
printNode(child, ident + 1);
}
},
.Expr => |expr| printExpr(expr),
else => {
print(ident, "unknown node: {}\n", node);
},
}
}
fn parenthetize(name: []const u8, exprs: []*Expr) void {
std.debug.warn("({}", name);
for (exprs) |expr| {
std.debug.warn(" ");
printExpr(expr);
}
std.debug.warn(")");
}
pub fn printExpr(expr: *Expr) void {
switch (expr.*) {
.Binary => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }),
.Unary => |unary| parenthetize(unary.op.lexeme, &[_]*Expr{unary.right}),
.Grouping => |expr_ptr| parenthetize("group", &[_]*Expr{expr_ptr}),
.Literal => |literal| {
switch (literal) {
.Bool => |val| std.debug.warn("{}", val),
.Integer => |val| std.debug.warn("{}", val),
.Float => |val| std.debug.warn("{}", val),
.String => |val| std.debug.warn("'{}'", val),
}
},
else => std.debug.warn("unknown"),
}
}