Compare commits
7 Commits
6a52297cce
...
9eaa71cbd6
Author | SHA1 | Date |
---|---|---|
Luna | 9eaa71cbd6 | |
Luna | 9e32ff9e16 | |
Luna | c3f0b4b4d5 | |
Luna | 1c8eda7305 | |
Luna | b382c136ec | |
Luna | 3cd19e6515 | |
Luna | 5bb57116c0 |
23
README.md
23
README.md
|
@ -1,6 +1,6 @@
|
||||||
# vig
|
# vig
|
||||||
|
|
||||||
a [v] parser in zig
|
a [v] parser in zig, also a shitpost taken too far
|
||||||
|
|
||||||
[v]: https://vlang.io
|
[v]: https://vlang.io
|
||||||
|
|
||||||
|
@ -9,20 +9,33 @@ for more epic adventures)
|
||||||
|
|
||||||
## why
|
## 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
|
negatively charged towards
|
||||||
|
- theres an ast now it looks pretty
|
||||||
|
- i finally understand recursive descent parsers
|
||||||
|
|
||||||
## variations
|
## variations
|
||||||
|
|
||||||
- `for` is split between `for` and `loop` because my fucking god i cant stand
|
- `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
|
- 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
|
## how
|
||||||
|
|
||||||
```
|
- step 1: dab
|
||||||
|
- step 2: ```
|
||||||
git clone https://gitdab.com/luna/vig.git
|
git clone https://gitdab.com/luna/vig.git
|
||||||
cd vig
|
cd vig
|
||||||
zig build install --prefix ~/.local/
|
zig build install --prefix ~/.local/
|
||||||
|
|
|
@ -37,7 +37,7 @@ fn main(a int) int {
|
||||||
println('skirts')
|
println('skirts')
|
||||||
}
|
}
|
||||||
|
|
||||||
cock_and_ball_torture('cbt', 1, 2, 3)
|
test('asd', 1, 2, 3)
|
||||||
|
|
||||||
return 23
|
return 23
|
||||||
|
|
||||||
|
@ -48,5 +48,7 @@ fn main(a int) int {
|
||||||
|
|
||||||
p.x = 69
|
p.x = 69
|
||||||
|
|
||||||
println(egg.scramble(3).with(cheddar))
|
println(a.b(3).c(d))
|
||||||
|
|
||||||
|
v()()()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ pub const NodeType = enum {
|
||||||
ConstDecl,
|
ConstDecl,
|
||||||
Struct,
|
Struct,
|
||||||
Block,
|
Block,
|
||||||
Expr,
|
|
||||||
Stmt,
|
Stmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -238,7 +237,6 @@ pub const Node = union(NodeType) {
|
||||||
|
|
||||||
Block: StmtList,
|
Block: StmtList,
|
||||||
|
|
||||||
Expr: *Expr,
|
|
||||||
Stmt: *Stmt,
|
Stmt: *Stmt,
|
||||||
|
|
||||||
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {
|
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {
|
||||||
|
|
|
@ -70,12 +70,6 @@ pub fn printNode(node: *Node, ident: usize) void {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.Expr => |expr| {
|
|
||||||
printIdent(ident);
|
|
||||||
printExpr(expr);
|
|
||||||
std.debug.warn("\n");
|
|
||||||
},
|
|
||||||
|
|
||||||
.Stmt => |stmt| {
|
.Stmt => |stmt| {
|
||||||
printIdent(ident);
|
printIdent(ident);
|
||||||
printStmt(ident, stmt);
|
printStmt(ident, stmt);
|
||||||
|
|
175
src/parser.zig
175
src/parser.zig
|
@ -88,6 +88,8 @@ pub const Parser = struct {
|
||||||
return token;
|
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 {
|
fn consume(self: *Parser, ttype: TokenType, comptime msg: []const u8) !Token {
|
||||||
if (self.check(ttype)) {
|
if (self.check(ttype)) {
|
||||||
var tok = self.peek();
|
var tok = self.peek();
|
||||||
|
@ -99,16 +101,15 @@ pub const Parser = struct {
|
||||||
return Result.CompileError;
|
return Result.CompileError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consume the current token. Gives default error messages
|
||||||
fn consumeSingle(self: *Parser, ttype: TokenType) !Token {
|
fn consumeSingle(self: *Parser, ttype: TokenType) !Token {
|
||||||
std.debug.warn("consume {}..?", ttype);
|
|
||||||
|
|
||||||
if (self.check(ttype)) {
|
if (self.check(ttype)) {
|
||||||
var cur = self.peek();
|
var cur = self.peek();
|
||||||
_ = try self.nextToken();
|
_ = try self.nextToken();
|
||||||
std.debug.warn(" now has {}\n", self.peek());
|
|
||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO maybe this could be entirely comptime?
|
||||||
var buf_main: [1000]u8 = undefined;
|
var buf_main: [1000]u8 = undefined;
|
||||||
var buf = try std.fmt.bufPrint(
|
var buf = try std.fmt.bufPrint(
|
||||||
buf_main[0..],
|
buf_main[0..],
|
||||||
|
@ -116,11 +117,12 @@ pub const Parser = struct {
|
||||||
ttype,
|
ttype,
|
||||||
self.peek().ttype,
|
self.peek().ttype,
|
||||||
);
|
);
|
||||||
try self.tokenError(self.peek(), buf);
|
|
||||||
|
|
||||||
|
try self.tokenError(self.peek(), buf);
|
||||||
return Result.CompileError;
|
return Result.CompileError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// check() against multiple tokens
|
||||||
fn compareAnyOf(self: *@This(), ttypes: []TokenType) bool {
|
fn compareAnyOf(self: *@This(), ttypes: []TokenType) bool {
|
||||||
for (ttypes) |ttype| {
|
for (ttypes) |ttype| {
|
||||||
if (self.check(ttype)) return true;
|
if (self.check(ttype)) return true;
|
||||||
|
@ -129,6 +131,8 @@ pub const Parser = struct {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO maybe move helper functions to ast_helper.zig?
|
||||||
|
|
||||||
fn mkFnDecl(
|
fn mkFnDecl(
|
||||||
self: *Parser,
|
self: *Parser,
|
||||||
name: Token,
|
name: Token,
|
||||||
|
@ -160,12 +164,6 @@ pub const Parser = struct {
|
||||||
return node;
|
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 {
|
fn mkStmt(self: *Parser, stmt: *Stmt) !*ast.Node {
|
||||||
var node = try self.allocator.create(Node);
|
var node = try self.allocator.create(Node);
|
||||||
node.* = Node{ .Stmt = stmt };
|
node.* = Node{ .Stmt = stmt };
|
||||||
|
@ -411,17 +409,20 @@ pub const Parser = struct {
|
||||||
errdefer consts.deinit();
|
errdefer consts.deinit();
|
||||||
|
|
||||||
_ = try self.consumeSingle(.Const);
|
_ = try self.consumeSingle(.Const);
|
||||||
|
|
||||||
_ = try self.consumeSingle(.LeftParen);
|
_ = try self.consumeSingle(.LeftParen);
|
||||||
|
|
||||||
while (self.peek().ttype != .RightParen) {
|
while (self.peek().ttype != .RightParen) {
|
||||||
const const_name = try self.consumeSingle(.Identifier);
|
const const_name = try self.consumeSingle(.Identifier);
|
||||||
_ = try self.consumeSingle(.Equal);
|
_ = 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();
|
var expr = try self.parseExpr();
|
||||||
try consts.append(ast.SingleConst{
|
try consts.append(ast.SingleConst{
|
||||||
.name = const_name,
|
.name = const_name,
|
||||||
.expr = expr.Expr,
|
.expr = expr,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,31 +464,27 @@ pub const Parser = struct {
|
||||||
.Struct => try self.parseStructDecl(),
|
.Struct => try self.parseStructDecl(),
|
||||||
|
|
||||||
else => |ttype| blk: {
|
else => |ttype| blk: {
|
||||||
self.doError("(basic) expected fn/const, got {}\n", ttype);
|
self.doError("expected Fn, Const, Struct, got {}\n", ttype);
|
||||||
return Result.CompileError;
|
return Result.CompileError;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseBlock(self: *@This()) !*Node {
|
fn parseBlockInternal(self: *@This(), comptime T: type) !T {
|
||||||
var stmts = ast.StmtList.init(self.allocator);
|
var stmts = T.init(self.allocator);
|
||||||
errdefer stmts.deinit();
|
errdefer stmts.deinit();
|
||||||
|
|
||||||
_ = try self.consumeSingle(.LeftBrace);
|
_ = try self.consumeSingle(.LeftBrace);
|
||||||
|
|
||||||
while (self.peek().ttype != .RightBrace) {
|
while (self.peek().ttype != .RightBrace) {
|
||||||
var stmt = try self.parseDecl();
|
var stmt = try self.parseStmt();
|
||||||
printer.printNode(try self.mkStmt(stmt), 0);
|
printer.printNode(try self.mkStmt(stmt), 0);
|
||||||
try stmts.append(stmt);
|
try stmts.append(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = try self.consumeSingle(.RightBrace);
|
_ = try self.consumeSingle(.RightBrace);
|
||||||
|
|
||||||
return try self.mkBlock(stmts);
|
return stmts;
|
||||||
}
|
|
||||||
|
|
||||||
fn parseDecl(self: *@This()) !*Stmt {
|
|
||||||
return try self.parseStmt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseStmt(self: *@This()) anyerror!*Stmt {
|
fn parseStmt(self: *@This()) anyerror!*Stmt {
|
||||||
|
@ -496,33 +493,25 @@ pub const Parser = struct {
|
||||||
.Loop => try self.parseLoop(),
|
.Loop => try self.parseLoop(),
|
||||||
.Println => try self.parsePrintln(),
|
.Println => try self.parsePrintln(),
|
||||||
.Return => try self.parseReturn(),
|
.Return => try self.parseReturn(),
|
||||||
|
|
||||||
// TODO make newlines tokens and consume newline?
|
|
||||||
else => try self.parseStmtExpr(),
|
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 {
|
fn parseStmtBlock(self: *@This()) !ast.Block {
|
||||||
var block = ast.Block.init(self.allocator);
|
var block = try self.parseBlockInternal(ast.Block);
|
||||||
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);
|
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseIfStmt(self: *@This()) !*Stmt {
|
fn parseIfStmt(self: *@This()) !*Stmt {
|
||||||
_ = try self.consumeSingle(.If);
|
_ = try self.consumeSingle(.If);
|
||||||
var condition = (try self.parseExpr()).Expr;
|
var condition = try self.parseExpr();
|
||||||
|
|
||||||
const then_branch = try self.parseStmtBlock();
|
const then_branch = try self.parseStmtBlock();
|
||||||
|
|
||||||
|
@ -546,11 +535,11 @@ pub const Parser = struct {
|
||||||
var expr: ?*Expr = null;
|
var expr: ?*Expr = null;
|
||||||
var body: ast.Block = undefined;
|
var body: ast.Block = undefined;
|
||||||
|
|
||||||
// infinite loop
|
// 'loop {' = infinite loop
|
||||||
if (self.check(.LeftBrace)) {
|
if (self.check(.LeftBrace)) {
|
||||||
body = try self.parseStmtBlock();
|
body = try self.parseStmtBlock();
|
||||||
} else {
|
} else {
|
||||||
expr = (try self.parseExpr()).Expr;
|
expr = try self.parseExpr();
|
||||||
body = try self.parseStmtBlock();
|
body = try self.parseStmtBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,7 +548,7 @@ pub const Parser = struct {
|
||||||
|
|
||||||
fn parseReturn(self: *@This()) !*Stmt {
|
fn parseReturn(self: *@This()) !*Stmt {
|
||||||
const tok = try self.consumeSingle(.Return);
|
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);
|
return try Stmt.mkReturn(self.allocator, tok, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,24 +556,23 @@ pub const Parser = struct {
|
||||||
_ = try self.consumeSingle(.Println);
|
_ = try self.consumeSingle(.Println);
|
||||||
|
|
||||||
_ = try self.consumeSingle(.LeftParen);
|
_ = try self.consumeSingle(.LeftParen);
|
||||||
var expr = (try self.parseExpr()).Expr;
|
var expr = try self.parseExpr();
|
||||||
_ = try self.consumeSingle(.RightParen);
|
_ = try self.consumeSingle(.RightParen);
|
||||||
|
|
||||||
return try Stmt.mkPrintln(self.allocator, expr);
|
return try Stmt.mkPrintln(self.allocator, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseStmtExpr(self: *@This()) !*Stmt {
|
fn parseStmtExpr(self: *@This()) !*Stmt {
|
||||||
var expr = (try self.parseExpr()).Expr;
|
var expr = try self.parseExpr();
|
||||||
return try self.mkStmtExpr(expr);
|
return try self.mkStmtExpr(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseExpr(self: *@This()) anyerror!*Node {
|
fn parseExpr(self: *@This()) anyerror!*Expr {
|
||||||
var expr: *Expr = try self.parseAssignment();
|
return try self.parseAssignment();
|
||||||
return self.mkExpr(expr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseAssignment(self: *@This()) anyerror!*Expr {
|
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 :=
|
// - a mutable/immutable variable declaration with :=
|
||||||
// - an assignment to a variable 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.
|
// of this is an Expr, we wrap variable assignments in an Expr as well.
|
||||||
var mutable: bool = false;
|
var mutable: bool = false;
|
||||||
|
|
||||||
std.debug.warn("start assignment pass with cur={}\n", self.peek());
|
|
||||||
|
|
||||||
if (self.check(.Mut)) {
|
if (self.check(.Mut)) {
|
||||||
_ = try self.consumeSingle(.Mut);
|
_ = try self.consumeSingle(.Mut);
|
||||||
mutable = true;
|
mutable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var expr = try self.parseOr();
|
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)) {
|
if (self.check(.ColonEqual) or self.check(.Equal)) {
|
||||||
op = self.peek();
|
return try self.finishAssignment(expr, mutable);
|
||||||
_ = 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 expr;
|
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 {
|
fn parseOr(self: *@This()) !*Expr {
|
||||||
var expr = try self.parseAnd();
|
var expr = try self.parseAnd();
|
||||||
|
|
||||||
|
@ -744,18 +729,14 @@ pub const Parser = struct {
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse either:
|
||||||
|
/// - A function call
|
||||||
|
/// - A struct initialization (Point.{...})
|
||||||
|
/// - A struct Get expression (p.x)
|
||||||
fn parseCall(self: *@This()) !*Expr {
|
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();
|
var expr = try self.parsePrimary();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std.debug.warn("maybe fncall / struct: {}\n", self.peek().ttype);
|
|
||||||
printer.printExpr(expr);
|
|
||||||
|
|
||||||
if (self.check(.LeftParen)) {
|
if (self.check(.LeftParen)) {
|
||||||
_ = try self.consumeSingle(.LeftParen);
|
_ = try self.consumeSingle(.LeftParen);
|
||||||
expr = try self.finishCall(expr);
|
expr = try self.finishCall(expr);
|
||||||
|
@ -766,7 +747,11 @@ pub const Parser = struct {
|
||||||
_ = try self.consumeSingle(.LeftBrace);
|
_ = try self.consumeSingle(.LeftBrace);
|
||||||
expr = try self.finishStructVal(expr);
|
expr = try self.finishStructVal(expr);
|
||||||
} else {
|
} 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);
|
expr = try self.mkGet(expr, name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -784,18 +769,17 @@ pub const Parser = struct {
|
||||||
if (!self.check(.RightParen)) {
|
if (!self.check(.RightParen)) {
|
||||||
|
|
||||||
// emulating do-while really badly
|
// emulating do-while really badly
|
||||||
var arg = (try self.parseExpr()).Expr;
|
var arg = try self.parseExpr();
|
||||||
try args.append(arg);
|
try args.append(arg);
|
||||||
|
|
||||||
while (self.check(.Comma)) {
|
while (self.check(.Comma)) {
|
||||||
_ = try self.consumeSingle(.Comma);
|
_ = try self.consumeSingle(.Comma);
|
||||||
|
|
||||||
arg = (try self.parseExpr()).Expr;
|
arg = try self.parseExpr();
|
||||||
try args.append(arg);
|
try args.append(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO shouldnt consume() return the current token, not nextToken?
|
|
||||||
var paren = try self.consume(.RightParen, "Expected ')' after arguments");
|
var paren = try self.consume(.RightParen, "Expected ')' after arguments");
|
||||||
|
|
||||||
return self.mkCall(callee, paren, args);
|
return self.mkCall(callee, paren, args);
|
||||||
|
@ -817,7 +801,7 @@ pub const Parser = struct {
|
||||||
// TODO check .Comma for the quick initialization {val,val,val}
|
// TODO check .Comma for the quick initialization {val,val,val}
|
||||||
|
|
||||||
_ = try self.consumeSingle(.Colon);
|
_ = try self.consumeSingle(.Colon);
|
||||||
const field_value = (try self.parseExpr()).Expr;
|
const field_value = try self.parseExpr();
|
||||||
|
|
||||||
try inits.append(ast.StructInit{
|
try inits.append(ast.StructInit{
|
||||||
.field = field_name,
|
.field = field_name,
|
||||||
|
@ -845,7 +829,7 @@ pub const Parser = struct {
|
||||||
|
|
||||||
.LeftParen => blk: {
|
.LeftParen => blk: {
|
||||||
_ = try self.nextToken();
|
_ = try self.nextToken();
|
||||||
var expr = (try self.parseExpr()).Expr;
|
var expr = try self.parseExpr();
|
||||||
_ = try self.consume(.RightParen, "Expected ')' after expression");
|
_ = try self.consume(.RightParen, "Expected ')' after expression");
|
||||||
|
|
||||||
// for groupings, we don't want to skip tokens as we already
|
// for groupings, we don't want to skip tokens as we already
|
||||||
|
@ -860,7 +844,6 @@ pub const Parser = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = try self.nextToken();
|
_ = try self.nextToken();
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue