add vig's parser

This commit is contained in:
Luna 2019-09-18 15:59:11 -03:00
parent b14a32a104
commit 927c0f6a1c
6 changed files with 1737 additions and 6 deletions

311
src/ast.zig Normal file
View file

@ -0,0 +1,311 @@
const std = @import("std");
const tokens = @import("tokens.zig");
const Token = tokens.Token;
pub const NodeList = std.ArrayList(*Node);
pub const StmtList = std.ArrayList(*Stmt);
pub const ExprList = std.ArrayList(*Expr);
pub const TokenList = std.ArrayList(Token);
pub const ParamList = std.ArrayList(ParamDecl);
pub const ConstList = std.ArrayList(SingleConst);
pub const NodeType = enum {
Root,
FnDecl,
ConstDecl,
Struct,
Enum,
Block,
Stmt,
};
pub const ParamDecl = struct {
name: Token,
typ: Token,
};
pub const MethodData = struct {
variable: Token,
typ: Token,
mutable: bool,
};
pub const FnDecl = struct {
func_name: Token,
params: ParamList,
return_type: Token,
body: StmtList,
method: ?*MethodData,
};
pub const SingleConst = struct {
name: Token,
expr: *Expr,
};
pub const BinaryExpr = struct {
left: *Expr,
op: Token,
right: *Expr,
};
pub const UnaryExpr = struct {
op: Token,
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) {
Bool: bool,
Integer: []const u8,
Float: []const u8,
String: []const u8,
Array: ExprList,
};
pub const AssignExpr = struct {
name: Token,
value: *Expr,
};
pub const ExprType = enum {
Assign,
// vardecls as expressions is a hack
VarDecl,
Binary,
Unary,
Logical,
Literal,
Variable,
Call,
Struct,
Grouping,
Get,
Set,
};
pub const VarDecl = struct {
assign: AssignExpr,
mutable: bool = false,
};
pub const CallExpr = struct {
callee: *Expr,
paren: Token,
arguments: ExprList,
};
pub const StructInit = struct {
field: Token,
expr: *Expr,
};
pub const StructInitList = std.ArrayList(StructInit);
pub const StructExpr = struct {
name: Token,
inits: StructInitList,
};
pub const GetExpr = struct {
struc: *Expr,
name: Token,
};
pub const SetExpr = struct {
struc: *Expr,
field: Token,
value: *Expr,
};
pub const Expr = union(ExprType) {
Assign: AssignExpr,
VarDecl: VarDecl,
Binary: BinaryExpr,
Unary: UnaryExpr,
Logical: LogicalExpr,
Literal: LiteralExpr,
Struct: StructExpr,
Variable: Token,
Grouping: *Expr,
Call: CallExpr,
Get: GetExpr,
Set: SetExpr,
};
pub const Block = std.ArrayList(*Stmt);
pub const IfStmt = struct {
condition: *Expr,
then_branch: Block,
else_branch: ?Block,
};
pub const LoopStmt = struct {
condition: ?*Expr,
then_branch: Block,
};
pub const ForStmt = struct {
index: ?Token,
value: Token,
array: Token,
block: Block,
};
pub const Stmt = union(enum) {
Expr: *Expr,
Println: *Expr,
If: IfStmt,
Loop: LoopStmt,
For: ForStmt,
Return: ReturnStmt,
pub const ReturnStmt = struct {
keyword: Token,
value: *Expr,
};
pub fn mkPrintln(allocator: *std.mem.Allocator, expr: *Expr) !*Stmt {
var stmt = try allocator.create(Stmt);
stmt.* = Stmt{ .Println = expr };
return stmt;
}
pub fn mkIfStmt(
allocator: *std.mem.Allocator,
condition: *Expr,
then: Block,
else_branch: ?Block,
) !*Stmt {
var stmt = try allocator.create(Stmt);
stmt.* = Stmt{
.If = IfStmt{
.condition = condition,
.then_branch = then,
.else_branch = else_branch,
},
};
return stmt;
}
pub fn mkLoop(
allocator: *std.mem.Allocator,
condition: ?*Expr,
then: Block,
) !*Stmt {
var stmt = try allocator.create(Stmt);
stmt.* = Stmt{
.Loop = LoopStmt{
.condition = condition,
.then_branch = then,
},
};
return stmt;
}
pub fn mkFor(allocator: *std.mem.Allocator, index: ?Token, value: Token, array: Token, block: Block) !*Stmt {
var stmt = try allocator.create(Stmt);
stmt.* = Stmt{
.For = ForStmt{
.index = index,
.value = value,
.array = array,
.block = block,
},
};
return stmt;
}
pub fn mkReturn(allocator: *std.mem.Allocator, tok: Token, value: *Expr) !*Stmt {
var stmt = try allocator.create(Stmt);
stmt.* = Stmt{
.Return = ReturnStmt{
.keyword = tok,
.value = value,
},
};
return stmt;
}
};
pub const FieldList = std.ArrayList(StructField);
pub const StructField = struct {
name: Token,
typ: Token,
mutable: bool = false,
public: bool = false,
mutable_outside: bool = false,
};
pub const Struct = struct {
name: Token,
fields: FieldList,
};
pub const Enum = struct {
name: Token,
fields: TokenList,
};
pub const Node = union(NodeType) {
Root: NodeList,
FnDecl: FnDecl,
ConstDecl: ConstList,
Struct: Struct,
Enum: Enum,
Block: StmtList,
Stmt: *Stmt,
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {
var node = try allocator.create(Node);
node.* = Node{ .Root = NodeList.init(allocator) };
return node;
}
pub fn mkStructDecl(allocator: *std.mem.Allocator, name: Token, fields: FieldList) !*Node {
var node = try allocator.create(Node);
node.* = Node{
.Struct = Struct{
.name = name,
.fields = fields,
},
};
return node;
}
pub fn mkEnumDecl(allocator: *std.mem.Allocator, name: Token, fields: TokenList) !*Node {
var node = try allocator.create(Node);
node.* = Node{
.Enum = Enum{
.name = name,
.fields = fields,
},
};
return node;
}
};

288
src/ast_printer.zig Normal file
View file

@ -0,0 +1,288 @@
const std = @import("std");
const tokens = @import("tokens.zig");
const Token = tokens.Token;
usingnamespace @import("ast.zig");
const warn = std.debug.warn;
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);
}
fn printBlock(ident: usize, block: var, endNewline: bool) void {
std.debug.warn("(\n");
for (block.toSlice()) |stmt| {
printIdent(ident);
printStmt(ident, stmt);
std.debug.warn("\n");
}
if (endNewline) {
print(ident - 1, ")\n");
} else {
print(ident - 1, ")");
}
}
pub fn printNode(node: *Node, ident: usize) void {
switch (node.*) {
.FnDecl => |decl| {
const name = decl.func_name.lexeme;
printIdent(ident);
const ret_type = decl.return_type.lexeme;
if (decl.method) |method| {
const vari = method.variable.lexeme;
const typ = method.typ.lexeme;
if (method.mutable) {
warn("(method mut {} {} {} {} ", vari, typ, name, ret_type);
} else {
warn("(method {} {} {} {} ", vari, typ, name, ret_type);
}
} else {
warn("(fn {} {} (", name, ret_type);
}
for (decl.params.toSlice()) |param| {
warn("({} {}) ", param.name.lexeme, param.typ.lexeme);
}
printBlock(ident + 1, decl.body, false);
warn(")\n");
},
.ConstDecl => |consts| {
print(ident, "(const (\n");
for (consts.toSlice()) |const_decl| {
print(
ident + 1,
"({} ",
const_decl.name.lexeme,
);
printExpr(const_decl.expr);
std.debug.warn(")\n");
}
print(ident, "))\n");
},
.Enum => |decl| {
print(ident, "(enum {} (\n", decl.name.lexeme);
for (decl.fields.toSlice()) |field| {
print(
ident + 1,
"{}\n",
field.lexeme,
);
}
print(ident, "))\n");
},
.Root => {
for (node.Root.toSlice()) |child| {
printNode(child, ident + 1);
}
},
.Stmt => |stmt| {
printIdent(ident);
printStmt(ident, stmt);
std.debug.warn("\n");
},
.Struct => |struc| {
print(ident, "(struct {} (\n", struc.name.lexeme);
for (struc.fields.toSlice()) |field| {
printIdent(ident + 1);
if (field.mutable) {
std.debug.warn("(mut ");
} else {
std.debug.warn("(");
}
if (field.public) {
std.debug.warn("pub ");
}
if (field.mutable_outside) {
std.debug.warn("MUT_OUT ");
}
std.debug.warn("{} {})\n", field.name.lexeme, field.typ.lexeme);
}
print(ident, "))\n");
},
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 }),
.Logical => |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),
.Array => |exprs| {
parenthetize("array", exprs.toSlice());
},
else => |typ| std.debug.warn("UnknownLiteral-{}", typ),
}
},
.Variable => |token| std.debug.warn("{}", token.lexeme),
.VarDecl => |decl| {
if (decl.mutable) {
std.debug.warn("(mut ");
} else {
std.debug.warn("(");
}
std.debug.warn("let {} ", decl.assign.name.lexeme);
printExpr(decl.assign.value);
std.debug.warn(")");
},
.Assign => |assign| {
std.debug.warn("(set ");
std.debug.warn("{} ", assign.name.lexeme);
printExpr(assign.value);
std.debug.warn(")");
},
.Call => |call| {
std.debug.warn("(");
printExpr(call.callee);
for (call.arguments.toSlice()) |arg| {
std.debug.warn(" ");
printExpr(arg);
}
std.debug.warn(")");
},
.Struct => |val| {
std.debug.warn("({} (", val.name.lexeme);
for (val.inits.toSlice()) |init| {
std.debug.warn(" ({} ", init.field.lexeme);
printExpr(init.expr);
std.debug.warn(")");
}
std.debug.warn("))");
},
.Get => |get| {
warn("(");
printExpr(get.struc);
warn(".{})", get.name.lexeme);
},
.Set => |set| {
warn("(set ");
printExpr(set.struc);
warn(" {} ", set.field.lexeme);
printExpr(set.value);
warn(")");
},
else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)),
}
}
pub fn printStmt(ident: usize, stmt: *Stmt) void {
switch (stmt.*) {
.Println => |expr| parenthetize("println", &[_]*Expr{expr}),
.Expr => |expr| printExpr(expr),
.If => |ifstmt| {
std.debug.warn("(if ");
printExpr(ifstmt.condition);
std.debug.warn(" ");
printBlock(ident + 1, ifstmt.then_branch, false);
if (ifstmt.else_branch) |else_branch| {
std.debug.warn(" else ");
printBlock(ident + 1, else_branch, false);
}
std.debug.warn(")\n");
},
.Loop => |loop| {
std.debug.warn("(loop ");
if (loop.condition) |cond| {
printExpr(cond);
} else {
std.debug.warn("true");
}
std.debug.warn(" ");
printBlock(ident + 1, loop.then_branch, false);
std.debug.warn(")\n");
},
.For => |forstmt| {
std.debug.warn("(for ");
if (forstmt.index) |index| {
std.debug.warn("({} {}) ", index.lexeme, forstmt.value.lexeme);
} else {
std.debug.warn("{} ", forstmt.value.lexeme);
}
std.debug.warn("{} ", forstmt.array.lexeme);
printBlock(ident + 1, forstmt.block, false);
std.debug.warn(")\n");
},
.Return => |ret| {
std.debug.warn("(return ");
printExpr(ret.value);
std.debug.warn(")\n");
},
else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)),
}
}

15
src/errors.zig Normal file
View file

@ -0,0 +1,15 @@
const std = @import("std");
pub fn report(line: usize, where: []const u8, message: []const u8) void {
std.debug.warn("[line {}] Error{}: {}", line, where, message);
}
pub fn reportN(line: usize, message: []const u8) void {
report(line, "", message);
}
pub fn reportFmt(line: usize, comptime fmt: []const u8, args: ...) void {
std.debug.warn("[line {}] Error", line);
std.debug.warn(fmt, args);
std.debug.warn("\n");
}

View file

@ -1,6 +1,8 @@
const std = @import("std");
const scanners = @import("scanners.zig");
const parsers = @import("parsers.zig");
const printer = @import("ast_printer.zig");
pub const Result = enum {
Ok,
@ -9,9 +11,8 @@ pub const Result = enum {
CompileError,
};
pub fn run(allocator: *std.mem.Allocator, slice: []const u8) Result {
pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result {
var scan = scanners.Scanner.init(allocator, slice);
//defer scan.deinit();
// do a full scan pass, then reset, then do it again (with parser)
while (true) {
@ -35,8 +36,12 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) Result {
// scan.reset();
//var parser = parsers.Parser.init(allocator, scan);
//defer parser.deinit();
var parser = parsers.Parser.init(allocator, &scan);
var root = try parser.parse();
var it = root.Root.iterator();
std.debug.warn("parse tree\n");
//printer.printNode(root, 0);
return Result.Ok;
}
@ -58,8 +63,7 @@ pub fn main() anyerror!void {
_ = try file.read(slice);
const result = run(allocator, slice);
//const result = try run(allocator, slice);
const result = try run(allocator, slice);
switch (result) {
.Ok => std.os.exit(0),

1107
src/parsers.zig Normal file

File diff suppressed because it is too large Load diff

View file

@ -107,6 +107,12 @@ pub const Scanner = struct {
return Scanner{ .allocator = allocator, .source = source };
}
pub fn reset(self: *Scanner) void {
self.start = 0;
self.current = 0;
self.line = 1;
}
fn isAtEnd(self: *Scanner) bool {
return self.current >= self.source.len;
}