| author | |
| committer | |
| log | e64c0941f9cff66311c969b85be5fe5575c4ce45 |
| tree | a3417dd85241d55362433f41e00b72d4d2cba435 |
| parent | fa6e3eec464227a2c20ca949e2fd12f3ab649960 |
closes #86 files changed, 177 insertions(+), 56 deletions(-)
doc/langref.md+5-3| ... | ... | @@ -60,9 +60,11 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) |
| 60 | 60 | |
| 61 | 61 | ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis) |
| 62 | 62 | |
| 63 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompileTimeFnCall | |
| 63 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr | |
| 64 | 64 | |
| 65 | CompileTimeFnCall : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen) | |
| 65 | CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen) | |
| 66 | ||
| 67 | CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen) | |
| 66 | 68 | |
| 67 | 69 | PointerType : token(Ampersand) option(token(Const)) Type |
| 68 | 70 | |
| ... | ... | @@ -152,7 +154,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 152 | 154 | |
| 153 | 155 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const))) |
| 154 | 156 | |
| 155 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | |
| 157 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | |
| 156 | 158 | |
| 157 | 159 | StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) |
| 158 | 160 |
src/analyze.cpp+55-9| ... | ... | @@ -59,7 +59,8 @@ static AstNode *first_executing_node(AstNode *node) { |
| 59 | 59 | case NodeTypeStructValueExpr: |
| 60 | 60 | case NodeTypeStructValueField: |
| 61 | 61 | case NodeTypeWhileExpr: |
| 62 | case NodeTypeCompilerFnCall: | |
| 62 | case NodeTypeCompilerFnExpr: | |
| 63 | case NodeTypeCompilerFnType: | |
| 63 | 64 | return node; |
| 64 | 65 | } |
| 65 | 66 | zig_panic("unreachable"); |
| ... | ... | @@ -109,6 +110,20 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { |
| 109 | 110 | return entry; |
| 110 | 111 | } |
| 111 | 112 | |
| 113 | static TypeTableEntry *get_number_literal_type_unsigned(CodeGen *g, uint64_t x) { | |
| 114 | NumLit kind; | |
| 115 | if (x <= UINT8_MAX) { | |
| 116 | kind = NumLitU8; | |
| 117 | } else if (x <= UINT16_MAX) { | |
| 118 | kind = NumLitU16; | |
| 119 | } else if (x <= UINT32_MAX) { | |
| 120 | kind = NumLitU32; | |
| 121 | } else { | |
| 122 | kind = NumLitU64; | |
| 123 | } | |
| 124 | return g->num_lit_types[kind]; | |
| 125 | } | |
| 126 | ||
| 112 | 127 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 113 | 128 | TypeTableEntry **parent_pointer = is_const ? |
| 114 | 129 | &child_type->pointer_const_parent : |
| ... | ... | @@ -279,15 +294,16 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry |
| 279 | 294 | case AstNodeTypeTypeCompilerExpr: |
| 280 | 295 | { |
| 281 | 296 | AstNode *compiler_expr_node = node->data.type.compiler_expr; |
| 282 | Buf *fn_name = &compiler_expr_node->data.compiler_fn_call.name; | |
| 297 | Buf *fn_name = &compiler_expr_node->data.compiler_fn_expr.name; | |
| 283 | 298 | if (buf_eql_str(fn_name, "typeof")) { |
| 284 | return analyze_expression(g, import, context, nullptr, | |
| 285 | compiler_expr_node->data.compiler_fn_call.expr); | |
| 299 | type_node->entry = analyze_expression(g, import, context, nullptr, | |
| 300 | compiler_expr_node->data.compiler_fn_expr.expr); | |
| 286 | 301 | } else { |
| 287 | 302 | add_node_error(g, node, |
| 288 | 303 | buf_sprintf("invalid compiler function: '%s'", buf_ptr(fn_name))); |
| 289 | return g->builtin_types.entry_invalid; | |
| 304 | type_node->entry = g->builtin_types.entry_invalid; | |
| 290 | 305 | } |
| 306 | return type_node->entry; | |
| 291 | 307 | } |
| 292 | 308 | } |
| 293 | 309 | zig_unreachable(); |
| ... | ... | @@ -625,7 +641,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 625 | 641 | case NodeTypeStructField: |
| 626 | 642 | case NodeTypeStructValueExpr: |
| 627 | 643 | case NodeTypeStructValueField: |
| 628 | case NodeTypeCompilerFnCall: | |
| 644 | case NodeTypeCompilerFnExpr: | |
| 645 | case NodeTypeCompilerFnType: | |
| 629 | 646 | zig_unreachable(); |
| 630 | 647 | } |
| 631 | 648 | } |
| ... | ... | @@ -698,7 +715,8 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 698 | 715 | case NodeTypeStructField: |
| 699 | 716 | case NodeTypeStructValueExpr: |
| 700 | 717 | case NodeTypeStructValueField: |
| 701 | case NodeTypeCompilerFnCall: | |
| 718 | case NodeTypeCompilerFnExpr: | |
| 719 | case NodeTypeCompilerFnType: | |
| 702 | 720 | zig_unreachable(); |
| 703 | 721 | } |
| 704 | 722 | } |
| ... | ... | @@ -1580,6 +1598,30 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, |
| 1580 | 1598 | node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node); |
| 1581 | 1599 | } |
| 1582 | 1600 | |
| 1601 | static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 1602 | TypeTableEntry *expected_type, AstNode *node) | |
| 1603 | { | |
| 1604 | assert(node->type == NodeTypeCompilerFnType); | |
| 1605 | ||
| 1606 | Buf *name = &node->data.compiler_fn_type.name; | |
| 1607 | if (buf_eql_str(name, "sizeof")) { | |
| 1608 | TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context); | |
| 1609 | uint64_t size_in_bytes = type_entry->size_in_bits / 8; | |
| 1610 | ||
| 1611 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes); | |
| 1612 | ||
| 1613 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; | |
| 1614 | assert(!codegen_num_lit->resolved_type); | |
| 1615 | codegen_num_lit->resolved_type = resolve_type_compatibility(g, context, node, expected_type, num_lit_type); | |
| 1616 | ||
| 1617 | return num_lit_type; | |
| 1618 | } else { | |
| 1619 | add_node_error(g, node, | |
| 1620 | buf_sprintf("invalid compiler function: '%s'", buf_ptr(name))); | |
| 1621 | return g->builtin_types.entry_invalid; | |
| 1622 | } | |
| 1623 | } | |
| 1624 | ||
| 1583 | 1625 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1584 | 1626 | TypeTableEntry *expected_type, AstNode *node) |
| 1585 | 1627 | { |
| ... | ... | @@ -1852,6 +1894,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1852 | 1894 | case NodeTypeStructValueExpr: |
| 1853 | 1895 | return_type = analyze_struct_val_expr(g, import, context, expected_type, node); |
| 1854 | 1896 | break; |
| 1897 | case NodeTypeCompilerFnType: | |
| 1898 | return_type = analyze_compiler_fn_type(g, import, context, expected_type, node); | |
| 1899 | break; | |
| 1855 | 1900 | case NodeTypeDirective: |
| 1856 | 1901 | case NodeTypeFnDecl: |
| 1857 | 1902 | case NodeTypeFnProto: |
| ... | ... | @@ -1866,7 +1911,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1866 | 1911 | case NodeTypeStructDecl: |
| 1867 | 1912 | case NodeTypeStructField: |
| 1868 | 1913 | case NodeTypeStructValueField: |
| 1869 | case NodeTypeCompilerFnCall: | |
| 1914 | case NodeTypeCompilerFnExpr: | |
| 1870 | 1915 | zig_unreachable(); |
| 1871 | 1916 | } |
| 1872 | 1917 | assert(return_type); |
| ... | ... | @@ -2015,7 +2060,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 2015 | 2060 | case NodeTypeStructField: |
| 2016 | 2061 | case NodeTypeStructValueExpr: |
| 2017 | 2062 | case NodeTypeStructValueField: |
| 2018 | case NodeTypeCompilerFnCall: | |
| 2063 | case NodeTypeCompilerFnExpr: | |
| 2064 | case NodeTypeCompilerFnType: | |
| 2019 | 2065 | zig_unreachable(); |
| 2020 | 2066 | } |
| 2021 | 2067 | } |
src/codegen.cpp+56-26| ... | ... | @@ -1191,6 +1191,58 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { |
| 1191 | 1191 | node->codegen_node->expr_node.block_context, false, &init_val); |
| 1192 | 1192 | } |
| 1193 | 1193 | |
| 1194 | static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node, | |
| 1195 | NumberLiteralNode *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) | |
| 1196 | { | |
| 1197 | TypeTableEntry *type_entry = codegen_num_lit->resolved_type; | |
| 1198 | assert(type_entry); | |
| 1199 | ||
| 1200 | // override the expression type for number literals | |
| 1201 | source_node->codegen_node->expr_node.type_entry = type_entry; | |
| 1202 | ||
| 1203 | if (type_entry->id == TypeTableEntryIdInt) { | |
| 1204 | // here the union has int64_t and uint64_t and we purposefully read | |
| 1205 | // the uint64_t value in either case, because we want the twos | |
| 1206 | // complement representation | |
| 1207 | ||
| 1208 | return LLVMConstInt(type_entry->type_ref, | |
| 1209 | num_lit_node->data.x_uint, | |
| 1210 | type_entry->data.integral.is_signed); | |
| 1211 | } else if (type_entry->id == TypeTableEntryIdFloat) { | |
| 1212 | ||
| 1213 | return LLVMConstReal(type_entry->type_ref, | |
| 1214 | num_lit_node->data.x_float); | |
| 1215 | } else { | |
| 1216 | zig_panic("bad number literal type"); | |
| 1217 | } | |
| 1218 | } | |
| 1219 | ||
| 1220 | static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { | |
| 1221 | assert(node->type == NodeTypeCompilerFnType); | |
| 1222 | ||
| 1223 | Buf *name = &node->data.compiler_fn_type.name; | |
| 1224 | if (buf_eql_str(name, "sizeof")) { | |
| 1225 | TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type); | |
| 1226 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; | |
| 1227 | AstNodeNumberLiteral num_lit_node; | |
| 1228 | num_lit_node.kind = type_entry->data.num_lit.kind; | |
| 1229 | num_lit_node.overflow = false; | |
| 1230 | num_lit_node.data.x_uint = type_entry->size_in_bits / 8; | |
| 1231 | return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node); | |
| 1232 | } else { | |
| 1233 | zig_unreachable(); | |
| 1234 | } | |
| 1235 | } | |
| 1236 | ||
| 1237 | static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) { | |
| 1238 | assert(node->type == NodeTypeNumberLiteral); | |
| 1239 | ||
| 1240 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; | |
| 1241 | assert(codegen_num_lit); | |
| 1242 | ||
| 1243 | return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal); | |
| 1244 | } | |
| 1245 | ||
| 1194 | 1246 | static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1195 | 1247 | switch (node->type) { |
| 1196 | 1248 | case NodeTypeBinOpExpr: |
| ... | ... | @@ -1228,31 +1280,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1228 | 1280 | case NodeTypeAsmExpr: |
| 1229 | 1281 | return gen_asm_expr(g, node); |
| 1230 | 1282 | case NodeTypeNumberLiteral: |
| 1231 | { | |
| 1232 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; | |
| 1233 | assert(codegen_num_lit); | |
| 1234 | TypeTableEntry *type_entry = codegen_num_lit->resolved_type; | |
| 1235 | assert(type_entry); | |
| 1236 | ||
| 1237 | // override the expression type for number literals | |
| 1238 | node->codegen_node->expr_node.type_entry = type_entry; | |
| 1239 | ||
| 1240 | if (type_entry->id == TypeTableEntryIdInt) { | |
| 1241 | // here the union has int64_t and uint64_t and we purposefully read | |
| 1242 | // the uint64_t value in either case, because we want the twos | |
| 1243 | // complement representation | |
| 1244 | ||
| 1245 | return LLVMConstInt(type_entry->type_ref, | |
| 1246 | node->data.number_literal.data.x_uint, | |
| 1247 | type_entry->data.integral.is_signed); | |
| 1248 | } else if (type_entry->id == TypeTableEntryIdFloat) { | |
| 1249 | ||
| 1250 | return LLVMConstReal(type_entry->type_ref, | |
| 1251 | node->data.number_literal.data.x_float); | |
| 1252 | } else { | |
| 1253 | zig_panic("bad number literal type"); | |
| 1254 | } | |
| 1255 | } | |
| 1283 | return gen_number_literal(g, node); | |
| 1256 | 1284 | case NodeTypeStringLiteral: |
| 1257 | 1285 | { |
| 1258 | 1286 | Buf *str = &node->data.string_literal.buf; |
| ... | ... | @@ -1313,6 +1341,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1313 | 1341 | } |
| 1314 | 1342 | case NodeTypeStructValueExpr: |
| 1315 | 1343 | return gen_struct_val_expr(g, node); |
| 1344 | case NodeTypeCompilerFnType: | |
| 1345 | return gen_compiler_fn_type(g, node); | |
| 1316 | 1346 | case NodeTypeRoot: |
| 1317 | 1347 | case NodeTypeRootExportDecl: |
| 1318 | 1348 | case NodeTypeFnProto: |
| ... | ... | @@ -1326,7 +1356,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1326 | 1356 | case NodeTypeStructDecl: |
| 1327 | 1357 | case NodeTypeStructField: |
| 1328 | 1358 | case NodeTypeStructValueField: |
| 1329 | case NodeTypeCompilerFnCall: | |
| 1359 | case NodeTypeCompilerFnExpr: | |
| 1330 | 1360 | zig_unreachable(); |
| 1331 | 1361 | } |
| 1332 | 1362 | zig_unreachable(); |
src/parser.cpp+47-12| ... | ... | @@ -142,8 +142,10 @@ const char *node_type_str(NodeType node_type) { |
| 142 | 142 | return "StructValueExpr"; |
| 143 | 143 | case NodeTypeStructValueField: |
| 144 | 144 | return "StructValueField"; |
| 145 | case NodeTypeCompilerFnCall: | |
| 146 | return "CompilerFnCall"; | |
| 145 | case NodeTypeCompilerFnExpr: | |
| 146 | return "CompilerFnExpr"; | |
| 147 | case NodeTypeCompilerFnType: | |
| 148 | return "CompilerFnType"; | |
| 147 | 149 | } |
| 148 | 150 | zig_unreachable(); |
| 149 | 151 | } |
| ... | ... | @@ -410,7 +412,10 @@ void ast_print(AstNode *node, int indent) { |
| 410 | 412 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name)); |
| 411 | 413 | ast_print(node->data.struct_val_field.expr, indent + 2); |
| 412 | 414 | break; |
| 413 | case NodeTypeCompilerFnCall: | |
| 415 | case NodeTypeCompilerFnExpr: | |
| 416 | fprintf(stderr, "%s\n", node_type_str(node->type)); | |
| 417 | break; | |
| 418 | case NodeTypeCompilerFnType: | |
| 414 | 419 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 415 | 420 | break; |
| 416 | 421 | } |
| ... | ... | @@ -996,7 +1001,32 @@ static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNod |
| 996 | 1001 | } |
| 997 | 1002 | |
| 998 | 1003 | /* |
| 999 | CompileTimeFnCall : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen) | |
| 1004 | CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen) | |
| 1005 | */ | |
| 1006 | static AstNode *ast_parse_compiler_fn_type(ParseContext *pc, int *token_index, bool mandatory) { | |
| 1007 | Token *token = &pc->tokens->at(*token_index); | |
| 1008 | ||
| 1009 | if (token->id == TokenIdNumberSign) { | |
| 1010 | *token_index += 1; | |
| 1011 | } else if (mandatory) { | |
| 1012 | ast_invalid_token_error(pc, token); | |
| 1013 | } else { | |
| 1014 | return nullptr; | |
| 1015 | } | |
| 1016 | ||
| 1017 | Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); | |
| 1018 | ast_eat_token(pc, token_index, TokenIdLParen); | |
| 1019 | ||
| 1020 | AstNode *node = ast_create_node(pc, NodeTypeCompilerFnType, token); | |
| 1021 | ast_buf_from_token(pc, name_symbol, &node->data.compiler_fn_type.name); | |
| 1022 | node->data.compiler_fn_type.type = ast_parse_type(pc, token_index); | |
| 1023 | ||
| 1024 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 1025 | return node; | |
| 1026 | } | |
| 1027 | ||
| 1028 | /* | |
| 1029 | CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen) | |
| 1000 | 1030 | */ |
| 1001 | 1031 | static AstNode *ast_parse_compiler_fn_call(ParseContext *pc, int *token_index, bool mandatory) { |
| 1002 | 1032 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1012,16 +1042,16 @@ static AstNode *ast_parse_compiler_fn_call(ParseContext *pc, int *token_index, b |
| 1012 | 1042 | Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 1013 | 1043 | ast_eat_token(pc, token_index, TokenIdLParen); |
| 1014 | 1044 | |
| 1015 | AstNode *node = ast_create_node(pc, NodeTypeCompilerFnCall, token); | |
| 1016 | ast_buf_from_token(pc, name_symbol, &node->data.compiler_fn_call.name); | |
| 1017 | node->data.compiler_fn_call.expr = ast_parse_expression(pc, token_index, true); | |
| 1045 | AstNode *node = ast_create_node(pc, NodeTypeCompilerFnExpr, token); | |
| 1046 | ast_buf_from_token(pc, name_symbol, &node->data.compiler_fn_expr.name); | |
| 1047 | node->data.compiler_fn_expr.expr = ast_parse_expression(pc, token_index, true); | |
| 1018 | 1048 | |
| 1019 | 1049 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 1020 | 1050 | return node; |
| 1021 | 1051 | } |
| 1022 | 1052 | |
| 1023 | 1053 | /* |
| 1024 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompileTimeFnCall | |
| 1054 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr | |
| 1025 | 1055 | PointerType : token(Ampersand) option(token(Const)) Type |
| 1026 | 1056 | ArrayType : token(LBracket) Type token(Semicolon) token(Number) token(RBracket) |
| 1027 | 1057 | */ |
| ... | ... | @@ -1029,10 +1059,10 @@ static AstNode *ast_parse_type(ParseContext *pc, int *token_index) { |
| 1029 | 1059 | Token *token = &pc->tokens->at(*token_index); |
| 1030 | 1060 | AstNode *node = ast_create_node(pc, NodeTypeType, token); |
| 1031 | 1061 | |
| 1032 | AstNode *compiler_fn_call = ast_parse_compiler_fn_call(pc, token_index, false); | |
| 1033 | if (compiler_fn_call) { | |
| 1062 | AstNode *compiler_fn_expr = ast_parse_compiler_fn_call(pc, token_index, false); | |
| 1063 | if (compiler_fn_expr) { | |
| 1034 | 1064 | node->data.type.type = AstNodeTypeTypeCompilerExpr; |
| 1035 | node->data.type.compiler_expr = compiler_fn_call; | |
| 1065 | node->data.type.compiler_expr = compiler_fn_expr; | |
| 1036 | 1066 | return node; |
| 1037 | 1067 | } |
| 1038 | 1068 | |
| ... | ... | @@ -1238,7 +1268,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) { |
| 1238 | 1268 | } |
| 1239 | 1269 | |
| 1240 | 1270 | /* |
| 1241 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | |
| 1271 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | |
| 1242 | 1272 | */ |
| 1243 | 1273 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1244 | 1274 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1317,6 +1347,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1317 | 1347 | return block_expr_node; |
| 1318 | 1348 | } |
| 1319 | 1349 | |
| 1350 | AstNode *compiler_fn_type = ast_parse_compiler_fn_type(pc, token_index, false); | |
| 1351 | if (compiler_fn_type) { | |
| 1352 | return compiler_fn_type; | |
| 1353 | } | |
| 1354 | ||
| 1320 | 1355 | if (!mandatory) |
| 1321 | 1356 | return nullptr; |
| 1322 | 1357 |
src/parser.hpp+10-3| ... | ... | @@ -57,7 +57,8 @@ enum NodeType { |
| 57 | 57 | NodeTypeStructField, |
| 58 | 58 | NodeTypeStructValueExpr, |
| 59 | 59 | NodeTypeStructValueField, |
| 60 | NodeTypeCompilerFnCall, | |
| 60 | NodeTypeCompilerFnExpr, | |
| 61 | NodeTypeCompilerFnType, | |
| 61 | 62 | }; |
| 62 | 63 | |
| 63 | 64 | struct AstNodeRoot { |
| ... | ... | @@ -332,11 +333,16 @@ struct AstNodeStructValueExpr { |
| 332 | 333 | ZigList<AstNode *> fields; |
| 333 | 334 | }; |
| 334 | 335 | |
| 335 | struct AstNodeCompilerFnCall { | |
| 336 | struct AstNodeCompilerFnExpr { | |
| 336 | 337 | Buf name; |
| 337 | 338 | AstNode *expr; |
| 338 | 339 | }; |
| 339 | 340 | |
| 341 | struct AstNodeCompilerFnType { | |
| 342 | Buf name; | |
| 343 | AstNode *type; | |
| 344 | }; | |
| 345 | ||
| 340 | 346 | struct AstNode { |
| 341 | 347 | enum NodeType type; |
| 342 | 348 | int line; |
| ... | ... | @@ -376,7 +382,8 @@ struct AstNode { |
| 376 | 382 | AstNodeNumberLiteral number_literal; |
| 377 | 383 | AstNodeStructValueExpr struct_val_expr; |
| 378 | 384 | AstNodeStructValueField struct_val_field; |
| 379 | AstNodeCompilerFnCall compiler_fn_call; | |
| 385 | AstNodeCompilerFnExpr compiler_fn_expr; | |
| 386 | AstNodeCompilerFnType compiler_fn_type; | |
| 380 | 387 | Buf symbol; |
| 381 | 388 | bool bool_literal; |
| 382 | 389 | } data; |
test/run_tests.cpp+4-3| ... | ... | @@ -698,16 +698,17 @@ fn outer() -> isize { |
| 698 | 698 | } |
| 699 | 699 | )SOURCE", "OK\n"); |
| 700 | 700 | |
| 701 | add_simple_case("#typeof()", R"SOURCE( | |
| 701 | add_simple_case("#sizeof() and #typeof()", R"SOURCE( | |
| 702 | 702 | use "std.zig"; |
| 703 | 703 | const x: u16 = 13; |
| 704 | 704 | const z: #typeof(x) = 19; |
| 705 | 705 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 706 | 706 | const y: #typeof(x) = 120; |
| 707 | print_str("OK\n"); | |
| 707 | print_u64(#sizeof(#typeof(y))); | |
| 708 | print_str("\n"); | |
| 708 | 709 | return 0; |
| 709 | 710 | } |
| 710 | )SOURCE", "OK\n"); | |
| 711 | )SOURCE", "2\n"); | |
| 711 | 712 | } |
| 712 | 713 | |
| 713 | 714 | //////////////////////////////////////////////////////////////////////////////////// |