Commit 25f7f66b8f
lib/std/c/ast.zig
@@ -26,10 +26,12 @@ pub const Tree = struct {
};
pub const Error = union(enum) {
- InvalidToken: SingleTokenError("Invalid token '{}'"),
+ InvalidToken: SingleTokenError("invalid token '{}'"),
ExpectedToken: ExpectedToken,
- ExpectedExpr: SingleTokenError("Expected expression, found '{}'"),
- ExpectedStmt: SingleTokenError("Expected statement, found '{}'"),
+ ExpectedExpr: SingleTokenError("expected expression, found '{}'"),
+ ExpectedStmt: SingleTokenError("expected statement, found '{}'"),
+ InvalidTypeSpecifier: InvalidTypeSpecifier,
+ DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"),
pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
switch (self.*) {
@@ -37,6 +39,8 @@ pub const Error = union(enum) {
.ExpectedToken => |*x| return x.render(tokens, stream),
.ExpectedExpr => |*x| return x.render(tokens, stream),
.ExpectedStmt => |*x| return x.render(tokens, stream),
+ .InvalidTypeSpecifier => |*x| return x.render(tokens, stream),
+ .DuplicateQualifier => |*x| return x.render(tokens, stream),
}
}
@@ -46,6 +50,8 @@ pub const Error = union(enum) {
.ExpectedToken => |x| return x.token,
.ExpectedExpr => |x| return x.token,
.ExpectedStmt => |x| return x.token,
+ .InvalidTypeSpecifier => |x| return x.token,
+ .DuplicateQualifier => |x| return x.token,
}
}
@@ -64,6 +70,18 @@ pub const Error = union(enum) {
}
};
+ pub const InvalidTypeSpecifier = struct {
+ token: TokenIndex,
+ type: *Node.Type,
+
+ pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
+ try stream.write("invalid type specifier '");
+ try type.specifier.print(tokens, stream);
+ const token_name = tokens.at(self.token).id.symbol();
+ return stream.print("{}'", .{ token_name });
+ }
+ };
+
fn SingleTokenError(comptime msg: []const u8) type {
return struct {
token: TokenIndex,
@@ -96,6 +114,69 @@ pub const Node = struct {
pub const DeclList = SegmentedList(*Node, 4);
};
+ pub const Type = struct {
+ qualifiers: Qualifiers,
+ specifier: union(enum) {
+ /// error or default to int
+ None,
+ Void: TokenIndex,
+ Char: struct {
+ sign: ?TokenIndex = null,
+ char: TokenIndex,
+ },
+ Short: struct {
+ sign: ?TokenIndex = null,
+ short: TokenIndex = null,
+ int: ?TokenIndex = null,
+ },
+ Int: struct {
+ sign: ?TokenIndex = null,
+ int: ?TokenIndex = null,
+ },
+ Long: struct {
+ sign: ?TokenIndex = null,
+ long: TokenIndex,
+ longlong: ?TokenIndex = null,
+ int: ?TokenIndex = null,
+ },
+ Float: struct {
+ float: TokenIndex,
+ complex: ?TokenIndex = null,
+ },
+ Double: struct {
+ long: ?TokenIndex = null,
+ double: ?TokenIndex,
+ complex: ?TokenIndex = null,
+ },
+ Bool: TokenIndex,
+ Atomic: struct {
+ atomic: TokenIndex,
+ typename: *Node,
+ rparen: TokenIndex,
+ },
+
+ //todo
+ // @"enum",
+ // record,
+
+ Typedef: TokenIndex,
+
+ pub fn print(self: *@This(), self: *const @This(), tokens: *Tree.TokenList, stream: var) !void {
+ switch (self) {
+ .None => unreachable,
+ else => @panic("TODO print type specifier"),
+ }
+ }
+ },
+ };
+
+ pub const Qualifiers = struct {
+ @"const": ?TokenIndex = null,
+ atomic: ?TokenIndex = null,
+ @"volatile": ?TokenIndex = null,
+ restrict: ?TokenIndex = null,
+ };
+
pub const JumpStmt = struct {
base: Node = Node{ .id = .JumpStmt },
ltoken: TokenIndex,
lib/std/c/parse.zig
@@ -109,35 +109,284 @@ const Parser = struct {
fn staticAssertDeclaration(parser: *Parser) !?*Node {}
/// DeclarationSpecifiers
- /// <- StorageClassSpecifier DeclarationSpecifiers?
- /// / TypeSpecifier DeclarationSpecifiers?
- /// / TypeQualifier DeclarationSpecifiers?
- /// / FunctionSpecifier DeclarationSpecifiers?
- /// / AlignmentSpecifier DeclarationSpecifiers?
+ /// <- (Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register
+ /// / Type
+ /// / Keyword_inline / Keyword_noreturn
+ /// / Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN)*
fn declarationSpecifiers(parser: *Parser) !*Node {}
- /// StorageClassSpecifier
- /// <- Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register
- fn storageClassSpecifier(parser: *Parser) !*Node {}
-
- /// TypeSpecifier
+ /// Type
/// <- Keyword_void / Keyword_char / Keyword_short / Keyword_int / Keyword_long / Keyword_float / Keyword_double
/// / Keyword_signed / Keyword_unsigned / Keyword_bool / Keyword_complex / Keyword_imaginary /
/// / Keyword_atomic LPAREN TypeName RPAREN
/// / EnumSpecifier
/// / RecordSpecifier
/// / IDENTIFIER // typedef name
- fn typeSpecifier(parser: *Parser) !*Node {}
+ /// / TypeQualifier
+ fn type(parser: *Parser, type: *Node.Type) !bool {
+ while (try parser.typeQualifier(type.qualifiers)) {}
+ blk: {
+ if (parser.eatToken(.Keyword_void)) |tok| {
+ if (type.specifier != .None)
+ break :blk;
+ type.specifier = .{ .Void = tok };
+ return true;
+ } else if (parser.eatToken(.Keyword_char)) |tok| {
+ switch (type.specifier) {
+ .None => {
+ type.specifier = .{
+ .Char = .{
+ .char = tok,
+ },
+ };
+ },
+ .Int => |int| {
+ if (int.int != null)
+ break :blk;
+ type.specifier = .{
+ .Char = .{
+ .char = tok,
+ .sign = int.sign,
+ },
+ };
+ },
+ else => break :blk,
+ }
+ return true;
+ } else if (parser.eatToken(.Keyword_short)) |tok| {
+ switch (type.specifier) {
+ .None => {
+ type.specifier = .{
+ .Short = .{
+ .short = tok,
+ },
+ };
+ },
+ .Int => |int| {
+ if (int.int != null)
+ break :blk;
+ type.specifier = .{
+ .Short = .{
+ .short = tok,
+ .sign = int.sign,
+ },
+ };
+ },
+ else => break :blk,
+ }
+ return true;
+ } else if (parser.eatToken(.Keyword_long)) |tok| {
+ switch (type.specifier) {
+ .None => {
+ type.specifier = .{
+ .Long = .{
+ .long = tok,
+ },
+ };
+ },
+ .Int => |int| {
+ type.specifier = .{
+ .Long = .{
+ .long = tok,
+ .sign = int.sign,
+ .int = int.int,
+ },
+ };
+ },
+ .Long => |*long| {
+ if (long.longlong != null)
+ break :blk;
+ long.longlong = tok;
+ },
+ .Double => |*double| {
+ if (double.long != null)
+ break :blk;
+ double.long = tok;
+ },
+ else => break :blk,
+ }
+ return true;
+ } else if (parser.eatToken(.Keyword_int)) |tok| {
+ switch (type.specifier) {
+ .None => {
+ type.specifier = .{
+ .Int = .{
+ .int = tok,
+ },
+ };
+ },
+ .Short => |*short| {
+ if (short.int != null)
+ break :blk;
+ short.int = tok;
+ },
+ .Int => |*int| {
+ if (int.int != null)
+ break :blk;
+ int.int = tok;
+ },
+ .Long => |*long| {
+ if (long.int != null)
+ break :blk;
+ long.int = tok;
+ },
+ else => break :blk,
+ }
+ return true;
+ } else if (parser.eatToken(.Keyword_signed) orelse parser.eatToken(.Keyword_unsigned)) |tok| {
+ switch (type.specifier) {
+ .None => {
+ type.specifier = .{
+ .Int = .{
+ .sign = tok,
+ },
+ };
+ },
+ .Char => |*char| {
+ if (char.sign != null)
+ break :blk;
+ char.sign = tok;
+ },
+ .Short => |*short| {
+ if (short.sign != null)
+ break :blk;
+ short.sign = tok;
+ },
+ .Int => |*int| {
+ if (int.sign != null)
+ break :blk;
+ int.sign = tok;
+ },
+ .Long => |*long| {
+ if (long.sign != null)
+ break :blk;
+ long.sign = tok;
+ },
+ else => break :blk,
+ }
+ return true;
+ } else if (parser.eatToken(.Keyword_float)) |tok| {
+ if (type.specifier != .None)
+ break :blk;
+ type.specifier = .{
+ .Float = .{
+ .float = tok,
+ },
+ };
+ return true;
+ } else if (parser.eatToken(.Keyword_double)) |tok| {
+ if (type.specifier != .None)
+ break :blk;
+ type.specifier = .{
+ .Double = .{
+ .double = tok,
+ },
+ };
+ return true;
+ } else if (parser.eatToken(.Keyword_complex)) |tok| {
+ switch (type.specifier) {
+ .None => {
+ type.specifier = .{
+ .Double = .{
+ .complex = tok,
+ .double = null
+ },
+ };
+ },
+ .Float => |*float| {
+ if (float.complex != null)
+ break :blk;
+ float.complex = tok;
+ },
+ .Double => |*double| {
+ if (double.complex != null)
+ break :blk;
+ double.complex = tok;
+ },
+ else => break :blk,
+ }
+ return true;
+ } if (parser.eatToken(.Keyword_bool)) |tok| {
+ if (type.specifier != .None)
+ break :blk;
+ type.specifier = .{ .Bool = tok };
+ return true;
+ } else if (parser.eatToken(.Keyword_atomic)) |tok| {
+ if (type.specifier != .None)
+ break :blk;
+ _ = try parser.expectToken(.LParen);
+ const name = try parser.expect(typeName, .{
+ .ExpectedTypeName = .{ .tok = it.index },
+ });
+ type.specifier.Atomic = .{
+ .atomic = tok,
+ .typename = name,
+ .rparen = try parser.expectToken(.RParen),
+ };
+ return true;
+ } else if (parser.eatToken(.Keyword_enum)) |tok| {
+ if (type.specifier != .None)
+ break :blk;
+ @panic("TODO enum type");
+ // return true;
+ } else if (parser.eatToken(.Keyword_union) orelse parser.eatToken(.Keyword_struct)) |tok| {
+ if (type.specifier != .None)
+ break :blk;
+ @panic("TODO record type");
+ // return true;
+ } else if (parser.eatToken(.Identifier)) |tok| {
+ if (!parser.typedefs.contains(tok)) {
+ parser.putBackToken(tok);
+ return false;
+ }
+ type.specifier = .{
+ .Typedef = tok,
+ };
+ return true;
+ }
+ }
+ try parser.tree.errors.push(.{
+ .InvalidTypeSpecifier = .{
+ .token = parser.it.index,
+ .type = type,
+ },
+ });
+ return error.ParseError;
+ }
/// TypeQualifier <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic
- fn typeQualifier(parser: *Parser) !*Node {}
+ fn typeQualifier(parser: *Parser, qualifiers: *Node.Qualifiers) !bool {
+ if (parser.eatToken(.Keyword_const)) |tok| {
+ if (qualifiers.@"const" != null)
+ return parser.warning(.{
+ .DuplicateQualifier = .{ .token = tok },
+ });
+ qualifiers.@"const" = tok;
+ } else if (parser.eatToken(.Keyword_restrict)) |tok| {
+ if (qualifiers.atomic != null)
+ return parser.warning(.{
+ .DuplicateQualifier = .{ .token = tok },
+ });
+ qualifiers.atomic = tok;
+ } else if (parser.eatToken(.Keyword_volatile)) |tok| {
+ if (qualifiers.@"volatile" != null)
+ return parser.warning(.{
+ .DuplicateQualifier = .{ .token = tok },
+ });
+ qualifiers.@"volatile" = tok;
+ } else if (parser.eatToken(.Keyword_atomic)) |tok| {
+ if (qualifiers.atomic != null)
+ return parser.warning(.{
+ .DuplicateQualifier = .{ .token = tok },
+ });
+ qualifiers.atomic = tok;
+ } else return false;
+ return true;
+ }
/// FunctionSpecifier <- Keyword_inline / Keyword_noreturn
fn functionSpecifier(parser: *Parser) !*Node {}
- /// AlignmentSpecifier <- Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN
- fn alignmentSpecifier(parser: *Parser) !*Node {}
-
/// EnumSpecifier <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)?
fn enumSpecifier(parser: *Parser) !*Node {}
@@ -148,19 +397,14 @@ const Parser = struct {
fn recordSpecifier(parser: *Parser) !*Node {}
/// RecordField
- /// <- SpecifierQualifer (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON
+ /// <- Type* (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON
/// \ StaticAssertDeclaration
fn recordField(parser: *Parser) !*Node {}
/// TypeName
- /// <- SpecifierQualifer AbstractDeclarator?
+ /// <- Type* AbstractDeclarator?
fn typeName(parser: *Parser) !*Node {}
- /// SpecifierQualifer
- /// <- TypeSpecifier SpecifierQualifer?
- /// / TypeQualifier SpecifierQualifer?
- fn specifierQualifer(parser: *Parser) !*Node {}
-
/// RecordDeclarator <- Declarator? (COLON ConstExpr)?
fn recordDeclarator(parser: *Parser) !*Node {}
@@ -329,7 +573,7 @@ const Parser = struct {
if (parser.eatToken(.Keyword_else)) |else_tok| {
node.@"else" = .{
.tok = else_tok,
- .stmt = try parser.stmt(expr, .{
+ .stmt = try parser.stmt(expr, .{
.ExpectedStmt = .{ .token = it.index },
}),
};
@@ -431,11 +675,11 @@ const Parser = struct {
}
}
- fn putBackToken(it: *TokenIterator, putting_back: TokenIndex) void {
+ fn putBackToken(parser: *Parser, putting_back: TokenIndex) void {
while (true) {
- const prev_tok = it.prev() orelse return;
+ const prev_tok = parser.it.prev() orelse return;
if (next_tok.id == .LineComment or next_tok.id == .MultiLineComment) continue;
- assert(it.list.at(putting_back) == prev_tok);
+ assert(parser.it.list.at(putting_back) == prev_tok);
return;
}
}
@@ -450,4 +694,10 @@ const Parser = struct {
return error.ParseError;
};
}
+
+ fn warning(parser: *Parser, err: ast.Error) Error {
+ // if (parser.warnaserror)
+ try parser.tree.errors.push(err);
+ return error.ParseError;
+ }
};