Compare commits

...

7 Commits

Author SHA1 Message Date
Luna 9eaa71cbd6 remove some debug calls 2019-08-26 15:29:59 -03:00
Luna 9e32ff9e16 parser: split into finishAssignment 2019-08-26 15:19:31 -03:00
Luna c3f0b4b4d5 parser: simplify parseBlock 2019-08-26 14:59:14 -03:00
Luna 1c8eda7305 ast: remove Expr Node (lives under Stmt) 2019-08-26 14:48:53 -03:00
Luna b382c136ec parser: make parseExpr return Expr instead of Node 2019-08-26 14:46:00 -03:00
Luna 3cd19e6515 add todo to readme 2019-08-26 14:30:13 -03:00
Luna 5bb57116c0 update readme 2019-08-26 14:26:58 -03:00
5 changed files with 101 additions and 111 deletions

View File

@ -1,6 +1,6 @@
# vig
a [v] parser in zig
a [v] parser in zig, also a shitpost taken too far
[v]: https://vlang.io
@ -9,20 +9,33 @@ for more epic adventures)
## why
because i want to learn parsers and what best to do it with a language i'm
- because i want to learn parsers and what best to do it with a language i'm
negatively charged towards
- theres an ast now it looks pretty
- i finally understand recursive descent parsers
## variations
- `for` is split between `for` and `loop` because my fucking god i cant stand
having *four* different variations of `for`.
having *four* different variations of `for` to parse.
- struct initialization is with `Struct.{}`, not `Struct{}`, to remove parsing
ambiguities
ambiguities (`if a {}` and `a{}`, v solves that with case, e.g structs Must
Be Properly Titled and i can't bother with that)
## todo
- no `for` yet
- no methods yet (`fn (v Type) blah() blah {...}`)
- do we really want a type system
- do we really want to output c
- do we really want to output llvm
- do we really want to output x86
## how
```
- step 1: dab
- step 2: ```
git clone https://gitdab.com/luna/vig.git
cd vig
zig build install --prefix ~/.local/

View File

@ -37,7 +37,7 @@ fn main(a int) int {
println('skirts')
}
cock_and_ball_torture('cbt', 1, 2, 3)
test('asd', 1, 2, 3)
return 23
@ -48,5 +48,7 @@ fn main(a int) int {
p.x = 69
println(egg.scramble(3).with(cheddar))
println(a.b(3).c(d))
v()()()
}

View File

@ -14,7 +14,6 @@ pub const NodeType = enum {
ConstDecl,
Struct,
Block,
Expr,
Stmt,
};
@ -238,7 +237,6 @@ pub const Node = union(NodeType) {
Block: StmtList,
Expr: *Expr,
Stmt: *Stmt,
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {

View File

@ -70,12 +70,6 @@ pub fn printNode(node: *Node, ident: usize) void {
}
},
.Expr => |expr| {
printIdent(ident);
printExpr(expr);
std.debug.warn("\n");
},
.Stmt => |stmt| {
printIdent(ident);
printStmt(ident, stmt);

View File

@ -88,6 +88,8 @@ pub const Parser = struct {
return token;
}
/// Consume the current token type, then walk to the next token.
/// Returns the consumed token.
fn consume(self: *Parser, ttype: TokenType, comptime msg: []const u8) !Token {
if (self.check(ttype)) {
var tok = self.peek();
@ -99,16 +101,15 @@ pub const Parser = struct {
return Result.CompileError;
}
/// Consume the current token. Gives default error messages
fn consumeSingle(self: *Parser, ttype: TokenType) !Token {
std.debug.warn("consume {}..?", ttype);
if (self.check(ttype)) {
var cur = self.peek();
_ = try self.nextToken();
std.debug.warn(" now has {}\n", self.peek());
return cur;
}
// TODO maybe this could be entirely comptime?
var buf_main: [1000]u8 = undefined;
var buf = try std.fmt.bufPrint(
buf_main[0..],
@ -116,11 +117,12 @@ pub const Parser = struct {
ttype,
self.peek().ttype,
);
try self.tokenError(self.peek(), buf);
try self.tokenError(self.peek(), buf);
return Result.CompileError;
}
/// check() against multiple tokens
fn compareAnyOf(self: *@This(), ttypes: []TokenType) bool {
for (ttypes) |ttype| {
if (self.check(ttype)) return true;
@ -129,6 +131,8 @@ pub const Parser = struct {
return false;
}
// TODO maybe move helper functions to ast_helper.zig?
fn mkFnDecl(
self: *Parser,
name: Token,
@ -160,12 +164,6 @@ pub const Parser = struct {
return node;
}
fn mkExpr(self: *Parser, expr: *Expr) !*ast.Node {
var node = try self.allocator.create(Node);
node.* = Node{ .Expr = expr };
return node;
}
fn mkStmt(self: *Parser, stmt: *Stmt) !*ast.Node {
var node = try self.allocator.create(Node);
node.* = Node{ .Stmt = stmt };
@ -411,17 +409,20 @@ pub const Parser = struct {
errdefer consts.deinit();
_ = try self.consumeSingle(.Const);
_ = try self.consumeSingle(.LeftParen);
while (self.peek().ttype != .RightParen) {
const const_name = try self.consumeSingle(.Identifier);
_ = try self.consumeSingle(.Equal);
// const declarations dont have type, a future type system must
// check the output type of the expression and assign it to the
// const later on.
var expr = try self.parseExpr();
try consts.append(ast.SingleConst{
.name = const_name,
.expr = expr.Expr,
.expr = expr,
});
}
@ -463,31 +464,27 @@ pub const Parser = struct {
.Struct => try self.parseStructDecl(),
else => |ttype| blk: {
self.doError("(basic) expected fn/const, got {}\n", ttype);
self.doError("expected Fn, Const, Struct, got {}\n", ttype);
return Result.CompileError;
},
};
}
fn parseBlock(self: *@This()) !*Node {
var stmts = ast.StmtList.init(self.allocator);
fn parseBlockInternal(self: *@This(), comptime T: type) !T {
var stmts = T.init(self.allocator);
errdefer stmts.deinit();
_ = try self.consumeSingle(.LeftBrace);
while (self.peek().ttype != .RightBrace) {
var stmt = try self.parseDecl();
var stmt = try self.parseStmt();
printer.printNode(try self.mkStmt(stmt), 0);
try stmts.append(stmt);
}
_ = try self.consumeSingle(.RightBrace);
return try self.mkBlock(stmts);
}
fn parseDecl(self: *@This()) !*Stmt {
return try self.parseStmt();
return stmts;
}
fn parseStmt(self: *@This()) anyerror!*Stmt {
@ -496,33 +493,25 @@ pub const Parser = struct {
.Loop => try self.parseLoop(),
.Println => try self.parsePrintln(),
.Return => try self.parseReturn(),
// TODO make newlines tokens and consume newline?
else => try self.parseStmtExpr(),
};
}
/// Copy of parseBlock for blocks in statements
/// Parse a list of statements.
fn parseBlock(self: *@This()) !*Node {
var stmts = try self.parseBlockInternal(ast.StmtList);
return try self.mkBlock(stmts);
}
/// parse blocks inside statements
fn parseStmtBlock(self: *@This()) !ast.Block {
var block = ast.Block.init(self.allocator);
errdefer block.deinit();
_ = try self.consumeSingle(.LeftBrace);
while (self.peek().ttype != .RightBrace) {
var stmt = try self.parseDecl();
printer.printNode(try self.mkStmt(stmt), 0);
try block.append(stmt);
}
_ = try self.consumeSingle(.RightBrace);
var block = try self.parseBlockInternal(ast.Block);
return block;
}
fn parseIfStmt(self: *@This()) !*Stmt {
_ = try self.consumeSingle(.If);
var condition = (try self.parseExpr()).Expr;
var condition = try self.parseExpr();
const then_branch = try self.parseStmtBlock();
@ -546,11 +535,11 @@ pub const Parser = struct {
var expr: ?*Expr = null;
var body: ast.Block = undefined;
// infinite loop
// 'loop {' = infinite loop
if (self.check(.LeftBrace)) {
body = try self.parseStmtBlock();
} else {
expr = (try self.parseExpr()).Expr;
expr = try self.parseExpr();
body = try self.parseStmtBlock();
}
@ -559,7 +548,7 @@ pub const Parser = struct {
fn parseReturn(self: *@This()) !*Stmt {
const tok = try self.consumeSingle(.Return);
const expr = (try self.parseExpr()).Expr;
const expr = try self.parseExpr();
return try Stmt.mkReturn(self.allocator, tok, expr);
}
@ -567,24 +556,23 @@ pub const Parser = struct {
_ = try self.consumeSingle(.Println);
_ = try self.consumeSingle(.LeftParen);
var expr = (try self.parseExpr()).Expr;
var expr = try self.parseExpr();
_ = try self.consumeSingle(.RightParen);
return try Stmt.mkPrintln(self.allocator, expr);
}
fn parseStmtExpr(self: *@This()) !*Stmt {
var expr = (try self.parseExpr()).Expr;
var expr = try self.parseExpr();
return try self.mkStmtExpr(expr);
}
fn parseExpr(self: *@This()) anyerror!*Node {
var expr: *Expr = try self.parseAssignment();
return self.mkExpr(expr);
fn parseExpr(self: *@This()) anyerror!*Expr {
return try self.parseAssignment();
}
fn parseAssignment(self: *@This()) anyerror!*Expr {
// there can be two types coming out of this function:
// there can be two assignments coming out of this function:
// - a mutable/immutable variable declaration with :=
// - an assignment to a variable with =
@ -592,53 +580,50 @@ pub const Parser = struct {
// of this is an Expr, we wrap variable assignments in an Expr as well.
var mutable: bool = false;
std.debug.warn("start assignment pass with cur={}\n", self.peek());
if (self.check(.Mut)) {
_ = try self.consumeSingle(.Mut);
mutable = true;
}
var expr = try self.parseOr();
std.debug.warn("lvalue: {}, cur: {}\n", expr, self.peek());
var value: *Expr = undefined;
var op: Token = undefined;
if (self.check(.ColonEqual) or self.check(.Equal)) {
op = self.peek();
_ = try self.nextToken();
value = try self.parseAssignment();
switch (expr.*) {
.Variable => {
switch (op.ttype) {
.ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable),
.Equal => return try self.mkAssign(expr.Variable, value),
else => unreachable,
}
},
.Get => |get| {
if (op.ttype == .ColonEqual) {
self.doError("can not initialize struct field");
return Result.CompileError;
}
return try self.mkSet(get.struc, get.name, value);
},
else => |expr_typ| {
self.doError("Invalid assignment target {}", expr_typ);
return Result.CompileError;
},
}
return try self.finishAssignment(expr, mutable);
}
return expr;
}
fn finishAssignment(self: *@This(), expr: *Expr, mutable: bool) !*Expr {
var op = self.peek();
_ = try self.nextToken();
var value = try self.parseAssignment();
switch (expr.*) {
.Variable => {
switch (op.ttype) {
.ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable),
.Equal => return try self.mkAssign(expr.Variable, value),
else => unreachable,
}
},
.Get => |get| {
if (op.ttype == .ColonEqual) {
self.doError("can not initialize struct field");
return Result.CompileError;
}
return try self.mkSet(get.struc, get.name, value);
},
else => |expr_typ| {
self.doError("Invalid assignment target {}", expr_typ);
return Result.CompileError;
},
}
}
fn parseOr(self: *@This()) !*Expr {
var expr = try self.parseAnd();
@ -744,18 +729,14 @@ pub const Parser = struct {
return expr;
}
/// Parse either:
/// - A function call
/// - A struct initialization (Point.{...})
/// - A struct Get expression (p.x)
fn parseCall(self: *@This()) !*Expr {
// we parse a primary expression instead of consuming a .Identifier
// since parseCall is connected to the rest of the parser. doing
// identifiers would break the rest of the rules that want primaries.
// nothing stops us from ensuring expr is a Variable though ;)
var expr = try self.parsePrimary();
while (true) {
std.debug.warn("maybe fncall / struct: {}\n", self.peek().ttype);
printer.printExpr(expr);
if (self.check(.LeftParen)) {
_ = try self.consumeSingle(.LeftParen);
expr = try self.finishCall(expr);
@ -766,7 +747,11 @@ pub const Parser = struct {
_ = try self.consumeSingle(.LeftBrace);
expr = try self.finishStructVal(expr);
} else {
var name = try self.consume(.Identifier, "Expect property name after '.'");
var name = try self.consume(
.Identifier,
"Expect property name after '.'",
);
expr = try self.mkGet(expr, name);
}
} else {
@ -784,18 +769,17 @@ pub const Parser = struct {
if (!self.check(.RightParen)) {
// emulating do-while really badly
var arg = (try self.parseExpr()).Expr;
var arg = try self.parseExpr();
try args.append(arg);
while (self.check(.Comma)) {
_ = try self.consumeSingle(.Comma);
arg = (try self.parseExpr()).Expr;
arg = try self.parseExpr();
try args.append(arg);
}
}
// TODO shouldnt consume() return the current token, not nextToken?
var paren = try self.consume(.RightParen, "Expected ')' after arguments");
return self.mkCall(callee, paren, args);
@ -817,7 +801,7 @@ pub const Parser = struct {
// TODO check .Comma for the quick initialization {val,val,val}
_ = try self.consumeSingle(.Colon);
const field_value = (try self.parseExpr()).Expr;
const field_value = try self.parseExpr();
try inits.append(ast.StructInit{
.field = field_name,
@ -845,7 +829,7 @@ pub const Parser = struct {
.LeftParen => blk: {
_ = try self.nextToken();
var expr = (try self.parseExpr()).Expr;
var expr = try self.parseExpr();
_ = try self.consume(.RightParen, "Expected ')' after expression");
// for groupings, we don't want to skip tokens as we already
@ -860,7 +844,6 @@ pub const Parser = struct {
};
_ = try self.nextToken();
return expr;
}
};