Merge pull request #3908 from Vexu/translate-c-2

Translate-c-2 enums
This commit is contained in:
Andrew Kelley 2019-12-14 21:13:42 -05:00 committed by GitHub
commit cf0d300dde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 482 additions and 252 deletions

View File

@ -581,7 +581,7 @@ pub const Node = struct {
}
pub const Root = struct {
base: Node,
base: Node = Node {.id = .Root},
decls: DeclList,
eof_token: TokenIndex,
@ -604,7 +604,7 @@ pub const Node = struct {
};
pub const VarDecl = struct {
base: Node,
base: Node = Node {.id = .VarDecl},
doc_comments: ?*DocComment,
visib_token: ?TokenIndex,
thread_local_token: ?TokenIndex,
@ -661,7 +661,7 @@ pub const Node = struct {
};
pub const Use = struct {
base: Node,
base: Node = Node {.id = .Use},
doc_comments: ?*DocComment,
visib_token: ?TokenIndex,
use_token: TokenIndex,
@ -688,7 +688,7 @@ pub const Node = struct {
};
pub const ErrorSetDecl = struct {
base: Node,
base: Node = Node {.id = .ErrorSetDecl},
error_token: TokenIndex,
decls: DeclList,
rbrace_token: TokenIndex,
@ -714,7 +714,7 @@ pub const Node = struct {
};
pub const ContainerDecl = struct {
base: Node,
base: Node = Node {.id = .ContainerDecl},
layout_token: ?TokenIndex,
kind_token: TokenIndex,
init_arg_expr: InitArg,
@ -801,7 +801,7 @@ pub const Node = struct {
};
pub const ErrorTag = struct {
base: Node,
base: Node = Node {.id = .ErrorTag},
doc_comments: ?*DocComment,
name_token: TokenIndex,
@ -826,7 +826,7 @@ pub const Node = struct {
};
pub const Identifier = struct {
base: Node,
base: Node = Node {.id = .Identifier},
token: TokenIndex,
pub fn iterate(self: *Identifier, index: usize) ?*Node {
@ -843,7 +843,7 @@ pub const Node = struct {
};
pub const FnProto = struct {
base: Node,
base: Node = Node {.id = .FnProto},
doc_comments: ?*DocComment,
visib_token: ?TokenIndex,
fn_token: TokenIndex,
@ -925,7 +925,7 @@ pub const Node = struct {
};
pub const AnyFrameType = struct {
base: Node,
base: Node = Node {.id = .AnyFrameType},
anyframe_token: TokenIndex,
result: ?Result,
@ -956,7 +956,7 @@ pub const Node = struct {
};
pub const ParamDecl = struct {
base: Node,
base: Node = Node {.id = .ParamDecl},
doc_comments: ?*DocComment,
comptime_token: ?TokenIndex,
noalias_token: ?TokenIndex,
@ -989,7 +989,7 @@ pub const Node = struct {
};
pub const Block = struct {
base: Node,
base: Node = Node {.id = .Block},
label: ?TokenIndex,
lbrace: TokenIndex,
statements: StatementList,
@ -1020,7 +1020,7 @@ pub const Node = struct {
};
pub const Defer = struct {
base: Node,
base: Node = Node {.id = .Defer},
defer_token: TokenIndex,
expr: *Node,
@ -1043,7 +1043,7 @@ pub const Node = struct {
};
pub const Comptime = struct {
base: Node,
base: Node = Node {.id = .Comptime},
doc_comments: ?*DocComment,
comptime_token: TokenIndex,
expr: *Node,
@ -1067,7 +1067,7 @@ pub const Node = struct {
};
pub const Payload = struct {
base: Node,
base: Node = Node {.id = .Payload},
lpipe: TokenIndex,
error_symbol: *Node,
rpipe: TokenIndex,
@ -1091,7 +1091,7 @@ pub const Node = struct {
};
pub const PointerPayload = struct {
base: Node,
base: Node = Node {.id = .PointerPayload},
lpipe: TokenIndex,
ptr_token: ?TokenIndex,
value_symbol: *Node,
@ -1116,7 +1116,7 @@ pub const Node = struct {
};
pub const PointerIndexPayload = struct {
base: Node,
base: Node = Node {.id = .PointerIndexPayload},
lpipe: TokenIndex,
ptr_token: ?TokenIndex,
value_symbol: *Node,
@ -1147,7 +1147,7 @@ pub const Node = struct {
};
pub const Else = struct {
base: Node,
base: Node = Node {.id = .Else},
else_token: TokenIndex,
payload: ?*Node,
body: *Node,
@ -1176,7 +1176,7 @@ pub const Node = struct {
};
pub const Switch = struct {
base: Node,
base: Node = Node {.id = .Switch},
switch_token: TokenIndex,
expr: *Node,
@ -1208,7 +1208,7 @@ pub const Node = struct {
};
pub const SwitchCase = struct {
base: Node,
base: Node = Node {.id = .SwitchCase},
items: ItemList,
arrow_token: TokenIndex,
payload: ?*Node,
@ -1243,7 +1243,7 @@ pub const Node = struct {
};
pub const SwitchElse = struct {
base: Node,
base: Node = Node {.id = .SwitchElse},
token: TokenIndex,
pub fn iterate(self: *SwitchElse, index: usize) ?*Node {
@ -1260,7 +1260,7 @@ pub const Node = struct {
};
pub const While = struct {
base: Node,
base: Node = Node {.id = .While},
label: ?TokenIndex,
inline_token: ?TokenIndex,
while_token: TokenIndex,
@ -1319,7 +1319,7 @@ pub const Node = struct {
};
pub const For = struct {
base: Node,
base: Node = Node {.id = .For},
label: ?TokenIndex,
inline_token: ?TokenIndex,
for_token: TokenIndex,
@ -1370,7 +1370,7 @@ pub const Node = struct {
};
pub const If = struct {
base: Node,
base: Node = Node {.id = .If},
if_token: TokenIndex,
condition: *Node,
payload: ?*Node,
@ -1413,7 +1413,7 @@ pub const Node = struct {
};
pub const InfixOp = struct {
base: Node,
base: Node = Node {.id = .InfixOp},
op_token: TokenIndex,
lhs: *Node,
op: Op,
@ -1646,7 +1646,7 @@ pub const Node = struct {
};
pub const FieldInitializer = struct {
base: Node,
base: Node = Node {.id = .FieldInitializer},
period_token: TokenIndex,
name_token: TokenIndex,
expr: *Node,
@ -1670,7 +1670,7 @@ pub const Node = struct {
};
pub const SuffixOp = struct {
base: Node,
base: Node = Node {.id = .SuffixOp},
lhs: Lhs,
op: Op,
rtoken: TokenIndex,
@ -1766,7 +1766,7 @@ pub const Node = struct {
};
pub const GroupedExpression = struct {
base: Node,
base: Node = Node {.id = .GroupedExpression},
lparen: TokenIndex,
expr: *Node,
rparen: TokenIndex,
@ -1790,7 +1790,7 @@ pub const Node = struct {
};
pub const ControlFlowExpression = struct {
base: Node,
base: Node = Node {.id = .ControlFlowExpression},
ltoken: TokenIndex,
kind: Kind,
rhs: ?*Node,
@ -1856,7 +1856,7 @@ pub const Node = struct {
};
pub const Suspend = struct {
base: Node,
base: Node = Node {.id = .Suspend},
suspend_token: TokenIndex,
body: ?*Node,
@ -1885,7 +1885,7 @@ pub const Node = struct {
};
pub const IntegerLiteral = struct {
base: Node,
base: Node = Node {.id = .IntegerLiteral},
token: TokenIndex,
pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node {
@ -1902,7 +1902,7 @@ pub const Node = struct {
};
pub const EnumLiteral = struct {
base: Node,
base: Node = Node {.id = .EnumLiteral},
dot: TokenIndex,
name: TokenIndex,
@ -1920,7 +1920,7 @@ pub const Node = struct {
};
pub const FloatLiteral = struct {
base: Node,
base: Node = Node {.id = .FloatLiteral},
token: TokenIndex,
pub fn iterate(self: *FloatLiteral, index: usize) ?*Node {
@ -1937,7 +1937,7 @@ pub const Node = struct {
};
pub const BuiltinCall = struct {
base: Node,
base: Node = Node {.id = .BuiltinCall},
builtin_token: TokenIndex,
params: ParamList,
rparen_token: TokenIndex,
@ -1963,7 +1963,7 @@ pub const Node = struct {
};
pub const StringLiteral = struct {
base: Node,
base: Node = Node {.id = .StringLiteral},
token: TokenIndex,
pub fn iterate(self: *StringLiteral, index: usize) ?*Node {
@ -1980,7 +1980,7 @@ pub const Node = struct {
};
pub const MultilineStringLiteral = struct {
base: Node,
base: Node = Node {.id = .MultilineStringLiteral},
lines: LineList,
pub const LineList = SegmentedList(TokenIndex, 4);
@ -1999,7 +1999,7 @@ pub const Node = struct {
};
pub const CharLiteral = struct {
base: Node,
base: Node = Node {.id = .CharLiteral},
token: TokenIndex,
pub fn iterate(self: *CharLiteral, index: usize) ?*Node {
@ -2016,7 +2016,7 @@ pub const Node = struct {
};
pub const BoolLiteral = struct {
base: Node,
base: Node = Node {.id = .BoolLiteral},
token: TokenIndex,
pub fn iterate(self: *BoolLiteral, index: usize) ?*Node {
@ -2033,7 +2033,7 @@ pub const Node = struct {
};
pub const NullLiteral = struct {
base: Node,
base: Node = Node {.id = .NullLiteral},
token: TokenIndex,
pub fn iterate(self: *NullLiteral, index: usize) ?*Node {
@ -2050,7 +2050,7 @@ pub const Node = struct {
};
pub const UndefinedLiteral = struct {
base: Node,
base: Node = Node {.id = .UndefinedLiteral},
token: TokenIndex,
pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node {
@ -2067,7 +2067,7 @@ pub const Node = struct {
};
pub const AsmOutput = struct {
base: Node,
base: Node = Node {.id = .AsmOutput},
lbracket: TokenIndex,
symbolic_name: *Node,
constraint: *Node,
@ -2112,7 +2112,7 @@ pub const Node = struct {
};
pub const AsmInput = struct {
base: Node,
base: Node = Node {.id = .AsmInput},
lbracket: TokenIndex,
symbolic_name: *Node,
constraint: *Node,
@ -2144,7 +2144,7 @@ pub const Node = struct {
};
pub const Asm = struct {
base: Node,
base: Node = Node {.id = .Asm},
asm_token: TokenIndex,
volatile_token: ?TokenIndex,
template: *Node,
@ -2179,7 +2179,7 @@ pub const Node = struct {
};
pub const Unreachable = struct {
base: Node,
base: Node = Node {.id = .Unreachable},
token: TokenIndex,
pub fn iterate(self: *Unreachable, index: usize) ?*Node {
@ -2196,7 +2196,7 @@ pub const Node = struct {
};
pub const ErrorType = struct {
base: Node,
base: Node = Node {.id = .ErrorType},
token: TokenIndex,
pub fn iterate(self: *ErrorType, index: usize) ?*Node {
@ -2230,7 +2230,7 @@ pub const Node = struct {
};
pub const DocComment = struct {
base: Node,
base: Node = Node {.id = .DocComment},
lines: LineList,
pub const LineList = SegmentedList(TokenIndex, 4);
@ -2249,7 +2249,7 @@ pub const Node = struct {
};
pub const TestDecl = struct {
base: Node,
base: Node = Node {.id = .TestDecl},
doc_comments: ?*DocComment,
test_token: TokenIndex,
name: *Node,

View File

@ -56,7 +56,6 @@ pub fn parse(allocator: *Allocator, source: []const u8) !*Tree {
fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {
const node = try arena.create(Node.Root);
node.* = Node.Root{
.base = Node{ .id = .Root },
.decls = undefined,
.eof_token = undefined,
};
@ -176,7 +175,6 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree)
const node = try arena.create(Node.DocComment);
node.* = Node.DocComment{
.base = Node{ .id = .DocComment },
.lines = lines,
};
return &node.base;
@ -194,7 +192,6 @@ fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const test_node = try arena.create(Node.TestDecl);
test_node.* = Node.TestDecl{
.base = Node{ .id = .TestDecl },
.doc_comments = null,
.test_token = test_token,
.name = name_node,
@ -217,7 +214,6 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*
const comptime_node = try arena.create(Node.Comptime);
comptime_node.* = Node.Comptime{
.base = Node{ .id = .Comptime },
.doc_comments = null,
.comptime_token = tok,
.expr = block_node,
@ -338,7 +334,6 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const fn_proto_node = try arena.create(Node.FnProto);
fn_proto_node.* = Node.FnProto{
.base = Node{ .id = .FnProto },
.doc_comments = null,
.visib_token = null,
.fn_token = fn_token,
@ -389,7 +384,6 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.VarDecl);
node.* = Node.VarDecl{
.base = Node{ .id = .VarDecl },
.doc_comments = null,
.visib_token = null,
.thread_local_token = null,
@ -477,7 +471,6 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
const node = try arena.create(Node.Comptime);
node.* = Node.Comptime{
.base = Node{ .id = .Comptime },
.doc_comments = null,
.comptime_token = token,
.expr = block_expr,
@ -496,7 +489,6 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
const node = try arena.create(Node.Suspend);
node.* = Node.Suspend{
.base = Node{ .id = .Suspend },
.suspend_token = suspend_token,
.body = body_node,
};
@ -510,7 +502,6 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
});
const node = try arena.create(Node.Defer);
node.* = Node.Defer{
.base = Node{ .id = .Defer },
.defer_token = token,
.expr = expr_node,
};
@ -558,7 +549,6 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const node = try arena.create(Node.Else);
node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = payload,
.body = else_body,
@ -652,7 +642,6 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = null,
.body = statement_node,
@ -677,7 +666,6 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = null,
.body = statement_node,
@ -714,7 +702,6 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = payload,
.body = statement_node,
@ -741,7 +728,6 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = payload,
.body = statement_node,
@ -870,7 +856,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const expr_node = try parseExpr(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
node.* = Node.ControlFlowExpression{
.base = Node{ .id = .ControlFlowExpression },
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind{ .Break = label },
.rhs = expr_node,
@ -884,7 +869,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
});
const node = try arena.create(Node.Comptime);
node.* = Node.Comptime{
.base = Node{ .id = .Comptime },
.doc_comments = null,
.comptime_token = token,
.expr = expr_node,
@ -896,7 +880,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const label = try parseBreakLabel(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
node.* = Node.ControlFlowExpression{
.base = Node{ .id = .ControlFlowExpression },
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind{ .Continue = label },
.rhs = null,
@ -910,7 +893,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
});
const node = try arena.create(Node.PrefixOp);
node.* = Node.PrefixOp{
.base = Node{ .id = .PrefixOp },
.op_token = token,
.op = Node.PrefixOp.Op.Resume,
.rhs = expr_node,
@ -922,7 +904,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const expr_node = try parseExpr(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
node.* = Node.ControlFlowExpression{
.base = Node{ .id = .ControlFlowExpression },
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind.Return,
.rhs = expr_node,
@ -970,7 +951,6 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const block_node = try arena.create(Node.Block);
block_node.* = Node.Block{
.base = Node{ .id = .Block },
.label = null,
.lbrace = lbrace,
.statements = statements,
@ -1020,7 +1000,6 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = null,
.body = body,
@ -1050,7 +1029,6 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = payload,
.body = body,
@ -1102,7 +1080,6 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf
const node = try arena.create(Node.SuffixOp);
node.* = Node.SuffixOp{
.base = Node{ .id = .SuffixOp },
.lhs = .{ .node = undefined }, // set by caller
.op = op,
.rtoken = try expectToken(it, tree, .RBrace),
@ -1171,7 +1148,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
};
const node = try arena.create(Node.SuffixOp);
node.* = Node.SuffixOp{
.base = Node{ .id = .SuffixOp },
.lhs = .{ .node = res },
.op = Node.SuffixOp.Op{
.Call = Node.SuffixOp.Op.Call{
@ -1199,7 +1175,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
if (try parseFnCallArguments(arena, it, tree)) |params| {
const call = try arena.create(Node.SuffixOp);
call.* = Node.SuffixOp{
.base = Node{ .id = .SuffixOp },
.lhs = .{ .node = res },
.op = Node.SuffixOp.Op{
.Call = Node.SuffixOp.Op.Call{
@ -1248,7 +1223,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
if (eatToken(it, .CharLiteral)) |token| {
const node = try arena.create(Node.CharLiteral);
node.* = Node.CharLiteral{
.base = Node{ .id = .CharLiteral },
.token = token,
};
return &node.base;
@ -1267,7 +1241,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
const node = try arena.create(Node.Comptime);
node.* = Node.Comptime{
.base = Node{ .id = .Comptime },
.doc_comments = null,
.comptime_token = token,
.expr = expr,
@ -1282,7 +1255,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
const global_error_set = try createLiteral(arena, Node.ErrorType, token);
const node = try arena.create(Node.InfixOp);
node.* = Node.InfixOp{
.base = Node{ .id = .InfixOp },
.op_token = period,
.lhs = global_error_set,
.op = Node.InfixOp.Op.Period,
@ -1295,7 +1267,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
if (eatToken(it, .Keyword_anyframe)) |token| {
const node = try arena.create(Node.AnyFrameType);
node.* = Node.AnyFrameType{
.base = Node{ .id = .AnyFrameType },
.anyframe_token = token,
.result = null,
};
@ -1337,7 +1308,6 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const node = try arena.create(Node.ErrorSetDecl);
node.* = Node.ErrorSetDecl{
.base = Node{ .id = .ErrorSetDecl },
.error_token = error_token,
.decls = decls,
.rbrace_token = rbrace,
@ -1355,7 +1325,6 @@ fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const node = try arena.create(Node.GroupedExpression);
node.* = Node.GroupedExpression{
.base = Node{ .id = .GroupedExpression },
.lparen = lparen,
.expr = expr,
.rparen = rparen,
@ -1438,7 +1407,6 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = null,
.body = else_expr,
@ -1469,7 +1437,6 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = null,
.body = else_expr,
@ -1495,7 +1462,6 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.Switch);
node.* = Node.Switch{
.base = Node{ .id = .Switch },
.switch_token = switch_token,
.expr = expr_node,
.cases = cases,
@ -1515,7 +1481,6 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.Asm);
node.* = Node.Asm{
.base = Node{ .id = .Asm },
.asm_token = asm_token,
.volatile_token = volatile_token,
.template = template,
@ -1538,7 +1503,6 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
if (eatToken(it, .Identifier)) |name| {
const node = try arena.create(Node.EnumLiteral);
node.* = Node.EnumLiteral{
.base = Node{ .id = .EnumLiteral },
.dot = dot,
.name = name,
};
@ -1591,7 +1555,6 @@ fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
const node = try arena.create(Node.AsmOutput);
node.* = Node.AsmOutput{
.base = Node{ .id = .AsmOutput },
.lbracket = lbracket,
.symbolic_name = name,
.constraint = constraint,
@ -1628,7 +1591,6 @@ fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const node = try arena.create(Node.AsmInput);
node.* = Node.AsmInput{
.base = Node{ .id = .AsmInput },
.lbracket = lbracket,
.symbolic_name = name,
.constraint = constraint,
@ -1687,7 +1649,6 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.FieldInitializer);
node.* = Node.FieldInitializer{
.base = Node{ .id = .FieldInitializer },
.period_token = period_token,
.name_token = name_token,
.expr = expr_node,
@ -1760,7 +1721,6 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const param_decl = try arena.create(Node.ParamDecl);
param_decl.* = Node.ParamDecl{
.base = Node{ .id = .ParamDecl },
.doc_comments = doc_comments,
.comptime_token = comptime_token,
.noalias_token = noalias_token,
@ -1807,7 +1767,6 @@ fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.If);
node.* = Node.If{
.base = Node{ .id = .If },
.if_token = if_token,
.condition = condition,
.payload = payload,
@ -1832,7 +1791,6 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const node = try arena.create(Node.While);
node.* = Node.While{
.base = Node{ .id = .While },
.label = null,
.inline_token = null,
.while_token = while_token,
@ -1861,7 +1819,6 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.For);
node.* = Node.For{
.base = Node{ .id = .For },
.label = null,
.inline_token = null,
.for_token = for_token,
@ -1883,7 +1840,6 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.Payload);
node.* = Node.Payload{
.base = Node{ .id = .Payload },
.lpipe = lpipe,
.error_symbol = identifier,
.rpipe = rpipe,
@ -1902,7 +1858,6 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.PointerPayload);
node.* = Node.PointerPayload{
.base = Node{ .id = .PointerPayload },
.lpipe = lpipe,
.ptr_token = asterisk,
.value_symbol = identifier,
@ -1930,7 +1885,6 @@ fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
const node = try arena.create(Node.PointerIndexPayload);
node.* = Node.PointerIndexPayload{
.base = Node{ .id = .PointerIndexPayload },
.lpipe = lpipe,
.ptr_token = asterisk,
.value_symbol = identifier,
@ -1972,7 +1926,6 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
} else if (eatToken(it, .Keyword_else)) |else_token| {
const else_node = try arena.create(Node.SwitchElse);
else_node.* = Node.SwitchElse{
.base = Node{ .id = .SwitchElse },
.token = else_token,
};
try list.push(&else_node.base);
@ -1980,7 +1933,6 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.SwitchCase);
node.* = Node.SwitchCase{
.base = Node{ .id = .SwitchCase },
.items = list,
.arrow_token = undefined, // set by caller
.payload = null,
@ -1999,7 +1951,6 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.InfixOp);
node.* = Node.InfixOp{
.base = Node{ .id = .InfixOp },
.op_token = token,
.lhs = expr,
.op = Node.InfixOp.Op{ .Range = {} },
@ -2052,7 +2003,6 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.InfixOp);
node.* = Node.InfixOp{
.base = Node{ .id = .InfixOp },
.op_token = token.index,
.lhs = undefined, // set by caller
.op = op,
@ -2212,7 +2162,6 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.PrefixOp);
node.* = Node.PrefixOp{
.base = Node{ .id = .PrefixOp },
.op_token = token.index,
.op = op,
.rhs = undefined,
@ -2236,7 +2185,6 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
if (eatToken(it, .QuestionMark)) |token| {
const node = try arena.create(Node.PrefixOp);
node.* = Node.PrefixOp{
.base = Node{ .id = .PrefixOp },
.op_token = token,
.op = Node.PrefixOp.Op.OptionalType,
.rhs = undefined, // set by caller
@ -2255,7 +2203,6 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
};
const node = try arena.create(Node.AnyFrameType);
node.* = Node.AnyFrameType{
.base = Node{ .id = .AnyFrameType },
.anyframe_token = token,
.result = Node.AnyFrameType.Result{
.arrow_token = arrow,
@ -2430,7 +2377,6 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
// this grammar rule be altered?
const node = try arena.create(Node.InfixOp);
node.* = Node.InfixOp{
.base = Node{ .id = .InfixOp },
.op_token = period,
.lhs = undefined, // set by caller
.op = Node.InfixOp.Op.Period,
@ -2452,7 +2398,6 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.SuffixOp);
node.* = Node.SuffixOp{
.base = Node{ .id = .SuffixOp },
.lhs = undefined, // set by caller
.op = op_and_token.op,
.rtoken = op_and_token.token,
@ -2506,7 +2451,6 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
const node = try arena.create(Node.PrefixOp);
node.* = Node.PrefixOp{
.base = Node{ .id = .PrefixOp },
.op_token = lbracket,
.op = op,
.rhs = undefined, // set by caller
@ -2656,7 +2600,6 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?
const node = try arena.create(Node.ContainerDecl);
node.* = Node.ContainerDecl{
.base = Node{ .id = .ContainerDecl },
.layout_token = null,
.kind_token = kind_token.index,
.init_arg_expr = init_arg_expr,
@ -2729,7 +2672,6 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No
const op_token = eatToken(it, token) orelse return null;
const node = try arena.create(Node.InfixOp);
node.* = Node.InfixOp{
.base = Node{ .id = .InfixOp },
.op_token = op_token,
.lhs = undefined, // set by caller
.op = op,
@ -2752,7 +2694,6 @@ fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
};
const node = try arena.create(Node.BuiltinCall);
node.* = Node.BuiltinCall{
.base = Node{ .id = .BuiltinCall },
.builtin_token = token,
.params = params.list,
.rparen_token = params.rparen,
@ -2766,7 +2707,6 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.ErrorTag);
node.* = Node.ErrorTag{
.base = Node{ .id = .ErrorTag },
.doc_comments = doc_comments,
.name_token = token,
};
@ -2777,7 +2717,6 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const token = eatToken(it, .Identifier) orelse return null;
const node = try arena.create(Node.Identifier);
node.* = Node.Identifier{
.base = Node{ .id = .Identifier },
.token = token,
};
return &node.base;
@ -2787,7 +2726,6 @@ fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const token = eatToken(it, .Keyword_var) orelse return null;
const node = try arena.create(Node.VarType);
node.* = Node.VarType{
.base = Node{ .id = .VarType },
.token = token,
};
return &node.base;
@ -2807,7 +2745,6 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
if (eatToken(it, .StringLiteral)) |token| {
const node = try arena.create(Node.StringLiteral);
node.* = Node.StringLiteral{
.base = Node{ .id = .StringLiteral },
.token = token,
};
return &node.base;
@ -2816,7 +2753,6 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
if (eatToken(it, .MultilineStringLiteralLine)) |first_line| {
const node = try arena.create(Node.MultilineStringLiteral);
node.* = Node.MultilineStringLiteral{
.base = Node{ .id = .MultilineStringLiteral },
.lines = Node.MultilineStringLiteral.LineList.init(arena),
};
try node.lines.push(first_line);
@ -2833,7 +2769,6 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
const token = eatToken(it, .IntegerLiteral) orelse return null;
const node = try arena.create(Node.IntegerLiteral);
node.* = Node.IntegerLiteral{
.base = Node{ .id = .IntegerLiteral },
.token = token,
};
return &node.base;
@ -2843,7 +2778,6 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const token = eatToken(it, .FloatLiteral) orelse return null;
const node = try arena.create(Node.FloatLiteral);
node.* = Node.FloatLiteral{
.base = Node{ .id = .FloatLiteral },
.token = token,
};
return &node.base;
@ -2853,7 +2787,6 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const token = eatToken(it, .Keyword_try) orelse return null;
const node = try arena.create(Node.PrefixOp);
node.* = Node.PrefixOp{
.base = Node{ .id = .PrefixOp },
.op_token = token,
.op = Node.PrefixOp.Op.Try,
.rhs = undefined, // set by caller
@ -2865,7 +2798,6 @@ fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const token = eatToken(it, .Keyword_usingnamespace) orelse return null;
const node = try arena.create(Node.Use);
node.* = Node.Use{
.base = Node{ .id = .Use },
.doc_comments = null,
.visib_token = null,
.use_token = token,
@ -2891,7 +2823,6 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node
});
const else_node = try arena.create(Node.Else);
else_node.* = Node.Else{
.base = Node{ .id = .Else },
.else_token = else_token,
.payload = payload,
.body = else_expr,
@ -2912,7 +2843,6 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D
const node = try arena.create(Node.DocComment);
node.* = Node.DocComment{
.base = Node{ .id = .DocComment },
.lines = lines,
};
return node;
@ -2924,7 +2854,6 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a
if (tree.tokensOnSameLine(after_token, comment_token)) {
const node = try arena.create(Node.DocComment);
node.* = Node.DocComment{
.base = Node{ .id = .DocComment },
.lines = Node.DocComment.LineList.init(arena),
};
try node.lines.push(comment_token);
@ -3031,7 +2960,6 @@ fn parseBinOpExpr(
fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node {
const node = try arena.create(Node.InfixOp);
node.* = Node.InfixOp{
.base = Node{ .id = .InfixOp },
.op_token = index,
.lhs = undefined,
.op = op,

View File

@ -193,6 +193,7 @@ fn renderRoot(
fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Child.Error!void {
const first_token = node.firstToken();
var prev_token = first_token;
if (prev_token == 0) return;
while (tree.tokens.at(prev_token - 1).id == .DocComment) {
prev_token -= 1;
}

View File

@ -9,66 +9,77 @@ pub const Token = struct {
pub const Keyword = struct {
bytes: []const u8,
id: Id,
hash: u32,
fn init(bytes: []const u8, id: Id) Keyword {
@setEvalBranchQuota(2000);
return .{
.bytes = bytes,
.id = id,
.hash = std.hash_map.hashString(bytes),
};
}
};
pub const keywords = [_]Keyword{
Keyword{ .bytes = "align", .id = Id.Keyword_align },
Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },
Keyword{ .bytes = "and", .id = Id.Keyword_and },
Keyword{ .bytes = "anyframe", .id = Id.Keyword_anyframe },
Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
Keyword{ .bytes = "async", .id = Id.Keyword_async },
Keyword{ .bytes = "await", .id = Id.Keyword_await },
Keyword{ .bytes = "break", .id = Id.Keyword_break },
Keyword{ .bytes = "catch", .id = Id.Keyword_catch },
Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime },
Keyword{ .bytes = "const", .id = Id.Keyword_const },
Keyword{ .bytes = "continue", .id = Id.Keyword_continue },
Keyword{ .bytes = "defer", .id = Id.Keyword_defer },
Keyword{ .bytes = "else", .id = Id.Keyword_else },
Keyword{ .bytes = "enum", .id = Id.Keyword_enum },
Keyword{ .bytes = "errdefer", .id = Id.Keyword_errdefer },
Keyword{ .bytes = "error", .id = Id.Keyword_error },
Keyword{ .bytes = "export", .id = Id.Keyword_export },
Keyword{ .bytes = "extern", .id = Id.Keyword_extern },
Keyword{ .bytes = "false", .id = Id.Keyword_false },
Keyword{ .bytes = "fn", .id = Id.Keyword_fn },
Keyword{ .bytes = "for", .id = Id.Keyword_for },
Keyword{ .bytes = "if", .id = Id.Keyword_if },
Keyword{ .bytes = "inline", .id = Id.Keyword_inline },
Keyword{ .bytes = "nakedcc", .id = Id.Keyword_nakedcc },
Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias },
Keyword{ .bytes = "noasync", .id = Id.Keyword_noasync },
Keyword{ .bytes = "noinline", .id = Id.Keyword_noinline },
Keyword{ .bytes = "null", .id = Id.Keyword_null },
Keyword{ .bytes = "or", .id = Id.Keyword_or },
Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
Keyword{ .bytes = "resume", .id = Id.Keyword_resume },
Keyword{ .bytes = "return", .id = Id.Keyword_return },
Keyword{ .bytes = "linksection", .id = Id.Keyword_linksection },
Keyword{ .bytes = "stdcallcc", .id = Id.Keyword_stdcallcc },
Keyword{ .bytes = "struct", .id = Id.Keyword_struct },
Keyword{ .bytes = "suspend", .id = Id.Keyword_suspend },
Keyword{ .bytes = "switch", .id = Id.Keyword_switch },
Keyword{ .bytes = "test", .id = Id.Keyword_test },
Keyword{ .bytes = "threadlocal", .id = Id.Keyword_threadlocal },
Keyword{ .bytes = "true", .id = Id.Keyword_true },
Keyword{ .bytes = "try", .id = Id.Keyword_try },
Keyword{ .bytes = "undefined", .id = Id.Keyword_undefined },
Keyword{ .bytes = "union", .id = Id.Keyword_union },
Keyword{ .bytes = "unreachable", .id = Id.Keyword_unreachable },
Keyword{ .bytes = "usingnamespace", .id = Id.Keyword_usingnamespace },
Keyword{ .bytes = "var", .id = Id.Keyword_var },
Keyword{ .bytes = "volatile", .id = Id.Keyword_volatile },
Keyword{ .bytes = "while", .id = Id.Keyword_while },
Keyword.init("align", .Keyword_align),
Keyword.init("allowzero", .Keyword_allowzero),
Keyword.init("and", .Keyword_and),
Keyword.init("anyframe", .Keyword_anyframe),
Keyword.init("asm", .Keyword_asm),
Keyword.init("async", .Keyword_async),
Keyword.init("await", .Keyword_await),
Keyword.init("break", .Keyword_break),
Keyword.init("catch", .Keyword_catch),
Keyword.init("comptime", .Keyword_comptime),
Keyword.init("const", .Keyword_const),
Keyword.init("continue", .Keyword_continue),
Keyword.init("defer", .Keyword_defer),
Keyword.init("else", .Keyword_else),
Keyword.init("enum", .Keyword_enum),
Keyword.init("errdefer", .Keyword_errdefer),
Keyword.init("error", .Keyword_error),
Keyword.init("export", .Keyword_export),
Keyword.init("extern", .Keyword_extern),
Keyword.init("false", .Keyword_false),
Keyword.init("fn", .Keyword_fn),
Keyword.init("for", .Keyword_for),
Keyword.init("if", .Keyword_if),
Keyword.init("inline", .Keyword_inline),
Keyword.init("nakedcc", .Keyword_nakedcc),
Keyword.init("noalias", .Keyword_noalias),
Keyword.init("noasync", .Keyword_noasync),
Keyword.init("noinline", .Keyword_noinline),
Keyword.init("null", .Keyword_null),
Keyword.init("or", .Keyword_or),
Keyword.init("orelse", .Keyword_orelse),
Keyword.init("packed", .Keyword_packed),
Keyword.init("pub", .Keyword_pub),
Keyword.init("resume", .Keyword_resume),
Keyword.init("return", .Keyword_return),
Keyword.init("linksection", .Keyword_linksection),
Keyword.init("stdcallcc", .Keyword_stdcallcc),
Keyword.init("struct", .Keyword_struct),
Keyword.init("suspend", .Keyword_suspend),
Keyword.init("switch", .Keyword_switch),
Keyword.init("test", .Keyword_test),
Keyword.init("threadlocal", .Keyword_threadlocal),
Keyword.init("true", .Keyword_true),
Keyword.init("try", .Keyword_try),
Keyword.init("undefined", .Keyword_undefined),
Keyword.init("union", .Keyword_union),
Keyword.init("unreachable", .Keyword_unreachable),
Keyword.init("usingnamespace", .Keyword_usingnamespace),
Keyword.init("var", .Keyword_var),
Keyword.init("volatile", .Keyword_volatile),
Keyword.init("while", .Keyword_while),
};
// TODO perfect hash at comptime
fn getKeyword(bytes: []const u8) ?Id {
pub fn getKeyword(bytes: []const u8) ?Id {
var hash = std.hash_map.hashString(bytes);
for (keywords) |kw| {
if (mem.eql(u8, kw.bytes, bytes)) {
if (kw.hash == hash and mem.eql(u8, kw.bytes, bytes)) {
return kw.id;
}
}

View File

@ -713,6 +713,10 @@ pub const ZigClangRecordDecl_field_iterator = extern struct {
opaque: *c_void,
};
pub const ZigClangEnumDecl_enumerator_iterator = extern struct {
opaque: *c_void,
};
pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
@ -723,7 +727,7 @@ pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*st
pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;
pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool;
pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl;
pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) ?*const struct_ZigClangEnumDecl;
pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl;
pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;
pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl;
pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl;
@ -742,6 +746,11 @@ pub extern fn ZigClangRecordDecl_field_iterator_next(ZigClangRecordDecl_field_it
pub extern fn ZigClangRecordDecl_field_iterator_deref(ZigClangRecordDecl_field_iterator) *const struct_ZigClangFieldDecl;
pub extern fn ZigClangRecordDecl_field_iterator_neq(ZigClangRecordDecl_field_iterator, ZigClangRecordDecl_field_iterator) bool;
pub extern fn ZigClangEnumDecl_getIntegerType(self: ?*const struct_ZigClangEnumDecl) struct_ZigClangQualType;
pub extern fn ZigClangEnumDecl_enumerator_begin(*const ZigClangEnumDecl) ZigClangEnumDecl_enumerator_iterator;
pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangEnumDecl_enumerator_iterator;
pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator;
pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl;
pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool;
pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*c]const u8;
pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;
pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl;
@ -992,6 +1001,8 @@ pub extern fn ZigClangBinaryOperator_getLHS(*const ZigClangBinaryOperator) *cons
pub extern fn ZigClangBinaryOperator_getRHS(*const ZigClangBinaryOperator) *const ZigClangExpr;
pub extern fn ZigClangBinaryOperator_getType(*const ZigClangBinaryOperator) ZigClangQualType;
pub extern fn ZigClangDecayedType_getDecayedType(*const ZigClangDecayedType) ZigClangQualType;
pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigClangStringLiteral_StringKind;
pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*c]const u8;
@ -1000,3 +1011,6 @@ pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigC
pub extern fn ZigClangFieldDecl_isBitField(*const struct_ZigClangFieldDecl) bool;
pub extern fn ZigClangFieldDecl_getType(*const struct_ZigClangFieldDecl) struct_ZigClangQualType;
pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) struct_ZigClangSourceLocation;
pub extern fn ZigClangEnumConstantDecl_getInitExpr(*const ZigClangEnumConstantDecl) ?*const ZigClangExpr;
pub extern fn ZigClangEnumConstantDecl_getInitVal(*const ZigClangEnumConstantDecl) *const ZigClangAPSInt;

View File

@ -15,7 +15,7 @@ pub const Error = error{OutOfMemory};
const TypeError = Error || error{UnsupportedType};
const TransError = TypeError || error{UnsupportedTranslation};
const DeclTable = std.HashMap(usize, void, addrHash, addrEql);
const DeclTable = std.HashMap(usize, []const u8, addrHash, addrEql);
fn addrHash(x: usize) u32 {
switch (@typeInfo(usize).Int.bits) {
@ -109,6 +109,12 @@ const Context = struct {
global_scope: *Scope.Root,
ptr_params: std.BufSet,
clang_context: *ZigClangASTContext,
mangle_count: u64 = 0,
fn getMangle(c: *Context) u64 {
c.mangle_count += 1;
return c.mangle_count;
}
fn a(c: *Context) *std.mem.Allocator {
return &c.tree.arena_allocator.allocator;
@ -239,7 +245,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));
},
.Enum => {
try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for enums", .{});
_ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl));
},
.Record => {
return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
@ -255,9 +261,10 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
}
fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice
if (c.decl_table.contains(@ptrToInt(fn_decl))) return; // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl)));
_ = try c.decl_table.put(@ptrToInt(fn_decl), fn_name);
const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);
const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
const fn_type = ZigClangQualType_getTypePtr(fn_qt);
@ -319,7 +326,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
}
fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
if (try c.decl_table.put(@ptrToInt(var_decl), {})) |_| return; // Avoid processing this decl twice
if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
@ -330,6 +337,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
var scope = &c.global_scope.base;
const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl)));
_ = try c.decl_table.put(@ptrToInt(var_decl), var_name);
const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
@ -348,7 +356,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
else
try appendToken(c, .Keyword_var, "var");
const name_tok = try appendToken(c, .Identifier, var_name);
const name_tok = try appendIdentifier(c, var_name);
_ = try appendToken(c, .Colon, ":");
const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) {
@ -381,7 +389,6 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
const node = try c.a().create(ast.Node.VarDecl);
node.* = ast.Node.VarDecl{
.base = ast.Node{ .id = .VarDecl },
.doc_comments = null,
.visib_token = visib_tok,
.thread_local_token = thread_local_token,
@ -401,13 +408,16 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
}
fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void {
if (try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), {})) |_| return; // Avoid processing this decl twice
if (c.decl_table.contains(
@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)),
)) return; // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
const const_tok = try appendToken(c, .Keyword_const, "const");
const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
const name_tok = try appendToken(c, .Identifier, typedef_name);
_ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name);
const name_tok = try appendIdentifier(c, typedef_name);
const eq_tok = try appendToken(c, .Equal, "=");
const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
@ -421,7 +431,6 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err
const node = try c.a().create(ast.Node.VarDecl);
node.* = ast.Node.VarDecl{
.base = ast.Node{ .id = .VarDecl },
.doc_comments = null,
.visib_token = visib_tok,
.thread_local_token = null,
@ -441,7 +450,7 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err
}
fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void {
if (try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), {})) |_| return; // Avoid processing this decl twice
if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
@ -451,7 +460,7 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!
else if (ZigClangRecordDecl_isStruct(record_decl))
"struct"
else
return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), bare_name, "record {} is not a struct or union", .{bare_name});
return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
return;
@ -460,7 +469,8 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!
const const_tok = try appendToken(c, .Keyword_const, "const");
const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
const name_tok = try appendToken(c, .Identifier, name);
_ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
const name_tok = try appendIdentifier(c, name);
const eq_tok = try appendToken(c, .Equal, "=");
const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) {
@ -473,7 +483,6 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!
const node = try c.a().create(ast.Node.VarDecl);
node.* = ast.Node.VarDecl{
.base = ast.Node{ .id = .VarDecl },
.doc_comments = null,
.visib_token = visib_tok,
.thread_local_token = null,
@ -497,14 +506,13 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!
fn createAlias(c: *Context, alias: var) !void {
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
const mut_tok = try appendToken(c, .Keyword_const, "const");
const name_tok = try appendToken(c, .Identifier, alias.alias);
const name_tok = try appendIdentifier(c, alias.alias);
const eq_tok = try appendToken(c, .Equal, "=");
const init_node = try appendIdentifier(c, alias.name);
const init_node = try transCreateNodeIdentifier(c, alias.name);
const node = try c.a().create(ast.Node.VarDecl);
node.* = ast.Node.VarDecl{
.base = ast.Node{ .id = .VarDecl },
.doc_comments = null,
.visib_token = visib_tok,
.thread_local_token = null,
@ -787,7 +795,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
const c_name = try c.str(ZigClangDecl_getName_bytes_begin(
@ptrCast(*const ZigClangDecl, var_decl),
));
const name_token = try appendToken(c, .Identifier, c_name);
const name_token = try appendIdentifier(c, c_name);
const var_scope = try c.a().create(Scope.Var);
var_scope.* = Scope.Var{
@ -810,7 +818,6 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
const node = try c.a().create(ast.Node.VarDecl);
node.* = ast.Node.VarDecl{
.base = ast.Node{ .id = .VarDecl },
.doc_comments = null,
.visib_token = null,
.thread_local_token = thread_local_token,
@ -856,7 +863,7 @@ fn transDeclRefExpr(
const c_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl)));
const zig_name = transLookupZigIdentifier(scope, c_name);
if (lrvalue == .l_value) try rp.c.ptr_params.put(zig_name);
const node = try appendIdentifier(rp.c, zig_name);
const node = try transCreateNodeIdentifier(rp.c, zig_name);
return TransResult{
.node = node,
.node_scope = scope,
@ -978,7 +985,6 @@ fn transStringLiteral(
const token = try appendToken(rp.c, .StringLiteral, buf);
const node = try rp.c.a().create(ast.Node.StringLiteral);
node.* = ast.Node.StringLiteral{
.base = ast.Node{ .id = .StringLiteral },
.token = token,
};
const res = TransResult{
@ -1145,7 +1151,6 @@ fn transInitListExpr(
const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**");
const mul_node = try rp.c.a().create(ast.Node.InfixOp);
mul_node.* = .{
.base = .{ .id = .InfixOp },
.op_token = mul_tok,
.lhs = &filler_init_node.base,
.op = .ArrayMult,
@ -1164,7 +1169,6 @@ fn transInitListExpr(
const cat_node = try rp.c.a().create(ast.Node.InfixOp);
cat_node.* = .{
.base = .{ .id = .InfixOp },
.op_token = cat_tok,
.lhs = &init_node.base,
.op = .ArrayCat,
@ -1292,11 +1296,10 @@ fn maybeSuppressResult(
if (used == .used) return result;
// NOTE: This is backwards, but the semicolon must immediately follow the node.
_ = try appendToken(rp.c, .Semicolon, ";");
const lhs = try appendIdentifier(rp.c, "_");
const lhs = try transCreateNodeIdentifier(rp.c, "_");
const op_token = try appendToken(rp.c, .Equal, "=");
const op_node = try rp.c.a().create(ast.Node.InfixOp);
op_node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = .InfixOp },
.op_token = op_token,
.lhs = lhs,
.op = .Assign,
@ -1352,7 +1355,6 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro
const container_node = try c.a().create(ast.Node.ContainerDecl);
container_node.* = .{
.base = ast.Node{ .id = .ContainerDecl },
.layout_token = extern_tok,
.kind_token = container_tok,
.init_arg_expr = .None,
@ -1374,7 +1376,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro
return node;
}
const field_name = try appendToken(c, .Identifier, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))));
const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))));
_ = try appendToken(c, .Colon, ":");
const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc);
@ -1396,6 +1398,195 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro
return &container_node.base;
}
fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {
if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|
return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
const const_tok = try appendToken(c, .Keyword_const, "const");
var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl)));
var is_unnamed = false;
if (bare_name.len == 0) {
bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_unnamed = true;
}
const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});
_ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
const name_tok = try appendIdentifier(c, name);
const eq_tok = try appendToken(c, .Equal, "=");
const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
var pure_enum = true;
var it = ZigClangEnumDecl_enumerator_begin(enum_def);
var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| {
pure_enum = false;
break;
}
}
const extern_tok = try appendToken(c, .Keyword_extern, "extern");
const container_tok = try appendToken(c, .Keyword_enum, "enum");
const container_node = try c.a().create(ast.Node.ContainerDecl);
container_node.* = .{
.layout_token = extern_tok,
.kind_token = container_tok,
.init_arg_expr = .None,
.fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
.lbrace_token = undefined,
.rbrace_token = undefined,
};
const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (!isCBuiltinType(int_type, .UInt) and
!isCBuiltinType(int_type, .Int))
{
_ = try appendToken(c, .LParen, "(");
container_node.init_arg_expr = .{
.Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
error.UnsupportedType => {
if (is_unnamed) {
try emitWarning(c, enum_loc, "unable to translate enum tag type", .{});
} else {
try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
}
return null;
},
else => |e| return e,
},
};
_ = try appendToken(c, .RParen, ")");
}
container_node.lbrace_token = try appendToken(c, .LBrace, "{");
it = ZigClangEnumDecl_enumerator_begin(enum_def);
end_it = ZigClangEnumDecl_enumerator_end(enum_def);
while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const)));
const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name))
enum_val_name[bare_name.len..]
else
enum_val_name;
const field_name_tok = try appendIdentifier(c, field_name);
const int_node = if (!pure_enum) blk: {
_ = try appendToken(c, .Colon, "=");
break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
} else
null;
const field_node = try c.a().create(ast.Node.ContainerField);
field_node.* = .{
.doc_comments = null,
.comptime_token = null,
.name_token = field_name_tok,
.type_expr = null,
.value_expr = int_node,
.align_expr = null,
};
try container_node.fields_and_decls.push(&field_node.base);
_ = try appendToken(c, .Comma, ",");
// In C each enum value is in the global namespace. So we put them there too.
// At this point we can rely on the enum emitting successfully.
try addEnumTopLevel(c, name, field_name, enum_val_name);
}
container_node.rbrace_token = try appendToken(c, .RBrace, "}");
break :blk &container_node.base;
} else
try transCreateNodeOpaqueType(c);
const semicolon_token = try appendToken(c, .Semicolon, ";");
const node = try c.a().create(ast.Node.VarDecl);
node.* = ast.Node.VarDecl{
.visib_token = visib_tok,
.mut_token = const_tok,
.name_token = name_tok,
.eq_token = eq_tok,
.init_node = init_node,
.semicolon_token = semicolon_token,
.doc_comments = null,
.comptime_token = null,
.extern_export_token = null,
.thread_local_token = null,
.lib_name = null,
.type_node = null,
.align_node = null,
.section_node = null,
};
try addTopLevelDecl(c, name, &node.base);
if (!is_unnamed)
try c.alias_list.push(.{ .alias = bare_name, .name = name });
return transCreateNodeIdentifier(c, name);
}
fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void {
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
const const_tok = try appendToken(c, .Keyword_const, "const");
const name_tok = try appendIdentifier(c, enum_val_name);
const eq_tok = try appendToken(c, .Equal, "=");
const enum_ident = try transCreateNodeIdentifier(c, enum_name);
const period_tok = try appendToken(c, .Period, ".");
const field_ident = try transCreateNodeIdentifier(c, field_name);
const field_access_node = try c.a().create(ast.Node.InfixOp);
field_access_node.* = .{
.op_token = period_tok,
.lhs = enum_ident,
.op = .Period,
.rhs = field_ident,
};
const semicolon_token = try appendToken(c, .Semicolon, ";");
const node = try c.a().create(ast.Node.VarDecl);
node.* = ast.Node.VarDecl{
.visib_token = visib_tok,
.mut_token = const_tok,
.name_token = name_tok,
.eq_token = eq_tok,
.init_node = &field_access_node.base,
.semicolon_token = semicolon_token,
.thread_local_token = null,
.doc_comments = null,
.comptime_token = null,
.extern_export_token = null,
.lib_name = null,
.type_node = null,
.align_node = null,
.section_node = null,
};
try addTopLevelDecl(c, field_name, &node.base);
}
fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {
const c_type = qualTypeCanon(qt);
if (ZigClangType_getTypeClass(c_type) != .Builtin)
return false;
const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type);
return ZigClangBuiltinType_getKind(builtin_ty) == kind;
}
fn qualTypeIsPtr(qt: ZigClangQualType) bool {
return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;
}
@ -1523,7 +1714,6 @@ fn transCreateNodeAssign(
const node = try rp.c.a().create(ast.Node.InfixOp);
node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = .InfixOp },
.op_token = eq_token,
.lhs = lhs_node.node,
.op = .Assign,
@ -1553,7 +1743,6 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti
_ = try appendToken(c, .LParen, "(");
const node = try c.a().create(ast.Node.BuiltinCall);
node.* = ast.Node.BuiltinCall{
.base = ast.Node{ .id = .BuiltinCall },
.builtin_token = builtin_token,
.params = ast.Node.BuiltinCall.ParamList.init(c.a()),
.rparen_token = undefined, // set after appending args
@ -1565,7 +1754,6 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
_ = try appendToken(c, .LParen, "(");
const node = try c.a().create(ast.Node.SuffixOp);
node.* = ast.Node.SuffixOp{
.base = ast.Node{ .id = .SuffixOp },
.lhs = fn_expr,
.op = ast.Node.SuffixOp.Op{
.Call = ast.Node.SuffixOp.Op.Call{
@ -1586,7 +1774,6 @@ fn transCreateNodePrefixOp(
) !*ast.Node.PrefixOp {
const node = try c.a().create(ast.Node.PrefixOp);
node.* = ast.Node.PrefixOp{
.base = ast.Node{ .id = .PrefixOp },
.op_token = try appendToken(c, op_tok_id, bytes),
.op = op,
.rhs = undefined, // translate and set afterward
@ -1609,7 +1796,6 @@ fn transCreateNodeInfixOp(
const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
const node = try rp.c.a().create(ast.Node.InfixOp);
node.* = ast.Node.InfixOp{
.base = ast.Node{ .id = .InfixOp },
.op_token = op_token,
.lhs = lhs.node,
.op = op,
@ -1619,7 +1805,6 @@ fn transCreateNodeInfixOp(
const rparen = try appendToken(rp.c, .RParen, ")");
const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
grouped_expr.* = ast.Node.GroupedExpression{
.base = ast.Node{ .id = .GroupedExpression },
.lparen = lparen,
.expr = &node.base,
.rparen = rparen,
@ -1644,7 +1829,7 @@ fn transCreateNodePtrType(
.Identifier => blk: {
const lbracket = try appendToken(c, .LBracket, "["); // Rendering checks if this token + 2 == .Identifier, so needs to return this token
_ = try appendToken(c, .Asterisk, "*");
_ = try appendToken(c, .Identifier, "c");
_ = try appendIdentifier(c, "c");
_ = try appendToken(c, .RBracket, "]");
break :blk lbracket;
},
@ -1652,7 +1837,6 @@ fn transCreateNodePtrType(
else => unreachable,
};
node.* = ast.Node.PrefixOp{
.base = ast.Node{ .id = .PrefixOp },
.op_token = op_token,
.op = ast.Node.PrefixOp.Op{
.PtrType = .{
@ -1679,7 +1863,6 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
const token = try appendToken(c, .IntegerLiteral, str);
const node = try c.a().create(ast.Node.IntegerLiteral);
node.* = ast.Node.IntegerLiteral{
.base = ast.Node{ .id = .IntegerLiteral },
.token = token,
};
return &node.base;
@ -1689,7 +1872,6 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {
const ltoken = try appendToken(c, .Keyword_return, "return");
const node = try c.a().create(ast.Node.ControlFlowExpression);
node.* = ast.Node.ControlFlowExpression{
.base = ast.Node{ .id = .ControlFlowExpression },
.ltoken = ltoken,
.kind = .Return,
.rhs = null,
@ -1701,7 +1883,6 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
const token = try appendToken(c, .Keyword_undefined, "undefined");
const node = try c.a().create(ast.Node.UndefinedLiteral);
node.* = ast.Node.UndefinedLiteral{
.base = ast.Node{ .id = .UndefinedLiteral },
.token = token,
};
return &node.base;
@ -1711,7 +1892,6 @@ fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
const token = try appendToken(c, .Keyword_null, "null");
const node = try c.a().create(ast.Node.NullLiteral);
node.* = ast.Node.NullLiteral{
.base = ast.Node{ .id = .NullLiteral },
.token = token,
};
return &node.base;
@ -1724,7 +1904,6 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
try appendToken(c, .Keyword_false, "false");
const node = try c.a().create(ast.Node.BoolLiteral);
node.* = ast.Node.BoolLiteral{
.base = ast.Node{ .id = .BoolLiteral },
.token = token,
};
return &node.base;
@ -1734,7 +1913,6 @@ fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.N
_ = try appendToken(c, .LBrace, "{");
const node = try c.a().create(ast.Node.SuffixOp);
node.* = ast.Node.SuffixOp{
.base = ast.Node{ .id = .SuffixOp },
.lhs = .{ .dot = dot_tok },
.op = .{
.ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()),
@ -1748,7 +1926,6 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});
const node = try c.a().create(ast.Node.IntegerLiteral);
node.* = ast.Node.IntegerLiteral{
.base = ast.Node{ .id = .IntegerLiteral },
.token = token,
};
return &node.base;
@ -1793,25 +1970,25 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
.Builtin => {
const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
switch (ZigClangBuiltinType_getKind(builtin_ty)) {
.Void => return appendIdentifier(rp.c, "c_void"),
.Bool => return appendIdentifier(rp.c, "bool"),
.Char_U, .UChar, .Char_S, .Char8 => return appendIdentifier(rp.c, "u8"),
.SChar => return appendIdentifier(rp.c, "i8"),
.UShort => return appendIdentifier(rp.c, "c_ushort"),
.UInt => return appendIdentifier(rp.c, "c_uint"),
.ULong => return appendIdentifier(rp.c, "c_ulong"),
.ULongLong => return appendIdentifier(rp.c, "c_ulonglong"),
.Short => return appendIdentifier(rp.c, "c_short"),
.Int => return appendIdentifier(rp.c, "c_int"),
.Long => return appendIdentifier(rp.c, "c_long"),
.LongLong => return appendIdentifier(rp.c, "c_longlong"),
.UInt128 => return appendIdentifier(rp.c, "u128"),
.Int128 => return appendIdentifier(rp.c, "i128"),
.Float => return appendIdentifier(rp.c, "f32"),
.Double => return appendIdentifier(rp.c, "f64"),
.Float128 => return appendIdentifier(rp.c, "f128"),
.Float16 => return appendIdentifier(rp.c, "f16"),
.LongDouble => return appendIdentifier(rp.c, "c_longdouble"),
.Void => return transCreateNodeIdentifier(rp.c, "c_void"),
.Bool => return transCreateNodeIdentifier(rp.c, "bool"),
.Char_U, .UChar, .Char_S, .Char8 => return transCreateNodeIdentifier(rp.c, "u8"),
.SChar => return transCreateNodeIdentifier(rp.c, "i8"),
.UShort => return transCreateNodeIdentifier(rp.c, "c_ushort"),
.UInt => return transCreateNodeIdentifier(rp.c, "c_uint"),
.ULong => return transCreateNodeIdentifier(rp.c, "c_ulong"),
.ULongLong => return transCreateNodeIdentifier(rp.c, "c_ulonglong"),
.Short => return transCreateNodeIdentifier(rp.c, "c_short"),
.Int => return transCreateNodeIdentifier(rp.c, "c_int"),
.Long => return transCreateNodeIdentifier(rp.c, "c_long"),
.LongLong => return transCreateNodeIdentifier(rp.c, "c_longlong"),
.UInt128 => return transCreateNodeIdentifier(rp.c, "u128"),
.Int128 => return transCreateNodeIdentifier(rp.c, "i128"),
.Float => return transCreateNodeIdentifier(rp.c, "f32"),
.Double => return transCreateNodeIdentifier(rp.c, "f64"),
.Float128 => return transCreateNodeIdentifier(rp.c, "f128"),
.Float16 => return transCreateNodeIdentifier(rp.c, "f16"),
.LongDouble => return transCreateNodeIdentifier(rp.c, "c_longdouble"),
else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
}
},
@ -1891,21 +2068,36 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
return appendIdentifier(rp.c, typedef_name);
return transCreateNodeIdentifier(rp.c, typedef_name);
},
.Record => {
const record_ty = @ptrCast(*const ZigClangRecordType, ty);
const record_decl = ZigClangRecordType_getDecl(record_ty);
if (try getContainerName(rp.c, record_decl)) |name|
return appendIdentifier(rp.c, name)
if (try getContainerName(rp, record_decl)) |name|
return transCreateNodeIdentifier(rp.c, name)
else
return transRecordDecl(rp.c, record_decl);
},
.Enum => {
const enum_ty = @ptrCast(*const ZigClangEnumType, ty);
const enum_decl = ZigClangEnumType_getDecl(enum_ty);
return (try transEnumDecl(rp.c, enum_decl)) orelse
revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{});
},
.Elaborated => {
const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
return transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc);
},
.Decayed => {
const decayed_ty = @ptrCast(*const ZigClangDecayedType, ty);
return transQualType(rp, ZigClangDecayedType_getDecayedType(decayed_ty), source_loc);
},
.Attributed => {
const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty);
return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc);
},
else => {
const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name});
@ -1913,22 +2105,20 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
}
}
fn getContainerName(c: *Context, record_decl: *const ZigClangRecordDecl) !?[]const u8 {
const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
fn getContainerName(rp: RestorePoint, record_decl: *const ZigClangRecordDecl) !?[]const u8 {
const bare_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
"union"
else if (ZigClangRecordDecl_isStruct(record_decl))
"struct"
else {
try emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
return null;
};
else
return revertAndWarn(rp, error.UnsupportedType, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
return null;
return try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
return try std.fmt.allocPrint(rp.c.a(), "{}_{}", .{ container_kind_name, bare_name });
}
fn isCVoid(qt: ZigClangQualType) bool {
@ -2020,7 +2210,7 @@ fn finishTransFnProto(
else
null;
const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn");
const name_tok = if (fn_decl_context) |ctx| try appendToken(rp.c, .Identifier, ctx.fn_name) else null;
const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null;
const lparen_tok = try appendToken(rp.c, .LParen, "(");
var fn_params = ast.Node.FnProto.ParamList.init(rp.c.a());
@ -2038,7 +2228,7 @@ fn finishTransFnProto(
const param_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param)));
if (param_name.len > 0) {
// TODO: If len == 0, auto-generate arg1, arg2, etc? Or leave the name blank?
const result = try appendToken(rp.c, .Identifier, param_name);
const result = try appendIdentifier(rp.c, param_name);
_ = try appendToken(rp.c, .Colon, ":");
break :blk result;
}
@ -2087,12 +2277,12 @@ fn finishTransFnProto(
const return_type_node = blk: {
if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) {
break :blk try appendIdentifier(rp.c, "noreturn");
break :blk try transCreateNodeIdentifier(rp.c, "noreturn");
} else {
const return_qt = ZigClangFunctionType_getReturnType(fn_ty);
if (isCVoid(return_qt)) {
// convert primitive c_void to actual void (only for return type)
break :blk try appendIdentifier(rp.c, "void");
break :blk try transCreateNodeIdentifier(rp.c, "void");
} else {
break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) {
error.UnsupportedType => {
@ -2145,7 +2335,7 @@ fn emitWarning(c: *Context, loc: ZigClangSourceLocation, comptime format: []cons
fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime format: []const u8, args: var) !void {
// const name = @compileError(msg);
const const_tok = try appendToken(c, .Keyword_const, "const");
const name_tok = try appendToken(c, .Identifier, name);
const name_tok = try appendIdentifier(c, name);
const eq_tok = try appendToken(c, .Equal, "=");
const builtin_tok = try appendToken(c, .Builtin, "@compileError");
const lparen_tok = try appendToken(c, .LParen, "(");
@ -2190,6 +2380,7 @@ fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime
}
fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex {
std.debug.assert(token_id != .Identifier); // use appendIdentifier
return appendTokenFmt(c, token_id, "{}", .{bytes});
}
@ -2218,8 +2409,27 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8,
return token_index;
}
fn appendIdentifier(c: *Context, name: []const u8) !*ast.Node {
const token_index = try appendToken(c, .Identifier, name);
fn isValidZigIdentifier(name: []const u8) bool {
for (name) |c, i| {
switch (c) {
'_', 'a'...'z', 'A'...'Z' => {},
'0'...'9' => if (i == 0) return false,
else => return false,
}
}
return true;
}
fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
if (!isValidZigIdentifier(name) or std.zig.Token.getKeyword(name) != null) {
return appendTokenFmt(c, .Identifier, "@\"{}\"", .{name});
} else {
return appendTokenFmt(c, .Identifier, "{}", .{name});
}
}
fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
const token_index = try appendIdentifier(c, name);
const identifier = try c.a().create(ast.Node.Identifier);
identifier.* = ast.Node.Identifier{
.base = ast.Node{ .id = ast.Node.Id.Identifier },

View File

@ -217,6 +217,72 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const OpenGLProcs = union_OpenGLProcs;
});
cases.add_2("enums",
\\typedef enum {
\\ a,
\\ b,
\\ c,
\\} d;
\\enum {
\\ e,
\\ f = 4,
\\ g,
\\} h = e;
\\struct Baz {
\\ enum {
\\ i,
\\ j,
\\ k,
\\ } l;
\\ d m;
\\};
\\enum i {
\\ n,
\\ o,
\\ p,
\\};
, &[_][]const u8{
\\pub const a = enum_unnamed_1.a;
\\pub const b = enum_unnamed_1.b;
\\pub const c = enum_unnamed_1.c;
\\pub const enum_unnamed_1 = extern enum {
\\ a,
\\ b,
\\ c,
\\};
\\pub const d = enum_unnamed_1;
\\pub const e = enum_unnamed_2.e;
\\pub const f = enum_unnamed_2.f;
\\pub const g = enum_unnamed_2.g;
\\pub const enum_unnamed_2 = extern enum {
\\ e = 0,
\\ f = 4,
\\ g = 5,
\\};
\\pub export var h: enum_unnamed_2 = @as(enum_unnamed_2, e);
\\pub const i = enum_unnamed_3.i;
\\pub const j = enum_unnamed_3.j;
\\pub const k = enum_unnamed_3.k;
\\pub const enum_unnamed_3 = extern enum {
\\ i,
\\ j,
\\ k,
\\};
\\pub const struct_Baz = extern struct {
\\ l: enum_unnamed_3,
\\ m: d,
\\};
\\pub const n = enum_i.n;
\\pub const o = enum_i.o;
\\pub const p = enum_i.p;
\\pub const enum_i = extern enum {
\\ n,
\\ o,
\\ p,
\\};
\\pub const Baz = struct_Baz;
});
/////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
cases.add_both("typedef of function in struct field",
@ -440,7 +506,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
cases.add("enums",
cases.add_both("enums",
\\enum Foo {
\\ FooA,
\\ FooB,
@ -462,7 +528,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const Foo = enum_Foo;
});
cases.add("enums",
cases.add_both("enums",
\\enum Foo {
\\ FooA = 2,
\\ FooB = 5,
@ -686,7 +752,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
});
cases.add("zig keywords in C code",
cases.add_both("zig keywords in C code",
\\struct comptime {
\\ int defer;
\\};