Commit dbc0457068
lib/std/c/ast.zig
@@ -51,9 +51,14 @@ pub const Error = union(enum) {
ExpectedEnumField: SingleTokenError("expected enum field, found '{}'"),
ExpectedType: SingleTokenError("expected enum field, found '{}'"),
InvalidTypeSpecifier: InvalidTypeSpecifier,
+ InvalidStorageClass: SingleTokenError("invalid storage class, found '{}'"),
+ InvalidDeclarator: SimpleError("invalid declarator"),
DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"),
DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"),
MustUseKwToRefer: MustUseKwToRefer,
+ FnSpecOnNonFn: SingleTokenError("function specifier '{}' on non function"),
+ NothingDeclared: SimpleError("declaration doesn't declare anything"),
+ QualifierIgnored: SingleTokenError("qualifier '{}' ignored"),
pub fn render(self: *const Error, tree: *Tree, stream: var) !void {
switch (self.*) {
@@ -68,9 +73,14 @@ pub const Error = union(enum) {
.ExpectedEnumField => |*x| return x.render(tree, stream),
.ExpectedType => |*x| return x.render(tree, stream),
.InvalidTypeSpecifier => |*x| return x.render(tree, stream),
+ .InvalidStorageClass => |*x| return x.render(tree, stream),
+ .InvalidDeclarator => |*x| return x.render(tree, stream),
.DuplicateQualifier => |*x| return x.render(tree, stream),
.DuplicateSpecifier => |*x| return x.render(tree, stream),
.MustUseKwToRefer => |*x| return x.render(tree, stream),
+ .FnSpecOnNonFn => |*x| return x.render(tree, stream),
+ .NothingDeclared => |*x| return x.render(tree, stream),
+ .QualifierIgnored => |*x| return x.render(tree, stream),
}
}
@@ -87,9 +97,14 @@ pub const Error = union(enum) {
.ExpectedEnumField => |x| return x.token,
.ExpectedType => |*x| return x.token,
.InvalidTypeSpecifier => |x| return x.token,
+ .InvalidStorageClass => |x| return x.token,
+ .InvalidDeclarator => |x| return x.token,
.DuplicateQualifier => |x| return x.token,
.DuplicateSpecifier => |x| return x.token,
.MustUseKwToRefer => |*x| return x.name,
+ .FnSpecOnNonFn => |*x| return x.name,
+ .NothingDeclared => |*x| return x.name,
+ .QualifierIgnored => |*x| return x.name,
}
}
@@ -125,7 +140,7 @@ pub const Error = union(enum) {
name: TokenIndex,
pub fn render(self: *const ExpectedToken, tree: *Tree, stream: var) !void {
- return stream.print("must use '{}' tag to refer to type '{}'", .{tree.slice(kw), tree.slice(name)});
+ return stream.print("must use '{}' tag to refer to type '{}'", .{ tree.slice(kw), tree.slice(name) });
}
};
@@ -139,6 +154,18 @@ pub const Error = union(enum) {
}
};
}
+
+ fn SimpleError(comptime msg: []const u8) type {
+ return struct {
+ const ThisError = @This();
+
+ token: TokenIndex,
+
+ pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
+ return stream.write(msg);
+ }
+ };
+ }
};
pub const Type = struct {
@@ -194,9 +221,11 @@ pub const Node = struct {
CompoundStmt,
IfStmt,
StaticAssert,
- Fn,
+ Declarator,
+ Pointer,
+ FnDecl,
Typedef,
- Var,
+ VarDecl,
};
pub const Root = struct {
@@ -457,7 +486,7 @@ pub const Node = struct {
pub const Declarator = struct {
base: Node = Node{ .id = .Declarator },
- pointer: *Pointer,
+ pointer: ?*Pointer,
prefix: union(enum) {
None,
Identifer: TokenIndex,
@@ -482,7 +511,7 @@ pub const Node = struct {
};
pub const Array = struct {
- rbracket: TokenIndex,
+ lbracket: TokenIndex,
inner: union(enum) {
Inferred,
Unspecified: TokenIndex,
@@ -490,7 +519,7 @@ pub const Node = struct {
asterisk: ?TokenIndex,
static: ?TokenIndex,
qual: TypeQual,
- expr: *Expr,
+ // expr: *Expr,
},
},
rbracket: TokenIndex,
@@ -514,10 +543,10 @@ pub const Node = struct {
},
};
- pub const Fn = struct {
- base: Node = Node{ .id = .Fn },
+ pub const FnDecl = struct {
+ base: Node = Node{ .id = .FnDecl },
decl_spec: DeclSpec,
- declarator: *Node,
+ declarator: *Declarator,
old_decls: OldDeclList,
body: ?*CompoundStmt,
@@ -528,20 +557,23 @@ pub const Node = struct {
base: Node = Node{ .id = .Typedef },
decl_spec: DeclSpec,
declarators: DeclaratorList,
+ semicolon: TokenIndex,
pub const DeclaratorList = Root.DeclList;
};
- pub const Var = struct {
- base: Node = Node{ .id = .Var },
+ pub const VarDecl = struct {
+ base: Node = Node{ .id = .VarDecl },
decl_spec: DeclSpec,
initializers: Initializers,
+ semicolon: TokenIndex,
- pub const Initializers = std.SegmentedList(*Initialized, 2);
+ pub const Initializers = Root.DeclList;
};
pub const Initialized = struct {
- declarator: *Node,
+ base: Node = Node{ .id = Initialized },
+ declarator: *Declarator,
eq: TokenIndex,
init: Initializer,
};
lib/std/c/parse.zig
@@ -105,6 +105,10 @@ const Parser = struct {
return null;
}
+ fn declareSymbol(parser: *Parser, decl_spec: *Node.DeclSpec, dr: *Node.Declarator) Error!void {
+ return; // TODO
+ }
+
/// Root <- ExternalDeclaration* eof
fn root(parser: *Parser) Allocator.Error!*Node.Root {
const node = try parser.arena.create(Node.Root);
@@ -140,77 +144,127 @@ const Parser = struct {
fn declarationExtra(parser: *Parser, local: bool) !?*Node {
if (try parser.staticAssert()) |decl| return decl;
+ const begin = parser.it.index + 1;
var ds = Node.DeclSpec{};
const got_ds = try parser.declSpec(&ds);
if (local and !got_ds) {
// not a declaration
return null;
}
- var dr = try parser.declarator();
- // TODO disallow auto and register
- const next_tok = parser.it.peek().?;
- if (next_tok.id == .Eof and !got_ds and dr == null) {
- return null;
- }
- switch (next_tok.id) {
- .Semicolon,
- .Equal,
- .Comma,
- .Eof,
- => {
- while (dr != null) {
- if (parser.eatToken(.Equal)) |tok| {
- // TODO typedef
- // dr.?.init = try parser.expect(initializer, .{
- // .ExpectedInitializer = .{ .token = parser.it.index },
- // });
- }
- if (parser.eatToken(.Comma) != null) break;
- dr = (try parser.declarator()) orelse return parser.err(.{
+ switch (ds.storage_class) {
+ .Auto, .Register => |tok| return parser.err(.{
+ .InvalidStorageClass = .{ .token = tok },
+ }),
+ .Typedef => {
+ const node = try parser.arena.create(Node.Typedef);
+ node.* = .{
+ .decl_spec = ds,
+ .declarators = Node.Typedef.DeclaratorList.init(parser.arena),
+ .semicolon = undefined,
+ };
+ while (true) {
+ const dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{
.ExpectedDeclarator = .{ .token = parser.it.index },
- });
- // .push(dr);
+ }));
+ try parser.declareSymbol(&ds, dr);
+ try node.declarators.push(&dr.base);
+ if (parser.eatToken(.Comma)) |_| {} else break;
}
- const semicolon = try parser.expectToken(.Semicolon);
-
- // TODO VarDecl, TypeDecl, TypeDef
- return null;
+ return &node.base;
},
- else => {
- if (dr == null)
- return parser.err(.{
- .ExpectedDeclarator = .{ .token = parser.it.index },
- });
- var old_decls = Node.FnDef.OldDeclList.init(parser.arena);
- while (true) {
- var old_ds = Node.DeclSpec{};
- if (!(try parser.declSpec(&old_ds))) {
- // not old decl
- break;
- }
- var old_dr = (try parser.declarator());
- // if (old_dr == null)
- // try parser.err(.{
- // .NoParamName = .{ .token = parser.it.index },
- // });
- // try old_decls.push(decl);
- }
- const body = (try parser.compoundStmt()) orelse return parser.err(.{
+ else => {},
+ }
+ var first_dr = try parser.declarator(.Must);
+ if (first_dr != null and declaratorIsFunction(first_dr.?)) {
+ const dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?);
+ try parser.declareSymbol(&ds, dr);
+ var old_decls = Node.FnDecl.OldDeclList.init(parser.arena);
+ const body = if (parser.eatToken(.Semicolon)) |_|
+ null
+ else blk: {
+ // TODO first_dr.is_old
+ // while (true) {
+ // var old_ds = Node.DeclSpec{};
+ // if (!(try parser.declSpec(&old_ds))) {
+ // // not old decl
+ // break;
+ // }
+ // var old_dr = (try parser.declarator(.Must));
+ // // if (old_dr == null)
+ // // try parser.err(.{
+ // // .NoParamName = .{ .token = parser.it.index },
+ // // });
+ // // try old_decls.push(decl);
+ // }
+ const body_node = (try parser.compoundStmt()) orelse return parser.err(.{
.ExpectedFnBody = .{ .token = parser.it.index },
});
+ break :blk @fieldParentPtr(Node.CompoundStmt, "base", body_node);
+ };
- const node = try parser.arena.create(Node.FnDef);
- node.* = .{
- .decl_spec = ds,
- .declarator = dr orelse return null,
- .old_decls = old_decls,
- .body = @fieldParentPtr(Node.CompoundStmt, "base", body),
+ const node = try parser.arena.create(Node.FnDecl);
+ node.* = .{
+ .decl_spec = ds,
+ .declarator = dr,
+ .old_decls = old_decls,
+ .body = body,
+ };
+ return &node.base;
+ } else {
+ switch (ds.fn_spec) {
+ .Inline, .Noreturn => |tok| return parser.err(.{
+ .FnSpecOnNonFn = .{ .token = tok },
+ }),
+ else => {},
+ }
+ // TODO threadlocal without static or extern on local variable
+ const node = try parser.arena.create(Node.VarDecl);
+ node.* = .{
+ .decl_spec = ds,
+ .initializers = Node.VarDecl.Initializers.init(parser.arena),
+ .semicolon = undefined,
+ };
+ if (first_dr == null) {
+ node.semicolon = try parser.expectToken(.Semicolon);
+ const ok = switch (ds.type_spec.spec) {
+ .Enum => |e| e.name != null,
+ .Record => |r| r.name != null,
+ else => false,
};
+ const q = ds.type_spec.qual;
+ if (!ok)
+ try parser.warn(.{
+ .NothingDeclared = .{ .token = begin },
+ })
+ else if (q.@"const" orelse q.atomic orelse q.@"volatile" orelse q.restrict) |tok|
+ try parser.warn(.{
+ .QualifierIgnored = .{ .token = tok },
+ });
return &node.base;
- },
+ }
+ var dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?);
+ while (true) {
+ try parser.declareSymbol(&ds, dr);
+ if (parser.eatToken(.Equal)) |tok| {
+ try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{
+ .ExpectedInitializer = .{ .token = parser.it.index },
+ }));
+ } else
+ try node.initializers.push(&dr.base);
+ if (parser.eatToken(.Comma) != null) break;
+ dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{
+ .ExpectedDeclarator = .{ .token = parser.it.index },
+ }));
+ }
+ node.semicolon = try parser.expectToken(.Semicolon);
+ return &node.base;
}
}
+ fn declaratorIsFunction(dr: *Node) bool {
+ return false; // TODO
+ }
+
/// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON
fn staticAssert(parser: *Parser) !?*Node {
const tok = parser.eatToken(.Keyword_static_assert) orelse return null;
@@ -733,7 +787,7 @@ const Parser = struct {
fn recordDeclarator(parser: *Parser) !*Node {}
/// Pointer <- ASTERISK TypeQual* Pointer?
- fn pointer(parser: *Parser) Error!?*Node {
+ fn pointer(parser: *Parser) Error!?*Node.Pointer {
const asterisk = parser.eatToken(.Asterisk) orelse return null;
const node = try parser.arena.create(Node.Pointer);
node.* = .{
@@ -743,7 +797,7 @@ const Parser = struct {
};
while (try parser.typeQual(&node.qual)) {}
node.pointer = try parser.pointer();
- return &node.base;
+ return node;
}
const Named = enum {
@@ -772,7 +826,7 @@ const Parser = struct {
node.* = .{
.pointer = ptr,
.prefix = .{
- .Comples = .{
+ .Complex = .{
.lparen = lparen,
.inner = inner,
.rparen = try parser.expectToken(.RParen),
@@ -785,7 +839,7 @@ const Parser = struct {
node = try parser.arena.create(Node.Declarator);
node.* = .{
.pointer = ptr,
- .prefix = .{ .Simple = tok },
+ .prefix = .{ .Identifer = tok },
.suffix = .None,
};
} else if (named == .Must) {
@@ -793,7 +847,9 @@ const Parser = struct {
.ExpectedToken = .{ .token = parser.it.index, .expected_id = .Identifier },
});
} else {
- return ptr;
+ if (ptr) |some|
+ return &some.base;
+ return null;
}
} else {
node = try parser.arena.create(Node.Declarator);
@@ -808,16 +864,16 @@ const Parser = struct {
node.suffix = .{
.Fn = .{
.lparen = lparen,
- .params = .Node.Declarator.Params.init(parser.arena),
+ .params = Node.Declarator.Params.init(parser.arena),
.rparen = undefined,
},
};
- try parser.ParamDecl(node);
+ try parser.paramDecl(node);
node.suffix.Fn.rparen = try parser.expectToken(.RParen);
} else {
- while (parser.arrayDeclarator()) |arr| {
+ while (try parser.arrayDeclarator()) |arr| {
if (node.suffix == .None)
- node.suffix = .{ .Array = .Node.Declarator.Arrays.init(parser.arena) };
+ node.suffix = .{ .Array = Node.Declarator.Arrays.init(parser.arena) };
try node.suffix.Array.push(arr);
}
}
@@ -825,7 +881,7 @@ const Parser = struct {
return parser.err(.{
.InvalidDeclarator = .{ .token = tok },
});
- return node;
+ return &node.base;
}
/// ArrayDeclarator
@@ -834,11 +890,11 @@ const Parser = struct {
/// / TypeQual+ (ASTERISK / Keyword_static AssignmentExpr)
/// / TypeQual+ AssignmentExpr?
/// / AssignmentExpr
- fn arrayDeclarator(parser: *Parser, dr: *Node.Declarator) !?*Node.Array {
+ fn arrayDeclarator(parser: *Parser) !?*Node.Array {
const lbracket = parser.eatToken(.LBracket) orelse return null;
const arr = try parser.arena.create(Node.Array);
arr.* = .{
- .lbracket = lbarcket,
+ .lbracket = lbracket,
.inner = .Inferred,
.rbracket = undefined,
};
@@ -856,12 +912,12 @@ const Parser = struct {
fn paramDecl(parser: *Parser, dr: *Node.Declarator) !void {
var old_style = false;
while (true) {
- var ds = Node.DeclSpec;
+ var ds = Node.DeclSpec{};
if (try parser.declSpec(&ds)) {
//TODO
- } else if (parser.eatToken(.Identifier)) {
+ } else if (parser.eatToken(.Identifier)) |tok| {
old_style = true;
- } else if (parser.eatToken(.Ellipsis)) {
+ } else if (parser.eatToken(.Ellipsis)) |tok| {
// TODO
}
}