| ... | @@ -2585,11 +2585,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { | ... | @@ -2585,11 +2585,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 2585 | while (it.I != it_end.I) : (it.I += 1) { | 2585 | while (it.I != it_end.I) : (it.I += 1) { |
| 2586 | const entity = ZigClangPreprocessingRecord_iterator_deref(it); | 2586 | const entity = ZigClangPreprocessingRecord_iterator_deref(it); |
| 2587 | tok_list.shrink(0); | 2587 | tok_list.shrink(0); |
| 2588 | | | |
| 2589 | switch (ZigClangPreprocessedEntity_getKind(entity)) { | 2588 | switch (ZigClangPreprocessedEntity_getKind(entity)) { |
| 2590 | .MacroExpansionKind => { | | |
| 2591 | // TODO | | |
| 2592 | }, | | |
| 2593 | .MacroDefinitionKind => { | 2589 | .MacroDefinitionKind => { |
| 2594 | const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity); | 2590 | const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity); |
| 2595 | const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro); | 2591 | const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro); |
| ... | @@ -2599,54 +2595,64 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { | ... | @@ -2599,54 +2595,64 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 2599 | // if (name_exists_global(c, name)) { // TODO | 2595 | // if (name_exists_global(c, name)) { // TODO |
| 2600 | // continue; | 2596 | // continue; |
| 2601 | // } | 2597 | // } |
| 2602 | | | |
| 2603 | const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); | 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 | else => {}, | 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 { | 2646 | fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) ParseError!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 | }; | | |
| 2616 | const rp = makeRestorePoint(c); | 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 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | 2649 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 2639 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | 2650 | const mut_tok = try appendToken(c, .Keyword_const, "const"); |
| 2640 | const name_tok = try appendIdentifier(c, name); | 2651 | const name_tok = try appendIdentifier(c, name); |
| 2641 | | 2652 | |
| 2642 | const eq_tok = try appendToken(c, .Equal, "="); | 2653 | const eq_tok = try appendToken(c, .Equal, "="); |
| 2643 | | 2654 | |
| 2644 | const init_node = parseCExpr(rp, &it, source_loc) catch |err| switch (err) { | 2655 | const init_node = try parseCExpr(rp, it, source_loc); |
| 2645 | error.UnsupportedTranslation, | | |
| 2646 | error.ParseError, | | |
| 2647 | => return failDecl(c, source_loc, name, "unable to translate macro", .{}), | | |
| 2648 | error.OutOfMemory => |e| return e, | | |
| 2649 | }; | | |
| 2650 | | 2656 | |
| 2651 | const node = try c.a().create(ast.Node.VarDecl); | 2657 | const node = try c.a().create(ast.Node.VarDecl); |
| 2652 | node.* = ast.Node.VarDecl{ | 2658 | node.* = ast.Node.VarDecl{ |
| ... | @@ -2668,6 +2674,97 @@ fn transMacroDefine(c: *Context, tok_list: *ctok.TokenList, name: []const u8, ch | ... | @@ -2668,6 +2674,97 @@ fn transMacroDefine(c: *Context, tok_list: *ctok.TokenList, name: []const u8, ch |
| 2668 | _ = try c.macro_table.put(name, &node.base); | 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 | const ParseError = Error || error{ | 2768 | const ParseError = Error || error{ |
| 2672 | ParseError, | 2769 | ParseError, |
| 2673 | UnsupportedTranslation, | 2770 | UnsupportedTranslation, |
| ... | @@ -2762,14 +2859,14 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: | ... | @@ -2762,14 +2859,14 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: |
| 2762 | .LParen => { | 2859 | .LParen => { |
| 2763 | const inner_node = try parseCExpr(rp, it, source_loc); | 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 | if (it.peek().?.id == .RParen) { | 2862 | if (it.peek().?.id == .RParen) { |
| 2769 | _ = it.next(); | 2863 | _ = it.next(); |
| 2770 | return inner_node; | 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 | const node_to_cast = try parseCExpr(rp, it, source_loc); | 2870 | const node_to_cast = try parseCExpr(rp, it, source_loc); |
| 2774 | | 2871 | |
| 2775 | if (it.next().?.id != .RParen) { | 2872 | if (it.next().?.id != .RParen) { |
| ... | @@ -2879,7 +2976,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -2879,7 +2976,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 2879 | ); | 2976 | ); |
| 2880 | | 2977 | |
| 2881 | const op_token = try appendToken(rp.c, .Period, "."); | 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 | const access_node = try rp.c.a().create(ast.Node.InfixOp); | 2980 | const access_node = try rp.c.a().create(ast.Node.InfixOp); |
| 2884 | access_node.* = .{ | 2981 | access_node.* = .{ |
| 2885 | .op_token = op_token, | 2982 | .op_token = op_token, |
| ... | @@ -2975,7 +3072,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 { | ... | @@ -2975,7 +3072,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 { |
| 2975 | } | 3072 | } |
| 2976 | | 3073 | |
| 2977 | fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { | 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 | const name = if (init.cast(ast.Node.Identifier)) |id| | 3076 | const name = if (init.cast(ast.Node.Identifier)) |id| |
| 2980 | tokenSlice(c, id.token) | 3077 | tokenSlice(c, id.token) |
| 2981 | else | 3078 | else |