std.zig.parser WIP generalizing parsing of payloads

* Note, it doesn't work :)
master
Jimmi Holst Christensen 2018-04-08 17:05:08 +02:00
parent bdff5bfa3e
commit e4d0b46c0c
2 changed files with 161 additions and 51 deletions

View File

@ -20,9 +20,11 @@ pub const Node = struct {
FnProto, FnProto,
ParamDecl, ParamDecl,
Block, Block,
Payload,
Switch, Switch,
SwitchCase, SwitchCase,
SwitchElse, SwitchElse,
While,
InfixOp, InfixOp,
PrefixOp, PrefixOp,
SuffixOp, SuffixOp,
@ -58,9 +60,11 @@ pub const Node = struct {
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index), Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index), Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),
Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index), Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
Id.Payload => @fieldParentPtr(NodePayload, "base", base).iterate(index),
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index), Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index), Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index),
Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index), Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index),
Id.While => @fieldParentPtr(NodeWhile, "base", base).iterate(index),
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index), Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index), Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index), Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index),
@ -97,9 +101,11 @@ pub const Node = struct {
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(), Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(), Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),
Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(), Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
Id.Payload => @fieldParentPtr(NodePayload, "base", base).firstToken(),
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(), Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(), Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(),
Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(), Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(),
Id.While => @fieldParentPtr(NodeWhile, "base", base).firstToken(),
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(), Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(), Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(), Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(),
@ -136,9 +142,11 @@ pub const Node = struct {
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(), Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(), Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),
Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(), Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
Id.Payload => @fieldParentPtr(NodePayload, "base", base).lastToken(),
Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(), Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(),
Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(), Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(),
Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(), Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).lastToken(),
Id.While => @fieldParentPtr(NodeWhile, "base", base).lastToken(),
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(), Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(), Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(), Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(),
@ -545,6 +553,31 @@ pub const NodeBlock = struct {
} }
}; };
pub const NodePayload = struct {
base: Node,
lpipe: Token,
is_ptr: bool,
symbol: &NodeIdentifier,
rpipe: Token,
pub fn iterate(self: &NodePayload, index: usize) ?&Node {
var i = index;
if (i < 1) return &self.symbol.base;
i -= 1;
return null;
}
pub fn firstToken(self: &NodePayload) Token {
return self.lpipe;
}
pub fn lastToken(self: &NodePayload) Token {
return self.rpipe;
}
};
pub const NodeSwitch = struct { pub const NodeSwitch = struct {
base: Node, base: Node,
switch_token: Token, switch_token: Token,
@ -576,22 +609,17 @@ pub const NodeSwitch = struct {
pub const NodeSwitchCase = struct { pub const NodeSwitchCase = struct {
base: Node, base: Node,
items: ArrayList(&Node), items: ArrayList(&Node),
capture: ?Capture, payload: ?&Node,
expr: &Node, expr: &Node,
const Capture = struct {
symbol: &NodeIdentifier,
is_ptr: bool,
};
pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node { pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
var i = index; var i = index;
if (i < self.items.len) return self.items.at(i); if (i < self.items.len) return self.items.at(i);
i -= self.items.len; i -= self.items.len;
if (self.capture) |capture| { if (self.payload) |payload| {
if (i < 1) return &capture.base; if (i < 1) return payload;
i -= 1; i -= 1;
} }
@ -627,6 +655,66 @@ pub const NodeSwitchElse = struct {
} }
}; };
pub const NodeWhile = struct {
base: Node,
while_token: Token,
condition: &Node,
payload: ?&NodePayload,
continue_expr: ?&Node,
body: &Node,
@"else": ?Else,
const Else = struct {
capture: ?&NodeIdentifier,
body: &Node,
};
pub fn iterate(self: &NodeWhile, index: usize) ?&Node {
var i = index;
if (i < 1) return self.condition;
i -= 1;
if (self.payload) |payload| {
if (i < 1) return &payload.base;
i -= 1;
}
if (self.continue_expr) |continue_expr| {
if (i < 1) return continue_expr;
i -= 1;
}
if (i < 1) return self.body;
i -= 1;
if (self.@"else") |@"else"| {
if (@"else".capture) |capture| {
if (i < 1) return &capture.base;
i -= 1;
}
if (i < 1) return @"else".body;
i -= 1;
}
return null;
}
pub fn firstToken(self: &NodeWhile) Token {
return self.while_token;
}
pub fn lastToken(self: &NodeWhile) Token {
if (self.@"else") |@"else"| {
return @"else".body.lastToken();
}
return self.body.lastToken();
}
};
pub const NodeInfixOp = struct { pub const NodeInfixOp = struct {
base: Node, base: Node,
op_token: Token, op_token: Token,
@ -661,7 +749,7 @@ pub const NodeInfixOp = struct {
BitXor, BitXor,
BoolAnd, BoolAnd,
BoolOr, BoolOr,
Catch: ?&NodeIdentifier, Catch: ?&Node,
Div, Div,
EqualEqual, EqualEqual,
ErrorUnion, ErrorUnion,

View File

@ -104,6 +104,11 @@ pub const Parser = struct {
ptr: &Token, ptr: &Token,
}; };
const ElseCtx = struct {
payload: ?DestPtr,
body: DestPtr,
};
fn ListSave(comptime T: type) type { fn ListSave(comptime T: type) type {
return struct { return struct {
list: &ArrayList(T), list: &ArrayList(T),
@ -140,7 +145,7 @@ pub const Parser = struct {
FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer), FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
FieldListCommaOrEnd: &ast.NodeContainerDecl, FieldListCommaOrEnd: &ast.NodeContainerDecl,
SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase), SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
SwitchCaseCapture: &?ast.NodeSwitchCase.Capture, Payload: DestPtr,
SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase), SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
SwitchCaseItem: &ArrayList(&ast.Node), SwitchCaseItem: &ArrayList(&ast.Node),
SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node), SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
@ -635,9 +640,6 @@ pub const Parser = struct {
Token.Id.Keyword_await => { Token.Id.Keyword_await => {
@panic("TODO: await"); @panic("TODO: await");
}, },
Token.Id.Keyword_suspend => {
@panic("TODO: suspend");
},
else => { else => {
self.putBackToken(token); self.putBackToken(token);
stack.append(State { .AssignmentExpressionBegin = dest_ptr }) catch unreachable; stack.append(State { .AssignmentExpressionBegin = dest_ptr }) catch unreachable;
@ -705,21 +707,14 @@ pub const Parser = struct {
stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable; stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }); try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
const next = self.getNextToken();
if (next.id != Token.Id.Pipe) {
self.putBackToken(next);
continue;
}
node.op.Catch = try self.createIdentifier(arena, Token(undefined));
try stack.append(State { .ExpectToken = Token.Id.Pipe });
try stack.append(State { try stack.append(State {
.ExpectTokenSave = ExpectTokenSave { .Optional = RevertState {
.id = Token.Id.Identifier, .tokenizer = *self.tokenizer,
.ptr = &(??node.op.Catch).name_token .parser = *self,
.ptr = &node.op.Catch,
} }
}); });
try stack.append(State { .Payload = DestPtr { .NullableField = &node.op.Catch } });
continue; continue;
}, },
Token.Id.QuestionMarkQuestionMark => { Token.Id.QuestionMarkQuestionMark => {
@ -1404,12 +1399,25 @@ pub const Parser = struct {
@panic("TODO: inline if"); @panic("TODO: inline if");
}, },
Token.Id.Keyword_while => { Token.Id.Keyword_while => {
const node = try arena.create(ast.NodeWhile);
*node = ast.NodeWhile {
.base = self.initNode(ast.Node.Id.While),
.while_token = token,
.condition = undefined,
.payload = null,
.continue_expr = null,
.body = undefined,
.@"else" = null,
};
dest_ptr.store(&node.base);
@panic("TODO: inline while"); @panic("TODO: inline while");
}, },
Token.Id.Keyword_for => { Token.Id.Keyword_for => {
@panic("TODO: inline for"); @panic("TODO: inline for");
}, },
Token.Id.Keyword_switch => { Token.Id.Keyword_switch => {
@breakpoint();
const node = try arena.create(ast.NodeSwitch); const node = try arena.create(ast.NodeSwitch);
*node = ast.NodeSwitch { *node = ast.NodeSwitch {
.base = self.initNode(ast.Node.Id.Switch), .base = self.initNode(ast.Node.Id.Switch),
@ -1434,9 +1442,6 @@ pub const Parser = struct {
Token.Id.Keyword_comptime => { Token.Id.Keyword_comptime => {
@panic("TODO: inline comptime"); @panic("TODO: inline comptime");
}, },
Token.Id.Keyword_suspend => {
@panic("TODO: inline suspend");
},
else => { else => {
try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id)); try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
continue; continue;
@ -1547,13 +1552,21 @@ pub const Parser = struct {
*node = ast.NodeSwitchCase { *node = ast.NodeSwitchCase {
.base = self.initNode(ast.Node.Id.SwitchCase), .base = self.initNode(ast.Node.Id.SwitchCase),
.items = ArrayList(&ast.Node).init(arena), .items = ArrayList(&ast.Node).init(arena),
.capture = null, .payload = null,
.expr = undefined, .expr = undefined,
}; };
try list_state.list.append(node); try list_state.list.append(node);
stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable; stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } }); try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } });
try stack.append(State { .SwitchCaseCapture = &node.capture }); try stack.append(State {
.Optional = RevertState {
.tokenizer = *self.tokenizer,
.parser = *self,
.ptr = &node.payload,
}
});
try stack.append(State { .Payload = DestPtr { .NullableField = &node.payload } });
try stack.append(State.Required);
const maybe_else = self.getNextToken(); const maybe_else = self.getNextToken();
if (maybe_else.id == Token.Id.Keyword_else) { if (maybe_else.id == Token.Id.Keyword_else) {
@ -1572,12 +1585,8 @@ pub const Parser = struct {
} }
}, },
State.SwitchCaseCapture => |capture| { State.Payload => |dest_ptr| {
const token = self.getNextToken(); const lpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
if (token.id != Token.Id.Pipe) {
self.putBackToken(token);
continue;
}
const is_ptr = blk: { const is_ptr = blk: {
const asterik = self.getNextToken(); const asterik = self.getNextToken();
@ -1590,11 +1599,16 @@ pub const Parser = struct {
}; };
const ident = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; const ident = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
_ = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
*capture = ast.NodeSwitchCase.Capture { const node = try arena.create(ast.NodePayload);
*node = ast.NodePayload {
.base = self.initNode(ast.Node.Id.Payload),
.lpipe = lpipe,
.is_ptr = is_ptr,
.symbol = try self.createIdentifier(arena, ident), .symbol = try self.createIdentifier(arena, ident),
.is_ptr = is_ptr .rpipe = rpipe
}; };
dest_ptr.store(&node.base);
}, },
State.SwitchCaseItem => |case_items| { State.SwitchCaseItem => |case_items| {
@ -1856,6 +1870,8 @@ pub const Parser = struct {
stack.append(State { .Block = inner_block }) catch unreachable; stack.append(State { .Block = inner_block }) catch unreachable;
continue; continue;
}, },
Token.Id.Keyword_suspend, Token.Id.Keyword_if,
Token.Id.Keyword_while, Token.Id.Keyword_for,
Token.Id.Keyword_switch => { Token.Id.Keyword_switch => {
self.putBackToken(next); self.putBackToken(next);
stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }) catch unreachable; stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }) catch unreachable;
@ -2572,9 +2588,8 @@ pub const Parser = struct {
if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) { if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
if (prefix_op_node.op.Catch) |payload| { if (prefix_op_node.op.Catch) |payload| {
try stack.append(RenderState { .Text = "| " }); try stack.append(RenderState { .Text = " " });
try stack.append(RenderState { .Expression = &payload.base }); try stack.append(RenderState { .Expression = payload });
try stack.append(RenderState { .Text = "|" });
} }
try stack.append(RenderState { .Text = " catch " }); try stack.append(RenderState { .Text = " catch " });
} else { } else {
@ -2764,6 +2779,17 @@ pub const Parser = struct {
try stack.append(RenderState { .Expression = rhs }); try stack.append(RenderState { .Expression = rhs });
} }
}, },
ast.Node.Id.Payload => {
const payload = @fieldParentPtr(ast.NodePayload, "base", base);
try stack.append(RenderState { .Text = "|"});
try stack.append(RenderState { .Expression = &payload.symbol.base });
if (payload.is_ptr) {
try stack.append(RenderState { .Text = "*"});
}
try stack.append(RenderState { .Text = "|"});
},
ast.Node.Id.GroupedExpression => { ast.Node.Id.GroupedExpression => {
const grouped_expr = @fieldParentPtr(ast.NodeGroupedExpression, "base", base); const grouped_expr = @fieldParentPtr(ast.NodeGroupedExpression, "base", base);
try stack.append(RenderState { .Text = ")"}); try stack.append(RenderState { .Text = ")"});
@ -2985,14 +3011,9 @@ pub const Parser = struct {
const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base); const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base);
try stack.append(RenderState { .Expression = switch_case.expr }); try stack.append(RenderState { .Expression = switch_case.expr });
if (switch_case.capture) |capture| { if (switch_case.payload) |payload| {
try stack.append(RenderState { .Text = "| "}); try stack.append(RenderState { .Text = " " });
try stack.append(RenderState { .Expression = &capture.symbol.base }); try stack.append(RenderState { .Expression = payload });
if (capture.is_ptr) {
try stack.append(RenderState { .Text = "*"});
}
try stack.append(RenderState { .Text = "|"});
} }
try stack.append(RenderState { .Text = " => "}); try stack.append(RenderState { .Text = " => "});
@ -3011,6 +3032,7 @@ pub const Parser = struct {
const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base); const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base);
try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token)); try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
}, },
ast.Node.Id.While => @panic("TODO: Render while"),
ast.Node.Id.StructField, ast.Node.Id.StructField,
ast.Node.Id.UnionTag, ast.Node.Id.UnionTag,