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,
ParamDecl,
Block,
Payload,
Switch,
SwitchCase,
SwitchElse,
While,
InfixOp,
PrefixOp,
SuffixOp,
@ -58,9 +60,11 @@ pub const Node = struct {
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "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.SwitchCase => @fieldParentPtr(NodeSwitchCase, "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.PrefixOp => @fieldParentPtr(NodePrefixOp, "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.ParamDecl => @fieldParentPtr(NodeParamDecl, "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.SwitchCase => @fieldParentPtr(NodeSwitchCase, "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.PrefixOp => @fieldParentPtr(NodePrefixOp, "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.ParamDecl => @fieldParentPtr(NodeParamDecl, "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.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.PrefixOp => @fieldParentPtr(NodePrefixOp, "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 {
base: Node,
switch_token: Token,
@ -576,22 +609,17 @@ pub const NodeSwitch = struct {
pub const NodeSwitchCase = struct {
base: Node,
items: ArrayList(&Node),
capture: ?Capture,
payload: ?&Node,
expr: &Node,
const Capture = struct {
symbol: &NodeIdentifier,
is_ptr: bool,
};
pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
var i = index;
if (i < self.items.len) return self.items.at(i);
i -= self.items.len;
if (self.capture) |capture| {
if (i < 1) return &capture.base;
if (self.payload) |payload| {
if (i < 1) return payload;
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 {
base: Node,
op_token: Token,
@ -661,7 +749,7 @@ pub const NodeInfixOp = struct {
BitXor,
BoolAnd,
BoolOr,
Catch: ?&NodeIdentifier,
Catch: ?&Node,
Div,
EqualEqual,
ErrorUnion,

View File

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