self-hosted: parse var decls

This commit is contained in:
Andrew Kelley 2017-12-10 22:44:04 -05:00
parent f210f17d30
commit 53d58684a6

View File

@ -562,9 +562,9 @@ const AstNodeVarDecl = struct {
visib_token: ?Token,
name_token: Token,
eq_token: Token,
mut: Mutability,
is_comptime: Comptime,
is_extern: Extern,
mut_token: Token,
comptime_token: ?Token,
extern_token: ?Token,
lib_name: ?&AstNode,
type_node: ?&AstNode,
align_node: ?&AstNode,
@ -608,10 +608,10 @@ const AstNodeFnProto = struct {
name_token: ?Token,
params: ArrayList(&AstNode),
return_type: ?&AstNode,
var_args: VarArgs,
is_extern: Extern,
is_inline: Inline,
cc: CallingConvention,
var_args_token: ?Token,
extern_token: ?Token,
inline_token: ?Token,
cc_token: ?Token,
fn_def_node: ?&AstNode,
lib_name: ?&AstNode, // populated if this is an extern declaration
align_expr: ?&AstNode, // populated if align(A) is present
@ -729,10 +729,15 @@ const Parser = struct {
self.allocator.free(self.utility_bytes);
}
const TopLevelExternCtx = struct {
visib_token: ?Token,
extern_token: Token,
};
const State = union(enum) {
TopLevel,
TopLevelModifier: ?Token,
TopLevelExtern: ?Token,
TopLevelExtern: TopLevelExternCtx,
Expression: &&AstNode,
GroupedExpression: &&AstNode,
UnwrapExpression: &&AstNode,
@ -803,25 +808,22 @@ const Parser = struct {
stack.append(State { .TopLevelModifier = token }) %% unreachable;
continue;
},
Token.Id.Keyword_const => {
Token.Id.Keyword_const, Token.Id.Keyword_var => {
stack.append(State.TopLevel) %% unreachable;
// TODO shouldn't need this cast
const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null),
Mutability.Const, Comptime.No, Extern.No);
%return stack.append(State { .VarDecl = var_decl_node });
continue;
},
Token.Id.Keyword_var => {
stack.append(State.TopLevel) %% unreachable;
// TODO shouldn't need this cast
const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null),
Mutability.Var, Comptime.No, Extern.No);
token, (?Token)(null), (?Token)(null));
%return stack.append(State { .VarDecl = var_decl_node });
continue;
},
Token.Id.Eof => return root_node,
Token.Id.Keyword_extern => {
stack.append(State { .TopLevelExtern = null }) %% unreachable;
stack.append(State {
.TopLevelExtern = TopLevelExternCtx {
.visib_token = null,
.extern_token = token,
}
}) %% unreachable;
continue;
},
else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)),
@ -830,43 +832,43 @@ const Parser = struct {
State.TopLevelModifier => |visib_token| {
const token = self.getNextToken();
switch (token.id) {
Token.Id.Keyword_const => {
Token.Id.Keyword_const, Token.Id.Keyword_var => {
stack.append(State.TopLevel) %% unreachable;
// TODO shouldn't need the casts here
const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token,
Mutability.Const, Comptime.No, Extern.No);
%return stack.append(State { .VarDecl = var_decl_node });
continue;
},
Token.Id.Keyword_var => {
stack.append(State.TopLevel) %% unreachable;
const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token,
Mutability.Var, Comptime.No, Extern.No);
token, (?Token)(null), (?Token)(null));
%return stack.append(State { .VarDecl = var_decl_node });
continue;
},
Token.Id.Keyword_extern => {
stack.append(State { .TopLevelExtern = visib_token }) %% unreachable;
stack.append(State {
.TopLevelExtern = TopLevelExternCtx {
.visib_token = visib_token,
.extern_token = token,
},
}) %% unreachable;
continue;
},
else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)),
}
},
State.TopLevelExtern => |visib_token| {
State.TopLevelExtern => |ctx| {
const token = self.getNextToken();
switch (token.id) {
Token.Id.Keyword_var => {
Token.Id.Keyword_var, Token.Id.Keyword_const => {
stack.append(State.TopLevel) %% unreachable;
const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token,
Mutability.Var, Comptime.No, Extern.Yes);
// TODO shouldn't need these casts
const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, ctx.visib_token,
token, (?Token)(null), (?Token)(ctx.extern_token));
%return stack.append(State { .VarDecl = var_decl_node });
continue;
},
Token.Id.Keyword_fn => {
stack.append(State.TopLevel) %% unreachable;
%return stack.append(State { .ExpectToken = Token.Id.Semicolon });
// TODO shouldn't need this cast
// TODO shouldn't need these casts
const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, token,
Extern.Yes, CallingConvention.Auto, (?Token)(null), Inline.Auto);
(?Token)(ctx.extern_token), (?Token)(null), (?Token)(null), (?Token)(null));
%return stack.append(State { .FnProto = fn_proto_node });
continue;
},
@ -876,16 +878,10 @@ const Parser = struct {
Token.Id.Keyword_coldcc, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
stack.append(State.TopLevel) %% unreachable;
%return stack.append(State { .ExpectToken = Token.Id.Semicolon });
const cc = switch (token.id) {
Token.Id.Keyword_coldcc => CallingConvention.Cold,
Token.Id.Keyword_nakedcc => CallingConvention.Naked,
Token.Id.Keyword_stdcallcc => CallingConvention.Stdcall,
else => unreachable,
};
const fn_token = %return self.eatToken(Token.Id.Keyword_fn);
// TODO shouldn't need this cast
const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, fn_token,
Extern.Yes, cc, (?Token)(null), Inline.Auto);
(?Token)(ctx.extern_token), (?Token)(token), (?Token)(null), (?Token)(null));
%return stack.append(State { .FnProto = fn_proto_node });
continue;
},
@ -1137,8 +1133,8 @@ const Parser = struct {
return node;
}
fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut: Mutability, is_comptime: Comptime,
is_extern: Extern) -> %&AstNodeVarDecl
fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,
extern_token: &const ?Token) -> %&AstNodeVarDecl
{
const node = %return self.allocator.create(AstNodeVarDecl);
%defer self.allocator.destroy(node);
@ -1146,9 +1142,9 @@ const Parser = struct {
*node = AstNodeVarDecl {
.base = AstNode {.id = AstNode.Id.VarDecl},
.visib_token = *visib_token,
.mut = mut,
.is_comptime = is_comptime,
.is_extern = is_extern,
.mut_token = *mut_token,
.comptime_token = *comptime_token,
.extern_token = *extern_token,
.type_node = null,
.align_node = null,
.init_node = null,
@ -1171,8 +1167,8 @@ const Parser = struct {
return node;
}
fn createFnProto(self: &Parser, fn_token: &const Token, is_extern: Extern,
cc: CallingConvention, visib_token: &const ?Token, is_inline: Inline) -> %&AstNodeFnProto
fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token,
cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) -> %&AstNodeFnProto
{
const node = %return self.allocator.create(AstNodeFnProto);
%defer self.allocator.destroy(node);
@ -1184,10 +1180,10 @@ const Parser = struct {
.fn_token = *fn_token,
.params = ArrayList(&AstNode).init(self.allocator),
.return_type = null,
.var_args = VarArgs.No,
.is_extern = is_extern,
.is_inline = is_inline,
.cc = cc,
.var_args_token = null,
.extern_token = *extern_token,
.inline_token = *inline_token,
.cc_token = *cc_token,
.fn_def_node = null,
.lib_name = null,
.align_expr = null,
@ -1242,18 +1238,19 @@ const Parser = struct {
}
fn createAttachFnProto(self: &Parser, list: &ArrayList(&AstNode), fn_token: &const Token,
is_extern: Extern, cc: CallingConvention, visib_token: &const ?Token, is_inline: Inline) -> %&AstNodeFnProto
extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,
inline_token: &const ?Token) -> %&AstNodeFnProto
{
const node = %return self.createFnProto(fn_token, is_extern, cc, visib_token, is_inline);
const node = %return self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token);
%defer self.allocator.destroy(node);
%return list.append(&node.base);
return node;
}
fn createAttachVarDecl(self: &Parser, list: &ArrayList(&AstNode), visib_token: &const ?Token, mut: Mutability,
is_comptime: Comptime, is_extern: Extern) -> %&AstNodeVarDecl
fn createAttachVarDecl(self: &Parser, list: &ArrayList(&AstNode), visib_token: &const ?Token,
mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) -> %&AstNodeVarDecl
{
const node = %return self.createVarDecl(visib_token, mut, is_comptime, is_extern);
const node = %return self.createVarDecl(visib_token, mut_token, comptime_token, extern_token);
%defer self.allocator.destroy(node);
%return list.append(&node.base);
return node;
@ -1376,8 +1373,8 @@ const Parser = struct {
else => unreachable,
};
}
if (fn_proto.is_extern == Extern.Yes) {
%return stream.print("extern ");
if (fn_proto.extern_token) |extern_token| {
%return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
}
%return stream.print("fn");
@ -1403,6 +1400,30 @@ const Parser = struct {
}
}
},
AstNode.Id.VarDecl => {
const var_decl = @fieldParentPtr(AstNodeVarDecl, "base", decl);
if (var_decl.visib_token) |visib_token| {
%return stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
}
if (var_decl.extern_token) |extern_token| {
%return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
if (var_decl.lib_name != null) {
@panic("TODO");
}
}
if (var_decl.comptime_token) |comptime_token| {
%return stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
}
%return stream.print("{} ", self.tokenizer.getTokenSlice(var_decl.mut_token));
%return stream.print("{}", self.tokenizer.getTokenSlice(var_decl.name_token));
%return stream.print(" = ");
%return stack.append(RenderState { .Text = ";\n" });
if (var_decl.init_node) |init_node| {
%return stack.append(RenderState { .Expression = init_node });
}
},
else => unreachable,
}
},
@ -1570,4 +1591,12 @@ test "zig fmt" {
\\extern fn puts(s: &const u8) -> c_int;
\\
);
testCanonical(
\\const a = b;
\\pub const a = b;
\\var a = b;
\\pub var a = b;
\\
);
}