| ... | ... | @@ -2585,11 +2585,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 2585 | 2585 | while (it.I != it_end.I) : (it.I += 1) { |
| 2586 | 2586 | const entity = ZigClangPreprocessingRecord_iterator_deref(it); |
| 2587 | 2587 | tok_list.shrink(0); |
| 2588 | | |
| 2589 | 2588 | switch (ZigClangPreprocessedEntity_getKind(entity)) { |
| 2590 | | .MacroExpansionKind => { |
| 2591 | | // TODO |
| 2592 | | }, |
| 2593 | 2589 | .MacroDefinitionKind => { |
| 2594 | 2590 | const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity); |
| 2595 | 2591 | const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro); |
| ... | ... | @@ -2599,54 +2595,64 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 2599 | 2595 | // if (name_exists_global(c, name)) { // TODO |
| 2600 | 2596 | // continue; |
| 2601 | 2597 | // } |
| 2602 | | |
| 2603 | 2598 | const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); |
| 2604 | | try transMacroDefine(c, &tok_list, name, begin_c, begin_loc); |
| 2599 | ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) { |
| 2600 | error.OutOfMemory => |e| return e, |
| 2601 | else => { |
| 2602 | try failDecl(c, begin_loc, name, "unable to tokenize macro definition", .{}); |
| 2603 | continue; |
| 2604 | }, |
| 2605 | }; |
| 2606 | |
| 2607 | var tok_it = tok_list.iterator(0); |
| 2608 | const first_tok = tok_it.next().?; |
| 2609 | assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name)); |
| 2610 | const next = tok_it.peek().?; |
| 2611 | switch (next.id) { |
| 2612 | .Identifier => { |
| 2613 | // if it equals itself, ignore. for example, from stdio.h: |
| 2614 | // #define stdin stdin |
| 2615 | if (std.mem.eql(u8, name, next.bytes)) { |
| 2616 | continue; |
| 2617 | } |
| 2618 | }, |
| 2619 | .Eof => { |
| 2620 | // this means it is a macro without a value |
| 2621 | // we don't care about such things |
| 2622 | continue; |
| 2623 | }, |
| 2624 | else => {}, |
| 2625 | } |
| 2626 | const macro_fn = if (tok_it.peek().?.id == .Fn) blk: { |
| 2627 | _ = tok_it.next(); |
| 2628 | break :blk true; |
| 2629 | } else false; |
| 2630 | |
| 2631 | (if (macro_fn) |
| 2632 | transMacroFnDefine(c, &tok_it, name, begin_c, begin_loc) |
| 2633 | else |
| 2634 | transMacroDefine(c, &tok_it, name, begin_c, begin_loc)) catch |err| switch (err) { |
| 2635 | error.UnsupportedTranslation, |
| 2636 | error.ParseError, |
| 2637 | => try failDecl(c, begin_loc, name, "unable to translate macro", .{}), |
| 2638 | error.OutOfMemory => |e| return e, |
| 2639 | }; |
| 2605 | 2640 | }, |
| 2606 | 2641 | else => {}, |
| 2607 | 2642 | } |
| 2608 | 2643 | } |
| 2609 | 2644 | } |
| 2610 | 2645 | |
| 2611 | | fn transMacroDefine(c: *Context, tok_list: *ctok.TokenList, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) Error!void { |
| 2612 | | ctok.tokenizeCMacro(tok_list, char_ptr) catch |err| switch (err) { |
| 2613 | | error.OutOfMemory => |e| return e, |
| 2614 | | else => return failDecl(c, source_loc, name, "unable to tokenize macro definition", .{}), |
| 2615 | | }; |
| 2646 | fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) ParseError!void { |
| 2616 | 2647 | const rp = makeRestorePoint(c); |
| 2617 | 2648 | |
| 2618 | | var it = tok_list.iterator(0); |
| 2619 | | const first_tok = it.next().?; |
| 2620 | | assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name)); |
| 2621 | | const next = it.peek().?; |
| 2622 | | switch (next.id) { |
| 2623 | | .Identifier => { |
| 2624 | | // if it equals itself, ignore. for example, from stdio.h: |
| 2625 | | // #define stdin stdin |
| 2626 | | if (std.mem.eql(u8, name, next.bytes)) { |
| 2627 | | return; |
| 2628 | | } |
| 2629 | | }, |
| 2630 | | .Eof => { |
| 2631 | | // this means it is a macro without a value |
| 2632 | | // we don't care about such things |
| 2633 | | return; |
| 2634 | | }, |
| 2635 | | else => {}, |
| 2636 | | } |
| 2637 | | |
| 2638 | 2649 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 2639 | 2650 | const mut_tok = try appendToken(c, .Keyword_const, "const"); |
| 2640 | 2651 | const name_tok = try appendIdentifier(c, name); |
| 2641 | 2652 | |
| 2642 | 2653 | const eq_tok = try appendToken(c, .Equal, "="); |
| 2643 | 2654 | |
| 2644 | | const init_node = parseCExpr(rp, &it, source_loc) catch |err| switch (err) { |
| 2645 | | error.UnsupportedTranslation, |
| 2646 | | error.ParseError, |
| 2647 | | => return failDecl(c, source_loc, name, "unable to translate macro", .{}), |
| 2648 | | error.OutOfMemory => |e| return e, |
| 2649 | | }; |
| 2655 | const init_node = try parseCExpr(rp, it, source_loc); |
| 2650 | 2656 | |
| 2651 | 2657 | const node = try c.a().create(ast.Node.VarDecl); |
| 2652 | 2658 | node.* = ast.Node.VarDecl{ |
| ... | ... | @@ -2668,6 +2674,97 @@ fn transMacroDefine(c: *Context, tok_list: *ctok.TokenList, name: []const u8, ch |
| 2668 | 2674 | _ = try c.macro_table.put(name, &node.base); |
| 2669 | 2675 | } |
| 2670 | 2676 | |
| 2677 | fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) ParseError!void { |
| 2678 | const rp = makeRestorePoint(c); |
| 2679 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 2680 | const inline_tok = try appendToken(c, .Keyword_inline, "inline"); |
| 2681 | const fn_tok = try appendToken(c, .Keyword_fn, "fn"); |
| 2682 | const name_tok = try appendIdentifier(c, name); |
| 2683 | _ = try appendToken(c, .LParen, "("); |
| 2684 | |
| 2685 | if (it.next().?.id != .LParen) { |
| 2686 | return error.ParseError; |
| 2687 | } |
| 2688 | var fn_params = ast.Node.FnProto.ParamList.init(c.a()); |
| 2689 | while (true) { |
| 2690 | const param_tok = it.next().?; |
| 2691 | if (param_tok.id != .Identifier) |
| 2692 | return error.ParseError; |
| 2693 | |
| 2694 | // TODO avoid name collisions |
| 2695 | const param_name_tok = try appendIdentifier(c, param_tok.bytes); |
| 2696 | _ = try appendToken(c, .Colon, ":"); |
| 2697 | |
| 2698 | const token_index = try appendToken(c, .Keyword_var, "var"); |
| 2699 | const identifier = try c.a().create(ast.Node.Identifier); |
| 2700 | identifier.* = ast.Node.Identifier{ |
| 2701 | .base = ast.Node{ .id = ast.Node.Id.Identifier }, |
| 2702 | .token = token_index, |
| 2703 | }; |
| 2704 | |
| 2705 | const param_node = try c.a().create(ast.Node.ParamDecl); |
| 2706 | param_node.* = .{ |
| 2707 | .doc_comments = null, |
| 2708 | .comptime_token = null, |
| 2709 | .noalias_token = null, |
| 2710 | .name_token = param_name_tok, |
| 2711 | .type_node = &identifier.base, |
| 2712 | .var_args_token = null, |
| 2713 | }; |
| 2714 | try fn_params.push(&param_node.base); |
| 2715 | |
| 2716 | if (it.peek().?.id != .Comma) |
| 2717 | break; |
| 2718 | _ = it.next(); |
| 2719 | _ = try appendToken(c, .Comma, ","); |
| 2720 | } |
| 2721 | |
| 2722 | if (it.next().?.id != .RParen) { |
| 2723 | return error.ParseError; |
| 2724 | } |
| 2725 | |
| 2726 | _ = try appendToken(c, .RParen, ")"); |
| 2727 | |
| 2728 | const type_of = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); |
| 2729 | type_of.rparen_token = try appendToken(c, .LParen, ")"); |
| 2730 | |
| 2731 | const fn_proto = try c.a().create(ast.Node.FnProto); |
| 2732 | fn_proto.* = .{ |
| 2733 | .visib_token = pub_tok, |
| 2734 | .extern_export_inline_token = inline_tok, |
| 2735 | .fn_token = fn_tok, |
| 2736 | .name_token = name_tok, |
| 2737 | .params = fn_params, |
| 2738 | .return_type = .{ .Explicit = &type_of.base }, |
| 2739 | .doc_comments = null, |
| 2740 | .var_args_token = null, |
| 2741 | .cc_token = null, |
| 2742 | .body_node = null, |
| 2743 | .lib_name = null, |
| 2744 | .align_expr = null, |
| 2745 | .section_expr = null, |
| 2746 | }; |
| 2747 | |
| 2748 | const block = try c.a().create(ast.Node.Block); |
| 2749 | block.* = .{ |
| 2750 | .label = null, |
| 2751 | .lbrace = try appendToken(c, .LBrace, "{"), |
| 2752 | .statements = ast.Node.Block.StatementList.init(c.a()), |
| 2753 | .rbrace = undefined, |
| 2754 | }; |
| 2755 | |
| 2756 | const return_expr = try transCreateNodeReturnExpr(c); |
| 2757 | const expr = try parseCExpr(rp, it, source_loc); |
| 2758 | _ = try appendToken(c, .Semicolon, ";"); |
| 2759 | try type_of.params.push(expr); |
| 2760 | return_expr.rhs = expr; |
| 2761 | |
| 2762 | block.rbrace = try appendToken(c, .RBrace, "}"); |
| 2763 | try block.statements.push(&return_expr.base); |
| 2764 | fn_proto.body_node = &block.base; |
| 2765 | _ = try c.macro_table.put(name, &fn_proto.base); |
| 2766 | } |
| 2767 | |
| 2671 | 2768 | const ParseError = Error || error{ |
| 2672 | 2769 | ParseError, |
| 2673 | 2770 | UnsupportedTranslation, |
| ... | ... | @@ -2762,14 +2859,14 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: |
| 2762 | 2859 | .LParen => { |
| 2763 | 2860 | const inner_node = try parseCExpr(rp, it, source_loc); |
| 2764 | 2861 | |
| 2765 | | // hack to get zig fmt to render a comma in builtin calls |
| 2766 | | _ = try appendToken(rp.c, .Comma, ","); |
| 2767 | | |
| 2768 | 2862 | if (it.peek().?.id == .RParen) { |
| 2769 | 2863 | _ = it.next(); |
| 2770 | 2864 | return inner_node; |
| 2771 | 2865 | } |
| 2772 | 2866 | |
| 2867 | // hack to get zig fmt to render a comma in builtin calls |
| 2868 | _ = try appendToken(rp.c, .Comma, ","); |
| 2869 | |
| 2773 | 2870 | const node_to_cast = try parseCExpr(rp, it, source_loc); |
| 2774 | 2871 | |
| 2775 | 2872 | if (it.next().?.id != .RParen) { |
| ... | ... | @@ -2879,7 +2976,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 2879 | 2976 | ); |
| 2880 | 2977 | |
| 2881 | 2978 | const op_token = try appendToken(rp.c, .Period, "."); |
| 2882 | | const rhs = try transCreateNodeIdentifier(rp.c, tok.bytes); |
| 2979 | const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes); |
| 2883 | 2980 | const access_node = try rp.c.a().create(ast.Node.InfixOp); |
| 2884 | 2981 | access_node.* = .{ |
| 2885 | 2982 | .op_token = op_token, |
| ... | ... | @@ -2975,7 +3072,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 { |
| 2975 | 3072 | } |
| 2976 | 3073 | |
| 2977 | 3074 | fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { |
| 2978 | | const init = ref.cast(ast.Node.VarDecl).?.init_node.?; |
| 3075 | const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null; |
| 2979 | 3076 | const name = if (init.cast(ast.Node.Identifier)) |id| |
| 2980 | 3077 | tokenSlice(c, id.token) |
| 2981 | 3078 | else |