translate-c: convert macro translation

This commit is contained in:
Veikka Tuominen
2021-02-11 17:44:04 +02:00
parent c30c2f7c13
commit 66bbd75a83
2 changed files with 307 additions and 694 deletions
+274 -686
View File
@@ -3512,86 +3512,48 @@ fn transCreateNodeNumber(c: *Context, int: anytype) !Node {
return Node.int_literal.create(c.arena, str);
}
fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node {
fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: Node, proto_alias: *ast.Payload.Func) !Node {
const scope = &c.global_scope.base;
const pub_tok = try appendToken(c, .Keyword_pub, "pub");
const fn_tok = try appendToken(c, .Keyword_fn, "fn");
const name_tok = try appendIdentifier(c, name);
_ = try appendToken(c, .LParen, "(");
var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa);
var fn_params = std.ArrayList(Node).init(c.gpa);
defer fn_params.deinit();
for (proto_alias.params()) |param, i| {
if (i != 0) {
_ = try appendToken(c, .Comma, ",");
}
const param_name_tok = param.name_token orelse
try appendTokenFmt(c, .Identifier, "arg_{d}", .{c.getMangle()});
const param_name = param.name orelse
try std.fmt.allocPrint(c.arena, "arg_{d}", .{c.getMangle()});
_ = try appendToken(c, .Colon, ":");
(try fn_params.addOne()).* = .{
.doc_comments = null,
.comptime_token = null,
.noalias_token = param.noalias_token,
.name_token = param_name_tok,
.param_type = param.param_type,
};
try fn_params.append(.{
.name = param_name,
.type = param.type,
.is_noalias = param.is_noalias,
});
}
_ = try appendToken(c, .RParen, ")");
_ = try appendToken(c, .Keyword_callconv, "callconv");
_ = try appendToken(c, .LParen, "(");
const callconv_expr = try transCreateNodeEnumLiteral(c, "Inline");
_ = try appendToken(c, .RParen, ")");
const block_lbrace = try appendToken(c, .LBrace, "{");
const return_kw = try appendToken(c, .Keyword_return, "return");
const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getInitNode().?);
const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
const call_params = call_expr.params();
const init = if (value.castTag(.var_decl)) |v|
v.data.init
else if (value.castTag(.var_simple) orelse value.castTag(.pub_var_simple)) |v|
v.data.init
else
unreachable;
const unwrap_expr = try Node.unwrap.create(c.arena, init);
const call_params = try c.arena.alloc(Node, fn_params.items.len);
for (fn_params.items) |param, i| {
if (i != 0) {
_ = try appendToken(c, .Comma, ",");
}
call_params[i] = try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?));
call_params[i] = try Node.identifier.create(c.arena, param.name);
}
call_expr.rtoken = try appendToken(c, .RParen, ")");
const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{
.ltoken = return_kw,
.tag = .Return,
}, .{
.rhs = &call_expr.base,
const call_expr = try Node.call.create(c.arean, .{
.lhs = unwrap_expr,
.args = call_params,
});
_ = try appendToken(c, .Semicolon, ";");
const return_expr = try Node.@"return".create(c.arean, call_expr);
const block = try Node.block_single.create(c.arean, return_expr);
const block = try ast.Node.Block.alloc(c.arena, 1);
block.* = .{
.lbrace = block_lbrace,
.statements_len = 1,
.rbrace = try appendToken(c, .RBrace, "}"),
};
block.statements()[0] = &return_expr.base;
const fn_proto = try ast.Node.FnProto.create(c.arena, .{
.params_len = fn_params.items.len,
.fn_token = fn_tok,
return Node.pub_inline_fn.create(c.arena, .{
.name = name,
.params = try c.arena.dupe(ast.Node.Param, fn_params.items),
.return_type = proto_alias.return_type,
}, .{
.visib_token = pub_tok,
.name_token = name_tok,
.body_node = &block.base,
.callconv_expr = callconv_expr,
.body = block,
});
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
return &fn_proto.base;
}
fn transCreateNodeShiftOp(
@@ -4108,27 +4070,13 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
const scope = &c.global_scope.base;
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
const mut_tok = try appendToken(c, .Keyword_const, "const");
const name_tok = try appendIdentifier(c, m.name);
const eq_token = try appendToken(c, .Equal, "=");
const init_node = try parseCExpr(c, m, scope);
const last = m.next().?;
if (last != .Eof and last != .Nl)
return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});
const semicolon_token = try appendToken(c, .Semicolon, ";");
const node = try ast.Node.VarDecl.create(c.arena, .{
.name_token = name_tok,
.mut_token = mut_tok,
.semicolon_token = semicolon_token,
}, .{
.visib_token = visib_tok,
.eq_token = eq_token,
.init_node = init_node,
});
_ = try c.global_scope.macro_table.put(m.name, &node.base);
const var_decl = try Node.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
_ = try c.global_scope.macro_table.put(m.name, var_decl);
}
fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
@@ -4136,16 +4084,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
defer block_scope.deinit();
const scope = &block_scope.base;
const pub_tok = try appendToken(c, .Keyword_pub, "pub");
const fn_tok = try appendToken(c, .Keyword_fn, "fn");
const name_tok = try appendIdentifier(c, m.name);
_ = try appendToken(c, .LParen, "(");
if (m.next().? != .LParen) {
return m.fail(c, "unable to translate C expr: expected '('", .{});
}
var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa);
var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
defer fn_params.deinit();
while (true) {
@@ -4153,120 +4096,78 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
_ = m.next();
const mangled_name = try block_scope.makeMangledName(c, m.slice());
const param_name_tok = try appendIdentifier(c, mangled_name);
_ = try appendToken(c, .Colon, ":");
const any_type = try c.arena.create(ast.Node.OneToken);
any_type.* = .{
.base = .{ .tag = .AnyType },
.token = try appendToken(c, .Keyword_anytype, "anytype"),
};
(try fn_params.addOne()).* = .{
.doc_comments = null,
.comptime_token = null,
.noalias_token = null,
.name_token = param_name_tok,
.param_type = .{ .any_type = &any_type.base },
};
try fn_params.append(.{
.is_noalias = false,
.name = mangled_name,
.type = Node.@"anytype".init(),
});
if (m.peek().? != .Comma) break;
_ = m.next();
_ = try appendToken(c, .Comma, ",");
}
if (m.next().? != .RParen) {
return m.fail(c, "unable to translate C expr: expected ')'", .{});
}
_ = try appendToken(c, .RParen, ")");
_ = try appendToken(c, .Keyword_callconv, "callconv");
_ = try appendToken(c, .LParen, "(");
const callconv_expr = try transCreateNodeEnumLiteral(c, "Inline");
_ = try appendToken(c, .RParen, ")");
const type_of = try c.createBuiltinCall("@TypeOf", 1);
const return_kw = try appendToken(c, .Keyword_return, "return");
const expr = try parseCExpr(c, m, scope);
const last = m.next().?;
if (last != .Eof and last != .Nl)
return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});
_ = try appendToken(c, .Semicolon, ";");
const type_of_arg = if (!expr.tag.isBlock()) expr else blk: {
const stmts = expr.blockStatements();
const typeof_arg = if (expr.castTag(.block)) |some| blk: {
const stmts = some.data.stmts;
const blk_last = stmts[stmts.len - 1];
const br = blk_last.cast(ast.Node.ControlFlowExpression).?;
break :blk br.getRHS().?;
};
type_of.params()[0] = type_of_arg;
type_of.rparen_token = try appendToken(c, .RParen, ")");
const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{
.ltoken = return_kw,
.tag = .Return,
}, .{
.rhs = expr,
});
const br = blk_last.castTag(.break_val).?;
break :blk br.data;
} else expr;
const typeof = try Node.typeof.create(c.arean, typeof_arg);
const return_expr = try Node.@"return".create(c.arena, expr);
try block_scope.statements.append(&return_expr.base);
const block_node = try block_scope.complete(c);
const fn_proto = try ast.Node.FnProto.create(c.arena, .{
.fn_token = fn_tok,
.params_len = fn_params.items.len,
.return_type = .{ .Explicit = &type_of.base },
}, .{
.visib_token = pub_tok,
.name_token = name_tok,
.body_node = block_node,
.callconv_expr = callconv_expr,
const fn_decl = try Node.pub_inline_fn.create(c.arena, .{
.name = m.name,
.params = try c.arena.dupe(ast.Payload.Param, fn_params.items),
.return_type = typeof,
.body = try block_scope.complete(c),
});
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
_ = try c.global_scope.macro_table.put(m.name, &fn_proto.base);
}
const ParseError = Error || error{ParseError};
fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
// TODO parseCAssignExpr here
const node = try parseCCondExpr(c, m, scope);
if (m.next().? != .Comma) {
m.i -= 1;
return node;
}
_ = try appendToken(c, .Semicolon, ";");
var block_scope = try Scope.Block.init(c, scope, true);
defer block_scope.deinit();
var last = node;
while (true) {
// suppress result
const lhs = try transCreateNodeIdentifier(c, "_");
const op_token = try appendToken(c, .Equal, "=");
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = .Assign },
.op_token = op_token,
.lhs = lhs,
.rhs = last,
};
try block_scope.statements.append(&op_node.base);
const ignore = try Node.ignore.create(c.arena, last);
try block_scope.statements.append(ignore);
last = try parseCCondExpr(c, m, scope);
_ = try appendToken(c, .Semicolon, ";");
if (m.next().? != .Comma) {
m.i -= 1;
break;
}
}
const break_node = try transCreateNodeBreak(c, block_scope.label, last);
try block_scope.statements.append(&break_node.base);
const break_node = try Node.break_val.create(c.arena, .{
.label = block_scope.label,
.val = last,
});
try block_scope.statements.append(break_node);
return try block_scope.complete(c);
}
fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
var lit_bytes = m.slice();
switch (m.list[m.i].id) {
@@ -4286,11 +4187,10 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
}
if (suffix == .none) {
return transCreateNodeInt(c, lit_bytes);
return transCreateNodeNumber(c, lit_bytes);
}
const cast_node = try c.createBuiltinCall("@as", 2);
cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (suffix) {
const type_node = try Node.type.create(c.arena, switch (suffix) {
.u => "c_uint",
.l => "c_long",
.lu => "c_ulong",
@@ -4304,27 +4204,22 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
.llu => 3,
else => unreachable,
}];
_ = try appendToken(c, .Comma, ",");
cast_node.params()[1] = try transCreateNodeInt(c, lit_bytes);
cast_node.rparen_token = try appendToken(c, .RParen, ")");
return &cast_node.base;
const rhs = try transCreateNodeNumber(c, lit_bytes);
return Node.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
},
.FloatLiteral => |suffix| {
if (lit_bytes[0] == '.')
lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});
if (suffix == .none) {
return transCreateNodeFloat(c, lit_bytes);
return transCreateNodeNumber(c, lit_bytes);
}
const cast_node = try c.createBuiltinCall("@as", 2);
cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (suffix) {
const type_node = try Node.type.create(c.arena, switch (suffix) {
.f => "f32",
.l => "c_longdouble",
else => unreachable,
});
_ = try appendToken(c, .Comma, ",");
cast_node.params()[1] = try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1]);
cast_node.rparen_token = try appendToken(c, .RParen, ")");
return &cast_node.base;
const rhs = try transCreateNodeNumber(c, lit_bytes[0 .. lit_bytes.len - 1]);
return Node.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
},
else => unreachable,
}
@@ -4490,79 +4385,62 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
return bytes[0..i];
}
fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
const tok = m.next().?;
const slice = m.slice();
switch (tok) {
.CharLiteral => {
if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, m));
const node = try c.arena.create(ast.Node.OneToken);
node.* = .{
.base = .{ .tag = .CharLiteral },
.token = token,
};
return &node.base;
return Node.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));
} else {
const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{slice[1 .. slice.len - 1]});
const node = try c.arena.create(ast.Node.OneToken);
node.* = .{
.base = .{ .tag = .IntegerLiteral },
.token = token,
};
return &node.base;
const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]});
return Node.int_literal.create(c.arena, str);
}
},
.StringLiteral => {
const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, m));
const node = try c.arena.create(ast.Node.OneToken);
node.* = .{
.base = .{ .tag = .StringLiteral },
.token = token,
};
return &node.base;
return Node.string_literal.create(c.arena, try zigifyEscapeSequences(c, m));
},
.IntegerLiteral, .FloatLiteral => {
return parseCNumLit(c, m);
},
// eventually this will be replaced by std.c.parse which will handle these correctly
.Keyword_void => return transCreateNodeIdentifierUnchecked(c, "c_void"),
.Keyword_bool => return transCreateNodeIdentifierUnchecked(c, "bool"),
.Keyword_double => return transCreateNodeIdentifierUnchecked(c, "f64"),
.Keyword_long => return transCreateNodeIdentifierUnchecked(c, "c_long"),
.Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_int"),
.Keyword_float => return transCreateNodeIdentifierUnchecked(c, "f32"),
.Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_short"),
.Keyword_char => return transCreateNodeIdentifierUnchecked(c, "u8"),
.Keyword_void => return Node.type.create(c.arena, "c_void"),
.Keyword_bool => return Node.type.create(c.arena, "bool"),
.Keyword_double => return Node.type.create(c.arena, "f64"),
.Keyword_long => return Node.type.create(c.arena, "c_long"),
.Keyword_int => return Node.type.create(c.arena, "c_int"),
.Keyword_float => return Node.type.create(c.arena, "f32"),
.Keyword_short => return Node.type.create(c.arena, "c_short"),
.Keyword_char => return Node.type.create(c.arena, "u8"),
.Keyword_unsigned => if (m.next()) |t| switch (t) {
.Keyword_char => return transCreateNodeIdentifierUnchecked(c, "u8"),
.Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_ushort"),
.Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_uint"),
.Keyword_char => return Node.type.create(c.arena, "u8"),
.Keyword_short => return Node.type.create(c.arena, "c_ushort"),
.Keyword_int => return Node.type.create(c.arena, "c_uint"),
.Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
_ = m.next();
return transCreateNodeIdentifierUnchecked(c, "c_ulonglong");
} else return transCreateNodeIdentifierUnchecked(c, "c_ulong"),
return Node.type.create(c.arena, "c_ulonglong");
} else return Node.type.create(c.arena, "c_ulong"),
else => {
m.i -= 1;
return transCreateNodeIdentifierUnchecked(c, "c_uint");
return Node.type.create(c.arena, "c_uint");
},
} else {
return transCreateNodeIdentifierUnchecked(c, "c_uint");
return Node.type.create(c.arena, "c_uint");
},
.Keyword_signed => if (m.next()) |t| switch (t) {
.Keyword_char => return transCreateNodeIdentifierUnchecked(c, "i8"),
.Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_short"),
.Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_int"),
.Keyword_char => return Node.type.create(c.arena, "i8"),
.Keyword_short => return Node.type.create(c.arena, "c_short"),
.Keyword_int => return Node.type.create(c.arena, "c_int"),
.Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
_ = m.next();
return transCreateNodeIdentifierUnchecked(c, "c_longlong");
} else return transCreateNodeIdentifierUnchecked(c, "c_long"),
return Node.type.create(c.arena, "c_longlong");
} else return Node.type.create(c.arena, "c_long"),
else => {
m.i -= 1;
return transCreateNodeIdentifierUnchecked(c, "c_int");
return Node.type.create(c.arena, "c_int");
},
} else {
return transCreateNodeIdentifierUnchecked(c, "c_int");
return Node.type.create(c.arena, "c_int");
},
.Keyword_enum, .Keyword_struct, .Keyword_union => {
// struct Foo will be declared as struct_Foo by transRecordDecl
@@ -4572,17 +4450,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
return error.ParseError;
}
const ident_token = try appendTokenFmt(c, .Identifier, "{s}_{s}", .{ slice, m.slice() });
const identifier = try c.arena.create(ast.Node.OneToken);
identifier.* = .{
.base = .{ .tag = .Identifier },
.token = ident_token,
};
return &identifier.base;
const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
return Node.identifier.create(c.arena, name);
},
.Identifier => {
const mangled_name = scope.getAlias(slice);
return transCreateNodeIdentifier(c, checkForBuiltinTypedef(mangled_name) orelse mangled_name);
return Node.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name);
},
.LParen => {
const inner_node = try parseCExpr(c, m, scope);
@@ -4612,10 +4485,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
},
else => return inner_node,
}
// hack to get zig fmt to render a comma in builtin calls
_ = try appendToken(c, .Comma, ",");
const node_to_cast = try parseCExpr(c, m, scope);
if (saw_l_paren and m.next().? != .RParen) {
@@ -4623,28 +4492,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
return error.ParseError;
}
const lparen = try appendToken(c, .LParen, "(");
//(@import("std").meta.cast(dest, x))
const import_fn_call = try c.createBuiltinCall("@import", 1);
const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
import_fn_call.params()[0] = std_node;
import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "meta");
const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "cast");
const cast_fn_call = try c.createCall(outer_field_access, 2);
cast_fn_call.params()[0] = inner_node;
cast_fn_call.params()[1] = node_to_cast;
cast_fn_call.rtoken = try appendToken(c, .RParen, ")");
const group_node = try c.arena.create(ast.Node.GroupedExpression);
group_node.* = .{
.lparen = lparen,
.expr = &cast_fn_call.base,
.rparen = try appendToken(c, .RParen, ")"),
};
return &group_node.base;
return Node.std_meta_cast.create(c.arena, .{ .lhs = inner_node, .rhs = node_to_cast });
},
else => {
try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});
@@ -4653,447 +4501,255 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
}
}
fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCPrimaryExprInner(c, m, scope);
// In C the preprocessor would handle concatting strings while expanding macros.
// This should do approximately the same by concatting any strings and identifiers
// after a primary expression.
while (true) {
var op_token: ast.TokenIndex = undefined;
var op_id: ast.Node.Tag = undefined;
switch (m.peek().?) {
.StringLiteral, .Identifier => {},
else => break,
}
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = .ArrayCat },
.op_token = try appendToken(c, .PlusPlus, "++"),
.lhs = node,
.rhs = try parseCPrimaryExprInner(c, m, scope),
};
node = &op_node.base;
node = try Node.array_cat.create(c.arena, .{ .lhs = node, .rhs = try parseCPrimaryExprInner(c, m, scope) });
}
return node;
}
fn nodeIsInfixOp(tag: ast.Node.Tag) bool {
return switch (tag) {
.Add,
.AddWrap,
.ArrayCat,
.ArrayMult,
.Assign,
.AssignBitAnd,
.AssignBitOr,
.AssignBitShiftLeft,
.AssignBitShiftRight,
.AssignBitXor,
.AssignDiv,
.AssignSub,
.AssignSubWrap,
.AssignMod,
.AssignAdd,
.AssignAddWrap,
.AssignMul,
.AssignMulWrap,
.BangEqual,
.BitAnd,
.BitOr,
.BitShiftLeft,
.BitShiftRight,
.BitXor,
.BoolAnd,
.BoolOr,
.Div,
.EqualEqual,
.ErrorUnion,
.GreaterOrEqual,
.GreaterThan,
.LessOrEqual,
.LessThan,
.MergeErrorSets,
.Mod,
.Mul,
.MulWrap,
.Period,
.Range,
.Sub,
.SubWrap,
.UnwrapOptional,
.Catch,
=> true,
else => false,
};
}
fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
fn macroBoolToInt(c: *Context, node: Node) !Node {
if (!isBoolRes(node)) {
if (!nodeIsInfixOp(node.tag)) return node;
const group_node = try c.arena.create(ast.Node.GroupedExpression);
group_node.* = .{
.lparen = try appendToken(c, .LParen, "("),
.expr = node,
.rparen = try appendToken(c, .RParen, ")"),
};
return &group_node.base;
return node;
}
const builtin_node = try c.createBuiltinCall("@boolToInt", 1);
builtin_node.params()[0] = node;
builtin_node.rparen_token = try appendToken(c, .RParen, ")");
return &builtin_node.base;
return Node.bool_to_int.create(c.arena, node);
}
fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
fn macroIntToBool(c: *Context, node: Node) !Node {
if (isBoolRes(node)) {
if (!nodeIsInfixOp(node.tag)) return node;
const group_node = try c.arena.create(ast.Node.GroupedExpression);
group_node.* = .{
.lparen = try appendToken(c, .LParen, "("),
.expr = node,
.rparen = try appendToken(c, .RParen, ")"),
};
return &group_node.base;
return node;
}
const op_token = try appendToken(c, .BangEqual, "!=");
const zero = try transCreateNodeInt(c, 0);
const res = try c.arena.create(ast.Node.SimpleInfixOp);
res.* = .{
.base = .{ .tag = .BangEqual },
.op_token = op_token,
.lhs = node,
.rhs = zero,
};
const group_node = try c.arena.create(ast.Node.GroupedExpression);
group_node.* = .{
.lparen = try appendToken(c, .LParen, "("),
.expr = &res.base,
.rparen = try appendToken(c, .RParen, ")"),
};
return &group_node.base;
return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init() });
}
fn macroGroup(c: *Context, node: *ast.Node) !*ast.Node {
if (!nodeIsInfixOp(node.tag)) return node;
const group_node = try c.arena.create(ast.Node.GroupedExpression);
group_node.* = .{
.lparen = try appendToken(c, .LParen, "("),
.expr = node,
.rparen = try appendToken(c, .RParen, ")"),
};
return &group_node.base;
}
fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
const node = try parseCOrExpr(c, m, scope);
if (m.peek().? != .QuestionMark) {
return node;
}
_ = m.next();
// must come immediately after expr
_ = try appendToken(c, .RParen, ")");
const if_node = try transCreateNodeIf(c);
if_node.condition = node;
if_node.body = try parseCOrExpr(c, m, scope);
const then_body = try parseCOrExpr(c, m, scope);
if (m.next().? != .Colon) {
try m.fail(c, "unable to translate C expr: expected ':'", .{});
return error.ParseError;
}
if_node.@"else" = try transCreateNodeElse(c);
if_node.@"else".?.body = try parseCCondExpr(c, m, scope);
return &if_node.base;
const else_body = try parseCCondExpr(c, m, scope);
return Node.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });
}
fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCAndExpr(c, m, scope);
while (m.next().? == .PipePipe) {
const lhs_node = try macroIntToBool(c, node);
const op_token = try appendToken(c, .Keyword_or, "or");
const rhs_node = try parseCAndExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = .BoolOr },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroIntToBool(c, rhs_node),
};
node = &op_node.base;
const lhs = try macroIntToBool(c, node);
const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));
node = try Node.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
}
m.i -= 1;
return node;
}
fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCBitOrExpr(c, m, scope);
while (m.next().? == .AmpersandAmpersand) {
const lhs_node = try macroIntToBool(c, node);
const op_token = try appendToken(c, .Keyword_and, "and");
const rhs_node = try parseCBitOrExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = .BoolAnd },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroIntToBool(c, rhs_node),
};
node = &op_node.base;
const lhs = try macroIntToBool(c, node);
const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));
node = try Node.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
}
m.i -= 1;
return node;
}
fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCBitXorExpr(c, m, scope);
while (m.next().? == .Pipe) {
const lhs_node = try macroBoolToInt(c, node);
const op_token = try appendToken(c, .Pipe, "|");
const rhs_node = try parseCBitXorExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = .BitOr },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroBoolToInt(c, rhs_node),
};
node = &op_node.base;
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCBitXorExpr(c, m, scope));
node = try Node.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
}
m.i -= 1;
return node;
}
fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCBitAndExpr(c, m, scope);
while (m.next().? == .Caret) {
const lhs_node = try macroBoolToInt(c, node);
const op_token = try appendToken(c, .Caret, "^");
const rhs_node = try parseCBitAndExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = .BitXor },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroBoolToInt(c, rhs_node),
};
node = &op_node.base;
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCBitAndExpr(c, m, scope));
node = try Node.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
}
m.i -= 1;
return node;
}
fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCEqExpr(c, m, scope);
while (m.next().? == .Ampersand) {
const lhs_node = try macroBoolToInt(c, node);
const op_token = try appendToken(c, .Ampersand, "&");
const rhs_node = try parseCEqExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = .BitAnd },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroBoolToInt(c, rhs_node),
};
node = &op_node.base;
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCEqExpr(c, m, scope));
node = try Node.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
}
m.i -= 1;
return node;
}
fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCRelExpr(c, m, scope);
while (true) {
var op_token: ast.TokenIndex = undefined;
var op_id: ast.Node.Tag = undefined;
switch (m.peek().?) {
.BangEqual => {
op_token = try appendToken(c, .BangEqual, "!=");
op_id = .BangEqual;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCRelExpr(c, m, scope));
node = try Node.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
.EqualEqual => {
op_token = try appendToken(c, .EqualEqual, "==");
op_id = .EqualEqual;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCRelExpr(c, m, scope));
node = try Node.equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
else => return node,
}
_ = m.next();
const lhs_node = try macroBoolToInt(c, node);
const rhs_node = try parseCRelExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = op_id },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroBoolToInt(c, rhs_node),
};
node = &op_node.base;
}
}
fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCShiftExpr(c, m, scope);
while (true) {
var op_token: ast.TokenIndex = undefined;
var op_id: ast.Node.Tag = undefined;
switch (m.peek().?) {
.AngleBracketRight => {
op_token = try appendToken(c, .AngleBracketRight, ">");
op_id = .GreaterThan;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope));
node = try Node.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
.AngleBracketRightEqual => {
op_token = try appendToken(c, .AngleBracketRightEqual, ">=");
op_id = .GreaterOrEqual;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope));
node = try Node.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
.AngleBracketLeft => {
op_token = try appendToken(c, .AngleBracketLeft, "<");
op_id = .LessThan;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope));
node = try Node.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
.AngleBracketLeftEqual => {
op_token = try appendToken(c, .AngleBracketLeftEqual, "<=");
op_id = .LessOrEqual;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope));
node = try Node.less_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
else => return node,
}
_ = m.next();
const lhs_node = try macroBoolToInt(c, node);
const rhs_node = try parseCShiftExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = op_id },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroBoolToInt(c, rhs_node),
};
node = &op_node.base;
}
}
fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCAddSubExpr(c, m, scope);
while (true) {
var op_token: ast.TokenIndex = undefined;
var op_id: ast.Node.Tag = undefined;
switch (m.peek().?) {
.AngleBracketAngleBracketLeft => {
op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<");
op_id = .BitShiftLeft;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCAddSubExpr(c, m, scope));
node = try Node.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
.AngleBracketAngleBracketRight => {
op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>");
op_id = .BitShiftRight;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCAddSubExpr(c, m, scope));
node = try Node.shr.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
else => return node,
}
_ = m.next();
const lhs_node = try macroBoolToInt(c, node);
const rhs_node = try parseCAddSubExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = op_id },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroBoolToInt(c, rhs_node),
};
node = &op_node.base;
}
}
fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCMulExpr(c, m, scope);
while (true) {
var op_token: ast.TokenIndex = undefined;
var op_id: ast.Node.Tag = undefined;
switch (m.peek().?) {
.Plus => {
op_token = try appendToken(c, .Plus, "+");
op_id = .Add;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCMulExpr(c, m, scope));
node = try Node.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
.Minus => {
op_token = try appendToken(c, .Minus, "-");
op_id = .Sub;
_ = m.next();
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCMulExpr(c, m, scope));
node = try Node.sub.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
else => return node,
}
_ = m.next();
const lhs_node = try macroBoolToInt(c, node);
const rhs_node = try parseCMulExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = op_id },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroBoolToInt(c, rhs_node),
};
node = &op_node.base;
}
}
fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCUnaryExpr(c, m, scope);
while (true) {
var op_token: ast.TokenIndex = undefined;
var op_id: ast.Node.Tag = undefined;
switch (m.next().?) {
.Asterisk => {
if (m.peek().? == .RParen) {
// type *)
// hack to get zig fmt to render a comma in builtin calls
_ = try appendToken(c, .Comma, ",");
// last token of `node`
const prev_id = m.list[m.i - 1].id;
if (prev_id == .Keyword_void) {
const ptr = try transCreateNodePtrType(c, false, false, .Asterisk);
ptr.rhs = node;
const optional_node = try transCreateNodeSimplePrefixOp(c, .OptionalType, .QuestionMark, "?");
optional_node.rhs = &ptr.base;
return &optional_node.base;
const ptr = try Node.single_pointer.create(c.arena, .{
.is_const = false,
.is_volatile = false,
.elem_type = node,
});
return Node.optional_type.create(c.arena, ptr);
} else {
const ptr = try transCreateNodePtrType(c, false, false, Token.Id.Identifier);
ptr.rhs = node;
return &ptr.base;
return Node.c_pointer.create(c.arena, .{
.is_const = false,
.is_volatile = false,
.elem_type = node,
});
}
} else {
// expr * expr
op_token = try appendToken(c, .Asterisk, "*");
op_id = .BitShiftLeft;
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
node = try Node.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
}
},
.Slash => {
op_id = .Div;
op_token = try appendToken(c, .Slash, "/");
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
node = try Node.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
.Percent => {
op_id = .Mod;
op_token = try appendToken(c, .Percent, "%");
const lhs = try macroBoolToInt(c, node);
const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
node = try Node.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
},
else => {
m.i -= 1;
return node;
},
}
const lhs_node = try macroBoolToInt(c, node);
const rhs_node = try parseCUnaryExpr(c, m, scope);
const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
op_node.* = .{
.base = .{ .tag = op_id },
.op_token = op_token,
.lhs = lhs_node,
.rhs = try macroBoolToInt(c, rhs_node),
};
node = &op_node.base;
}
}
fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
var node = try parseCPrimaryExpr(c, m, scope);
while (true) {
switch (m.next().?) {
@@ -5103,38 +4759,31 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
return error.ParseError;
}
node = try transCreateNodeFieldAccess(c, node, m.slice());
continue;
const ident = try Node.identifier.create(c.arena, m.slice());
node = try Node.field_access.create(c.arena, .{ .lhs = node, .rhs = ident });
},
.Arrow => {
if (m.next().? != .Identifier) {
try m.fail(c, "unable to translate C expr: expected identifier", .{});
return error.ParseError;
}
const deref = try transCreateNodePtrDeref(c, node);
node = try transCreateNodeFieldAccess(c, deref, m.slice());
continue;
const deref = try Node.deref.create(c.arena, node);
const ident = try Node.identifier.create(c.arena, m.slice());
node = try Node.field_access.create(c.arena, .{ .lhs = deref, .rhs = ident });
},
.LBracket => {
const arr_node = try transCreateNodeArrayAccess(c, node);
arr_node.index_expr = try parseCExpr(c, m, scope);
arr_node.rtoken = try appendToken(c, .RBracket, "]");
node = &arr_node.base;
if (m.next().? != .RBracket) {
try m.fail(c, "unable to translate C expr: expected ']'", .{});
return error.ParseError;
}
continue;
const index = try macroBoolToInt(c, try parseCExpr(c, m, scope));
node = try Node.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
},
.LParen => {
_ = try appendToken(c, .LParen, "(");
var call_params = std.ArrayList(*ast.Node).init(c.gpa);
var call_params = std.ArrayList(Node).init(c.gpa);
defer call_params.deinit();
while (true) {
const arg = try parseCCondExpr(c, m, scope);
try call_params.append(arg);
switch (m.next().?) {
.Comma => _ = try appendToken(c, .Comma, ","),
.Comma => {},
.RParen => break,
else => {
try m.fail(c, "unable to translate C expr: expected ',' or ')'", .{});
@@ -5142,32 +4791,17 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
},
}
}
const call_node = try ast.Node.Call.alloc(c.arena, call_params.items.len);
call_node.* = .{
.lhs = node,
.params_len = call_params.items.len,
.async_token = null,
.rtoken = try appendToken(c, .RParen, ")"),
};
mem.copy(*ast.Node, call_node.params(), call_params.items);
node = &call_node.base;
continue;
node = try Node.call.create(c.arena, .{ .lhs = node, .rhs = try c.arena.dupe(Node, call_params.items) });
},
.LBrace => {
// must come immediately after `node`
_ = try appendToken(c, .Comma, ",");
const dot = try appendToken(c, .Period, ".");
_ = try appendToken(c, .LBrace, "{");
var init_vals = std.ArrayList(*ast.Node).init(c.gpa);
var init_vals = std.ArrayList(Node).init(c.gpa);
defer init_vals.deinit();
while (true) {
const val = try parseCCondExpr(c, m, scope);
try init_vals.append(val);
switch (m.next().?) {
.Comma => _ = try appendToken(c, .Comma, ","),
.Comma => {},
.RBrace => break,
else => {
try m.fail(c, "unable to translate C expr: expected ',' or '}}'", .{});
@@ -5175,29 +4809,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
},
}
}
const tuple_node = try ast.Node.StructInitializerDot.alloc(c.arena, init_vals.items.len);
tuple_node.* = .{
.dot = dot,
.list_len = init_vals.items.len,
.rtoken = try appendToken(c, .RBrace, "}"),
};
mem.copy(*ast.Node, tuple_node.list(), init_vals.items);
//(@import("std").mem.zeroInit(T, .{x}))
const import_fn_call = try c.createBuiltinCall("@import", 1);
const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
import_fn_call.params()[0] = std_node;
import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem");
const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroInit");
const zero_init_call = try c.createCall(outer_field_access, 2);
zero_init_call.params()[0] = node;
zero_init_call.params()[1] = &tuple_node.base;
zero_init_call.rtoken = try appendToken(c, .RParen, ")");
node = &zero_init_call.base;
continue;
const tuple_node = try Node.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));
node = try Node.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node });
},
.PlusPlus, .MinusMinus => {
try m.fail(c, "TODO postfix inc/dec expr", .{});
@@ -5211,35 +4824,31 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
}
}
fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
switch (m.next().?) {
.Bang => {
const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");
node.rhs = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
return &node.base;
const operand = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
return Node.not.create(c.arena, operand);
},
.Minus => {
const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");
node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
return &node.base;
const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
return Node.negate.create(c.arena, operand);
},
.Plus => return try parseCUnaryExpr(c, m, scope),
.Tilde => {
const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");
node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
return &node.base;
const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
return Node.bit_not.create(c.arena, operand);
},
.Asterisk => {
const node = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
return try transCreateNodePtrDeref(c, node);
const operand = try parseCUnaryExpr(c, m, scope);
return Node.deref.create(c.arena, operand);
},
.Ampersand => {
const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");
node.rhs = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
return &node.base;
const operand = try parseCUnaryExpr(c, m, scope);
return Node.address_of.create(c.arena, operand);
},
.Keyword_sizeof => {
const inner = if (m.peek().? == .LParen) blk: {
const operand = if (m.peek().? == .LParen) blk: {
_ = m.next();
// C grammar says this should be 'type-name' but we have to
// use parseCMulExpr to correctly handle pointer types.
@@ -5251,18 +4860,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
break :blk inner;
} else try parseCUnaryExpr(c, m, scope);
//(@import("std").meta.sizeof(dest, x))
const import_fn_call = try c.createBuiltinCall("@import", 1);
const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
import_fn_call.params()[0] = std_node;
import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "meta");
const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "sizeof");
const sizeof_call = try c.createCall(outer_field_access, 1);
sizeof_call.params()[0] = inner;
sizeof_call.rtoken = try appendToken(c, .RParen, ")");
return &sizeof_call.base;
return Node.std_meta_sizeof.create(c.arena, operand);
},
.Keyword_alignof => {
// TODO this won't work if using <stdalign.h>'s
@@ -5273,16 +4871,13 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
}
// C grammar says this should be 'type-name' but we have to
// use parseCMulExpr to correctly handle pointer types.
const inner = try parseCMulExpr(c, m, scope);
const operand = try parseCMulExpr(c, m, scope);
if (m.next().? != .RParen) {
try m.fail(c, "unable to translate C expr: expected ')'", .{});
return error.ParseError;
}
const builtin_call = try c.createBuiltinCall("@alignOf", 1);
builtin_call.params()[0] = inner;
builtin_call.rparen_token = try appendToken(c, .RParen, ")");
return &builtin_call.base;
return Node.alignof.create(c.arena, operand);
},
.PlusPlus, .MinusMinus => {
try m.fail(c, "TODO unary inc/dec expr", .{});
@@ -5295,50 +4890,40 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
}
}
fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
const tok = c.token_locs.items[token];
const slice = c.source_buffer.items[tok.start..tok.end];
return if (mem.startsWith(u8, slice, "@\""))
slice[2 .. slice.len - 1]
else
slice;
}
fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
switch (node.tag) {
.ContainerDecl,
.AddressOf,
.Await,
.BitNot,
.BoolNot,
.OptionalType,
.Negation,
.NegationWrap,
.Resume,
.Try,
.ArrayType,
.ArrayTypeSentinel,
.PtrType,
.SliceType,
fn getContainer(c: *Context, node: Node) ?Node {
switch (node.tag()) {
.@"union",
.@"struct",
.@"enum",
.address_of,
.bit_not,
.not,
.optional_type,
.negate,
.negate_wrap,
.array_type,
.c_pointer,
.single_pointer,
=> return node,
.Identifier => {
const ident = node.castTag(.Identifier).?;
if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
if (value.cast(ast.Node.VarDecl)) |var_decl|
return getContainer(c, var_decl.getInitNode().?);
.identifier => {
const ident = node.castTag(.identifier).?;
if (c.global_scope.sym_table.get(ident.data)) |value| {
if (value.castTag(.var_decl)) |var_decl|
return getContainer(c, var_decl.data.init);
if (value.castTag(.var_simple) orelse value.castTag(.pub_var_simple)) |var_decl|
return getContainer(c, var_decl.data.init);
}
},
.Period => {
const infix = node.castTag(.Period).?;
.field_access => {
const infix = node.castTag(.field_access).?;
if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
for (container.fieldsAndDecls()) |field_ref| {
const field = field_ref.cast(ast.Node.ContainerField).?;
const ident = infix.rhs.castTag(.Identifier).?;
if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
if (getContainerTypeOf(c, infix.data.lhs)) |ty_node| {
if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| {
for (container.data.fields) |field| {
const ident = infix.data.rhs.castTag(.identifier).?;
if (mem.eql(u8, field.data.name, field.data)) {
return getContainer(c, field.type_expr.?);
}
}
@@ -5351,22 +4936,20 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
return null;
}
fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
if (ref.castTag(.Identifier)) |ident| {
if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
if (value.cast(ast.Node.VarDecl)) |var_decl| {
if (var_decl.getTypeNode()) |ty|
return getContainer(c, ty);
fn getContainerTypeOf(c: *Context, ref: Node) ?Node {
if (ref.castTag(.identifier)) |ident| {
if (c.global_scope.sym_table.get(ident.data)) |value| {
if (value.castTag(.var_decl)) |var_decl| {
return getContainer(c, var_decl.data.type);
}
}
} else if (ref.castTag(.Period)) |infix| {
if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
for (container.fieldsAndDecls()) |field_ref| {
const field = field_ref.cast(ast.Node.ContainerField).?;
const ident = infix.rhs.castTag(.Identifier).?;
if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
return getContainer(c, field.type_expr.?);
} else if (ref.castTag(.field_access)) |infix| {
if (getContainerTypeOf(c, infix.data.lhs)) |ty_node| {
if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| {
for (container.data.fields) |field| {
const ident = infix.data.rhs.castTag(.identifier).?;
if (mem.eql(u8, field.name, ident.data)) {
return getContainer(c, field.type);
}
}
} else
@@ -5376,11 +4959,16 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
return null;
}
fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getInitNode().? else return null;
fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func {
const init = if (value.castTag(.var_decl)) |v|
v.data.init
else if (value.castTag(.var_simple) orelse value.castTag(.pub_var_simple)) |v|
v.data.init
else
return null;
if (getContainerTypeOf(c, init)) |ty_node| {
if (ty_node.castTag(.OptionalType)) |prefix| {
if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
if (ty_node.castTag(.optional_type)) |prefix| {
if (prefix.data.castTag(.func)) |fn_proto| {
return fn_proto;
}
}
+33 -8
View File
@@ -47,7 +47,6 @@ pub const Node = extern union {
field_access,
array_access,
call,
std_mem_zeroes,
var_decl,
func,
warning,
@@ -57,6 +56,7 @@ pub const Node = extern union {
@"struct",
@"union",
array_init,
tuple,
container_init,
std_meta_cast,
discard,
@@ -162,6 +162,8 @@ pub const Node = extern union {
deref,
block,
/// { operand }
block_single,
@"break",
sizeof,
@@ -173,8 +175,12 @@ pub const Node = extern union {
single_pointer,
array_type,
/// @import("std").mem.zeroes(T)
/// @import("std").meta.sizeof(operand)
std_meta_sizeof,
/// @import("std").mem.zeroes(operand)
std_mem_zeroes,
/// @import("std").mem.zeroInit(lhs, rhs)
std_mem_zeroinit,
// pub const name = @compileError(msg);
fail_decl,
// var actual = mangled;
@@ -188,6 +194,9 @@ pub const Node = extern union {
/// pub const enum_field_name = @enumToInt(enum_name.field_name);
enum_redecl,
/// pub inline fn name(params) return_type body
pub_inline_fn,
/// [0]type{}
empty_array,
/// [1]type{val} ** count
@@ -195,6 +204,7 @@ pub const Node = extern union {
/// _ = operand;
ignore,
@"anytype",
pub const last_no_payload_tag = Tag.usingnamespace_builtins;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -213,6 +223,7 @@ pub const Node = extern union {
.one_literal,
.void_type,
.noreturn_type,
.@"anytype",
=> @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
.std_mem_zeroes,
@@ -234,6 +245,7 @@ pub const Node = extern union {
.if_not_break,
.switch_else,
.ignore,
.block_single,
=> Payload.UnOp,
.add,
@@ -302,6 +314,8 @@ pub const Node = extern union {
.field_access,
.assign,
.align_cast,
.array_access,
.std_mem_zeroinit,
=> Payload.BinOp,
.number_literal,
@@ -325,7 +339,7 @@ pub const Node = extern union {
.func => Payload.Func,
.@"enum" => Payload.Enum,
.@"struct", .@"union" => Payload.Record,
.array_init => Payload.ArrayInit,
.array_init, .tuple => Payload.ArrayInit,
.container_init => Payload.ContainerInit,
.std_meta_cast => Payload.Infix,
.block => Payload.Block,
@@ -336,6 +350,7 @@ pub const Node = extern union {
.typedef, .pub_typedef, .var_simple, .pub_var_simple => Payload.SimpleVarDecl,
.enum_redecl => Payload.EnumRedecl,
.array_filler => Payload.ArrayFiller,
.pub_inline_fn => Payload.PubInlineFn,
};
}
@@ -488,12 +503,12 @@ pub const Payload = struct {
body: ?Node,
alignment: ?c_uint,
},
};
pub const Param = struct {
is_noalias: bool,
name: ?[]const u8,
type: Node,
};
pub const Param = struct {
is_noalias: bool,
name: ?[]const u8,
type: Node,
};
pub const Enum = struct {
@@ -598,6 +613,16 @@ pub const Payload = struct {
count: usize,
},
};
pub const PubInlineFn = struct {
base: Node,
data: struct {
name: []const u8,
params: []Param,
return_type: Node,
body: Node,
},
};
};
/// Converts the nodes into a Zig ast.