authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-03 18:17:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-03 18:17:50-07:00
logfa6e3eec464227a2c20ca949e2fd12f3ab649960
tree6ac09e0230a70cd9473f067fb6fe50f55c614594
parentb453345554cf7a48061e0cb43a6e8b45641cb4c3

add #typeof() compiler function


8 files changed, 148 insertions(+), 29 deletions(-)

doc/langref.md+3-1
...@@ -60,7 +60,9 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)...@@ -60,7 +60,9 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
6060
61ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis)61ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis)
6262
63Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType63Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompileTimeFnCall
64
65CompileTimeFnCall : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
6466
65PointerType : token(Ampersand) option(token(Const)) Type67PointerType : token(Ampersand) option(token(Const)) Type
6668
example/rand/main.zig+1-1
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2const ARRAY_SIZE : u16 = 624;2const ARRAY_SIZE : u16 = 624;
33
4/// Use `rand_init` to initialize this state.4/// Use `rand_init` to initialize this state.
5pub struct Rand {5struct Rand {
6 array: [u32; ARRAY_SIZE],6 array: [u32; ARRAY_SIZE],
7 index: #typeof(ARRAY_SIZE),7 index: #typeof(ARRAY_SIZE),
88
src/analyze.cpp+34-14
...@@ -59,6 +59,7 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -59,6 +59,7 @@ static AstNode *first_executing_node(AstNode *node) {
59 case NodeTypeStructValueExpr:59 case NodeTypeStructValueExpr:
60 case NodeTypeStructValueField:60 case NodeTypeStructValueField:
61 case NodeTypeWhileExpr:61 case NodeTypeWhileExpr:
62 case NodeTypeCompilerFnCall:
62 return node;63 return node;
63 }64 }
64 zig_panic("unreachable");65 zig_panic("unreachable");
...@@ -208,7 +209,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, ui...@@ -208,7 +209,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, ui
208 }209 }
209}210}
210211
211static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {212static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import, BlockContext *context) {
212 assert(node->type == NodeTypeType);213 assert(node->type == NodeTypeType);
213 alloc_codegen_node(node);214 alloc_codegen_node(node);
214 TypeNode *type_node = &node->codegen_node->data.type_node;215 TypeNode *type_node = &node->codegen_node->data.type_node;
...@@ -228,7 +229,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {...@@ -228,7 +229,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
228 }229 }
229 case AstNodeTypeTypePointer:230 case AstNodeTypeTypePointer:
230 {231 {
231 resolve_type(g, node->data.type.child_type);232 resolve_type(g, node->data.type.child_type, import, context);
232 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;233 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
233 assert(child_type);234 assert(child_type);
234 if (child_type->id == TypeTableEntryIdUnreachable) {235 if (child_type->id == TypeTableEntryIdUnreachable) {
...@@ -242,7 +243,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {...@@ -242,7 +243,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
242 }243 }
243 case AstNodeTypeTypeArray:244 case AstNodeTypeTypeArray:
244 {245 {
245 resolve_type(g, node->data.type.child_type);246 resolve_type(g, node->data.type.child_type, import, context);
246 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;247 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
247 if (child_type->id == TypeTableEntryIdUnreachable) {248 if (child_type->id == TypeTableEntryIdUnreachable) {
248 add_node_error(g, node,249 add_node_error(g, node,
...@@ -263,7 +264,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {...@@ -263,7 +264,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
263 }264 }
264 case AstNodeTypeTypeMaybe:265 case AstNodeTypeTypeMaybe:
265 {266 {
266 resolve_type(g, node->data.type.child_type);267 resolve_type(g, node->data.type.child_type, import, context);
267 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;268 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
268 assert(child_type);269 assert(child_type);
269 if (child_type->id == TypeTableEntryIdUnreachable) {270 if (child_type->id == TypeTableEntryIdUnreachable) {
...@@ -275,11 +276,26 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {...@@ -275,11 +276,26 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
275 type_node->entry = get_maybe_type(g, child_type);276 type_node->entry = get_maybe_type(g, child_type);
276 return type_node->entry;277 return type_node->entry;
277 }278 }
279 case AstNodeTypeTypeCompilerExpr:
280 {
281 AstNode *compiler_expr_node = node->data.type.compiler_expr;
282 Buf *fn_name = &compiler_expr_node->data.compiler_fn_call.name;
283 if (buf_eql_str(fn_name, "typeof")) {
284 return analyze_expression(g, import, context, nullptr,
285 compiler_expr_node->data.compiler_fn_call.expr);
286 } else {
287 add_node_error(g, node,
288 buf_sprintf("invalid compiler function: '%s'", buf_ptr(fn_name)));
289 return g->builtin_types.entry_invalid;
290 }
291 }
278 }292 }
279 zig_unreachable();293 zig_unreachable();
280}294}
281295
282static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {296static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
297 ImportTableEntry *import)
298{
283 assert(node->type == NodeTypeFnProto);299 assert(node->type == NodeTypeFnProto);
284300
285 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {301 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
...@@ -310,7 +326,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -310,7 +326,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
310 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {326 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
311 AstNode *child = node->data.fn_proto.params.at(i);327 AstNode *child = node->data.fn_proto.params.at(i);
312 assert(child->type == NodeTypeParamDecl);328 assert(child->type == NodeTypeParamDecl);
313 TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type);329 TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type, import, import->block_context);
314 if (type_entry->id == TypeTableEntryIdUnreachable) {330 if (type_entry->id == TypeTableEntryIdUnreachable) {
315 add_node_error(g, child->data.param_decl.type,331 add_node_error(g, child->data.param_decl.type,
316 buf_sprintf("parameter of type 'unreachable' not allowed"));332 buf_sprintf("parameter of type 'unreachable' not allowed"));
...@@ -322,7 +338,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -322,7 +338,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
322 }338 }
323 }339 }
324340
325 resolve_type(g, node->data.fn_proto.return_type);341 resolve_type(g, node->data.fn_proto.return_type, import, import->block_context);
326}342}
327343
328static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {344static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {
...@@ -383,7 +399,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE...@@ -383,7 +399,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
383 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);399 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
384 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];400 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
385 type_struct_field->name = &field_node->data.struct_field.name;401 type_struct_field->name = &field_node->data.struct_field.name;
386 type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type);402 type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type, import, import->block_context);
387403
388 if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) {404 if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) {
389 resolve_struct_type(g, import, type_struct_field->type_entry);405 resolve_struct_type(g, import, type_struct_field->type_entry);
...@@ -453,7 +469,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -453,7 +469,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
453 fn_table_entry->import_entry = import;469 fn_table_entry->import_entry = import;
454 fn_table_entry->label_table.init(8);470 fn_table_entry->label_table.init(8);
455471
456 resolve_function_proto(g, fn_proto, fn_table_entry);472 resolve_function_proto(g, fn_proto, fn_table_entry, import);
457473
458 Buf *name = &fn_proto->data.fn_proto.name;474 Buf *name = &fn_proto->data.fn_proto.name;
459 g->fn_protos.append(fn_table_entry);475 g->fn_protos.append(fn_table_entry);
...@@ -512,7 +528,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -512,7 +528,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
512 g->fn_table.put(proto_name, fn_table_entry);528 g->fn_table.put(proto_name, fn_table_entry);
513 }529 }
514530
515 resolve_function_proto(g, proto_node, fn_table_entry);531 resolve_function_proto(g, proto_node, fn_table_entry, import);
516532
517533
518 alloc_codegen_node(proto_node);534 alloc_codegen_node(proto_node);
...@@ -609,6 +625,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -609,6 +625,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
609 case NodeTypeStructField:625 case NodeTypeStructField:
610 case NodeTypeStructValueExpr:626 case NodeTypeStructValueExpr:
611 case NodeTypeStructValueField:627 case NodeTypeStructValueField:
628 case NodeTypeCompilerFnCall:
612 zig_unreachable();629 zig_unreachable();
613 }630 }
614}631}
...@@ -681,6 +698,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {...@@ -681,6 +698,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
681 case NodeTypeStructField:698 case NodeTypeStructField:
682 case NodeTypeStructValueExpr:699 case NodeTypeStructValueExpr:
683 case NodeTypeStructValueField:700 case NodeTypeStructValueField:
701 case NodeTypeCompilerFnCall:
684 zig_unreachable();702 zig_unreachable();
685 }703 }
686}704}
...@@ -1132,7 +1150,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {...@@ -1132,7 +1150,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
1132static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,1150static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1133 TypeTableEntry *expected_type, AstNode *node)1151 TypeTableEntry *expected_type, AstNode *node)
1134{1152{
1135 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type);1153 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context);
1136 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);1154 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);
11371155
1138 if (wanted_type->id == TypeTableEntryIdInvalid ||1156 if (wanted_type->id == TypeTableEntryIdInvalid ||
...@@ -1328,7 +1346,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa...@@ -1328,7 +1346,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
1328{1346{
1329 TypeTableEntry *explicit_type = nullptr;1347 TypeTableEntry *explicit_type = nullptr;
1330 if (variable_declaration->type != nullptr) {1348 if (variable_declaration->type != nullptr) {
1331 explicit_type = resolve_type(g, variable_declaration->type);1349 explicit_type = resolve_type(g, variable_declaration->type, import, context);
1332 if (explicit_type->id == TypeTableEntryIdUnreachable) {1350 if (explicit_type->id == TypeTableEntryIdUnreachable) {
1333 add_node_error(g, variable_declaration->type,1351 add_node_error(g, variable_declaration->type,
1334 buf_sprintf("variable of type 'unreachable' not allowed"));1352 buf_sprintf("variable of type 'unreachable' not allowed"));
...@@ -1428,7 +1446,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp...@@ -1428,7 +1446,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp
14281446
1429 AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr;1447 AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr;
14301448
1431 TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type);1449 TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type, import, context);
14321450
1433 if (type_entry->id == TypeTableEntryIdInvalid) {1451 if (type_entry->id == TypeTableEntryIdInvalid) {
1434 return g->builtin_types.entry_invalid;1452 return g->builtin_types.entry_invalid;
...@@ -1655,7 +1673,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1655,7 +1673,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1655 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);1673 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
1656 if (asm_output->return_type) {1674 if (asm_output->return_type) {
1657 node->data.asm_expr.return_count += 1;1675 node->data.asm_expr.return_count += 1;
1658 return_type = resolve_type(g, asm_output->return_type);1676 return_type = resolve_type(g, asm_output->return_type, import, context);
1659 if (node->data.asm_expr.return_count > 1) {1677 if (node->data.asm_expr.return_count > 1) {
1660 add_node_error(g, node,1678 add_node_error(g, node,
1661 buf_sprintf("inline assembly allows up to one output value"));1679 buf_sprintf("inline assembly allows up to one output value"));
...@@ -1848,6 +1866,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1848,6 +1866,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1848 case NodeTypeStructDecl:1866 case NodeTypeStructDecl:
1849 case NodeTypeStructField:1867 case NodeTypeStructField:
1850 case NodeTypeStructValueField:1868 case NodeTypeStructValueField:
1869 case NodeTypeCompilerFnCall:
1851 zig_unreachable();1870 zig_unreachable();
1852 }1871 }
1853 assert(return_type);1872 assert(return_type);
...@@ -1996,6 +2015,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -1996,6 +2015,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
1996 case NodeTypeStructField:2015 case NodeTypeStructField:
1997 case NodeTypeStructValueExpr:2016 case NodeTypeStructValueExpr:
1998 case NodeTypeStructValueField:2017 case NodeTypeStructValueField:
2018 case NodeTypeCompilerFnCall:
1999 zig_unreachable();2019 zig_unreachable();
2000 }2020 }
2001}2021}
src/analyze.hpp+2
...@@ -159,9 +159,11 @@ struct CodeGen {...@@ -159,9 +159,11 @@ struct CodeGen {
159 struct {159 struct {
160 TypeTableEntry *entry_bool;160 TypeTableEntry *entry_bool;
161 TypeTableEntry *entry_u8;161 TypeTableEntry *entry_u8;
162 TypeTableEntry *entry_u16;
162 TypeTableEntry *entry_u32;163 TypeTableEntry *entry_u32;
163 TypeTableEntry *entry_u64;164 TypeTableEntry *entry_u64;
164 TypeTableEntry *entry_i8;165 TypeTableEntry *entry_i8;
166 TypeTableEntry *entry_i16;
165 TypeTableEntry *entry_i32;167 TypeTableEntry *entry_i32;
166 TypeTableEntry *entry_i64;168 TypeTableEntry *entry_i64;
167 TypeTableEntry *entry_isize;169 TypeTableEntry *entry_isize;
src/codegen.cpp+27
...@@ -1326,6 +1326,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1326,6 +1326,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1326 case NodeTypeStructDecl:1326 case NodeTypeStructDecl:
1327 case NodeTypeStructField:1327 case NodeTypeStructField:
1328 case NodeTypeStructValueField:1328 case NodeTypeStructValueField:
1329 case NodeTypeCompilerFnCall:
1329 zig_unreachable();1330 zig_unreachable();
1330 }1331 }
1331 zig_unreachable();1332 zig_unreachable();
...@@ -1685,6 +1686,19 @@ static void define_builtin_types(CodeGen *g) {...@@ -1685,6 +1686,19 @@ static void define_builtin_types(CodeGen *g) {
1685 g->type_table.put(&entry->name, entry);1686 g->type_table.put(&entry->name, entry);
1686 g->builtin_types.entry_u8 = entry;1687 g->builtin_types.entry_u8 = entry;
1687 }1688 }
1689 {
1690 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1691 entry->type_ref = LLVMInt16Type();
1692 buf_init_from_str(&entry->name, "u16");
1693 entry->size_in_bits = 16;
1694 entry->align_in_bits = 16;
1695 entry->data.integral.is_signed = false;
1696 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1697 entry->size_in_bits, entry->align_in_bits,
1698 LLVMZigEncoding_DW_ATE_unsigned());
1699 g->type_table.put(&entry->name, entry);
1700 g->builtin_types.entry_u16 = entry;
1701 }
1688 {1702 {
1689 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);1703 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1690 entry->type_ref = LLVMInt32Type();1704 entry->type_ref = LLVMInt32Type();
...@@ -1725,6 +1739,19 @@ static void define_builtin_types(CodeGen *g) {...@@ -1725,6 +1739,19 @@ static void define_builtin_types(CodeGen *g) {
1725 g->type_table.put(&entry->name, entry);1739 g->type_table.put(&entry->name, entry);
1726 g->builtin_types.entry_i8 = entry;1740 g->builtin_types.entry_i8 = entry;
1727 }1741 }
1742 {
1743 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1744 entry->type_ref = LLVMInt16Type();
1745 buf_init_from_str(&entry->name, "i16");
1746 entry->size_in_bits = 16;
1747 entry->align_in_bits = 16;
1748 entry->data.integral.is_signed = true;
1749 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1750 entry->size_in_bits, entry->align_in_bits,
1751 LLVMZigEncoding_DW_ATE_signed());
1752 g->type_table.put(&entry->name, entry);
1753 g->builtin_types.entry_i16 = entry;
1754 }
1728 {1755 {
1729 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);1756 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1730 entry->type_ref = LLVMInt32Type();1757 entry->type_ref = LLVMInt32Type();
src/parser.cpp+46-3
...@@ -142,6 +142,8 @@ const char *node_type_str(NodeType node_type) {...@@ -142,6 +142,8 @@ const char *node_type_str(NodeType node_type) {
142 return "StructValueExpr";142 return "StructValueExpr";
143 case NodeTypeStructValueField:143 case NodeTypeStructValueField:
144 return "StructValueField";144 return "StructValueField";
145 case NodeTypeCompilerFnCall:
146 return "CompilerFnCall";
145 }147 }
146 zig_unreachable();148 zig_unreachable();
147}149}
...@@ -233,6 +235,12 @@ void ast_print(AstNode *node, int indent) {...@@ -233,6 +235,12 @@ void ast_print(AstNode *node, int indent) {
233 ast_print(node->data.type.child_type, indent + 2);235 ast_print(node->data.type.child_type, indent + 2);
234 break;236 break;
235 }237 }
238 case AstNodeTypeTypeCompilerExpr:
239 {
240 fprintf(stderr, "CompilerExprType\n");
241 ast_print(node->data.type.compiler_expr, indent + 2);
242 break;
243 }
236 }244 }
237 break;245 break;
238 case NodeTypeReturnExpr:246 case NodeTypeReturnExpr:
...@@ -402,6 +410,9 @@ void ast_print(AstNode *node, int indent) {...@@ -402,6 +410,9 @@ void ast_print(AstNode *node, int indent) {
402 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name));410 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name));
403 ast_print(node->data.struct_val_field.expr, indent + 2);411 ast_print(node->data.struct_val_field.expr, indent + 2);
404 break;412 break;
413 case NodeTypeCompilerFnCall:
414 fprintf(stderr, "%s\n", node_type_str(node->type));
415 break;
405 }416 }
406}417}
407418
...@@ -985,16 +996,48 @@ static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNod...@@ -985,16 +996,48 @@ static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNod
985}996}
986997
987/*998/*
988Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType999CompileTimeFnCall : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
1000*/
1001static AstNode *ast_parse_compiler_fn_call(ParseContext *pc, int *token_index, bool mandatory) {
1002 Token *token = &pc->tokens->at(*token_index);
1003
1004 if (token->id == TokenIdNumberSign) {
1005 *token_index += 1;
1006 } else if (mandatory) {
1007 ast_invalid_token_error(pc, token);
1008 } else {
1009 return nullptr;
1010 }
1011
1012 Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
1013 ast_eat_token(pc, token_index, TokenIdLParen);
1014
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);
1018
1019 ast_eat_token(pc, token_index, TokenIdRParen);
1020 return node;
1021}
1022
1023/*
1024Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompileTimeFnCall
989PointerType : token(Ampersand) option(token(Const)) Type1025PointerType : token(Ampersand) option(token(Const)) Type
990ArrayType : token(LBracket) Type token(Semicolon) token(Number) token(RBracket)1026ArrayType : token(LBracket) Type token(Semicolon) token(Number) token(RBracket)
991*/1027*/
992static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {1028static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {
993 Token *token = &pc->tokens->at(*token_index);1029 Token *token = &pc->tokens->at(*token_index);
994 *token_index += 1;
995
996 AstNode *node = ast_create_node(pc, NodeTypeType, token);1030 AstNode *node = ast_create_node(pc, NodeTypeType, token);
9971031
1032 AstNode *compiler_fn_call = ast_parse_compiler_fn_call(pc, token_index, false);
1033 if (compiler_fn_call) {
1034 node->data.type.type = AstNodeTypeTypeCompilerExpr;
1035 node->data.type.compiler_expr = compiler_fn_call;
1036 return node;
1037 }
1038
1039 *token_index += 1;
1040
998 if (token->id == TokenIdKeywordUnreachable) {1041 if (token->id == TokenIdKeywordUnreachable) {
999 node->data.type.type = AstNodeTypeTypePrimitive;1042 node->data.type.type = AstNodeTypeTypePrimitive;
1000 buf_init_from_str(&node->data.type.primitive_name, "unreachable");1043 buf_init_from_str(&node->data.type.primitive_name, "unreachable");
src/parser.hpp+9
...@@ -57,6 +57,7 @@ enum NodeType {...@@ -57,6 +57,7 @@ enum NodeType {
57 NodeTypeStructField,57 NodeTypeStructField,
58 NodeTypeStructValueExpr,58 NodeTypeStructValueExpr,
59 NodeTypeStructValueField,59 NodeTypeStructValueField,
60 NodeTypeCompilerFnCall,
60};61};
6162
62struct AstNodeRoot {63struct AstNodeRoot {
...@@ -97,6 +98,7 @@ enum AstNodeTypeType {...@@ -97,6 +98,7 @@ enum AstNodeTypeType {
97 AstNodeTypeTypePointer,98 AstNodeTypeTypePointer,
98 AstNodeTypeTypeArray,99 AstNodeTypeTypeArray,
99 AstNodeTypeTypeMaybe,100 AstNodeTypeTypeMaybe,
101 AstNodeTypeTypeCompilerExpr,
100};102};
101103
102struct AstNodeType {104struct AstNodeType {
...@@ -105,6 +107,7 @@ struct AstNodeType {...@@ -105,6 +107,7 @@ struct AstNodeType {
105 AstNode *child_type;107 AstNode *child_type;
106 AstNode *array_size;108 AstNode *array_size;
107 bool is_const;109 bool is_const;
110 AstNode *compiler_expr;
108};111};
109112
110struct AstNodeBlock {113struct AstNodeBlock {
...@@ -329,6 +332,11 @@ struct AstNodeStructValueExpr {...@@ -329,6 +332,11 @@ struct AstNodeStructValueExpr {
329 ZigList<AstNode *> fields;332 ZigList<AstNode *> fields;
330};333};
331334
335struct AstNodeCompilerFnCall {
336 Buf name;
337 AstNode *expr;
338};
339
332struct AstNode {340struct AstNode {
333 enum NodeType type;341 enum NodeType type;
334 int line;342 int line;
...@@ -368,6 +376,7 @@ struct AstNode {...@@ -368,6 +376,7 @@ struct AstNode {
368 AstNodeNumberLiteral number_literal;376 AstNodeNumberLiteral number_literal;
369 AstNodeStructValueExpr struct_val_expr;377 AstNodeStructValueExpr struct_val_expr;
370 AstNodeStructValueField struct_val_field;378 AstNodeStructValueField struct_val_field;
379 AstNodeCompilerFnCall compiler_fn_call;
371 Buf symbol;380 Buf symbol;
372 bool bool_literal;381 bool bool_literal;
373 } data;382 } data;
test/run_tests.cpp+26-10
...@@ -347,7 +347,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {...@@ -347,7 +347,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
347 add_simple_case("hello world without libc", R"SOURCE(347 add_simple_case("hello world without libc", R"SOURCE(
348use "std.zig";348use "std.zig";
349349
350export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {350pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
351 print_str("Hello, world!\n");351 print_str("Hello, world!\n");
352 return 0;352 return 0;
353}353}
...@@ -357,7 +357,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -357,7 +357,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
357 add_simple_case("a + b + c", R"SOURCE(357 add_simple_case("a + b + c", R"SOURCE(
358use "std.zig";358use "std.zig";
359359
360export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {360pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
361 if (false || false || false) { print_str("BAD 1\n"); }361 if (false || false || false) { print_str("BAD 1\n"); }
362 if (true && true && false) { print_str("BAD 2\n"); }362 if (true && true && false) { print_str("BAD 2\n"); }
363 if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); }363 if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); }
...@@ -379,7 +379,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -379,7 +379,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
379 add_simple_case("short circuit", R"SOURCE(379 add_simple_case("short circuit", R"SOURCE(
380use "std.zig";380use "std.zig";
381381
382export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {382pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
383 if (true || { print_str("BAD 1\n"); false }) {383 if (true || { print_str("BAD 1\n"); false }) {
384 print_str("OK 1\n");384 print_str("OK 1\n");
385 }385 }
...@@ -402,7 +402,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -402,7 +402,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
402 add_simple_case("modify operators", R"SOURCE(402 add_simple_case("modify operators", R"SOURCE(
403use "std.zig";403use "std.zig";
404404
405export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {405pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
406 var i : i32 = 0;406 var i : i32 = 0;
407 i += 5; if (i != 5) { print_str("BAD +=\n"); }407 i += 5; if (i != 5) { print_str("BAD +=\n"); }
408 i -= 2; if (i != 3) { print_str("BAD -=\n"); }408 i -= 2; if (i != 3) { print_str("BAD -=\n"); }
...@@ -554,7 +554,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -554,7 +554,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
554 add_simple_case("structs", R"SOURCE(554 add_simple_case("structs", R"SOURCE(
555use "std.zig";555use "std.zig";
556556
557export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {557pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
558 var foo : Foo;558 var foo : Foo;
559 foo.a += 1;559 foo.a += 1;
560 foo.b = foo.a == 1;560 foo.b = foo.a == 1;
...@@ -628,7 +628,7 @@ use "std.zig";...@@ -628,7 +628,7 @@ use "std.zig";
628const g1 : i32 = 1233 + 1;628const g1 : i32 = 1233 + 1;
629var g2 : i32;629var g2 : i32;
630630
631export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {631pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
632 if (g2 != 0) { print_str("BAD\n"); }632 if (g2 != 0) { print_str("BAD\n"); }
633 g2 = g1;633 g2 = g1;
634 if (g2 != 1234) { print_str("BAD\n"); }634 if (g2 != 1234) { print_str("BAD\n"); }
...@@ -639,7 +639,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -639,7 +639,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
639639
640 add_simple_case("while loop", R"SOURCE(640 add_simple_case("while loop", R"SOURCE(
641use "std.zig";641use "std.zig";
642export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {642pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
643 var i : i32 = 0;643 var i : i32 = 0;
644 while (i < 4) {644 while (i < 4) {
645 print_str("loop\n");645 print_str("loop\n");
...@@ -651,7 +651,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -651,7 +651,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
651651
652 add_simple_case("continue and break", R"SOURCE(652 add_simple_case("continue and break", R"SOURCE(
653use "std.zig";653use "std.zig";
654export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {654pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
655 var i : i32 = 0;655 var i : i32 = 0;
656 while (true) {656 while (true) {
657 print_str("loop\n");657 print_str("loop\n");
...@@ -667,7 +667,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -667,7 +667,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
667667
668 add_simple_case("maybe type", R"SOURCE(668 add_simple_case("maybe type", R"SOURCE(
669use "std.zig";669use "std.zig";
670export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {670pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
671 const x : ?bool = true;671 const x : ?bool = true;
672672
673 if (const y ?= x) {673 if (const y ?= x) {
...@@ -685,7 +685,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -685,7 +685,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
685685
686 add_simple_case("implicit cast after unreachable", R"SOURCE(686 add_simple_case("implicit cast after unreachable", R"SOURCE(
687use "std.zig";687use "std.zig";
688export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {688pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
689 const x = outer();689 const x = outer();
690 if (x == 1234) {690 if (x == 1234) {
691 print_str("OK\n");691 print_str("OK\n");
...@@ -695,6 +695,17 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -695,6 +695,17 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
695fn inner() -> i32 { 1234 }695fn inner() -> i32 { 1234 }
696fn outer() -> isize {696fn outer() -> isize {
697 return inner();697 return inner();
698}
699 )SOURCE", "OK\n");
700
701 add_simple_case("#typeof()", R"SOURCE(
702use "std.zig";
703const x: u16 = 13;
704const z: #typeof(x) = 19;
705pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
706 const y: #typeof(x) = 120;
707 print_str("OK\n");
708 return 0;
698}709}
699 )SOURCE", "OK\n");710 )SOURCE", "OK\n");
700}711}
...@@ -999,6 +1010,11 @@ fn f() -> i32 {...@@ -999,6 +1010,11 @@ fn f() -> i32 {
999 (return 1) as i321010 (return 1) as i32
1000}1011}
1001 )SOURCE", 1, ".tmp_source.zig:3:16: error: invalid cast from type 'unreachable' to 'i32'");1012 )SOURCE", 1, ".tmp_source.zig:3:16: error: invalid cast from type 'unreachable' to 'i32'");
1013
1014 add_compile_fail_case("invalid compiler fn", R"SOURCE(
1015fn f() -> #bogus(foo) {
1016}
1017 )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid compiler function: 'bogus'");
1002}1018}
10031019
1004static void print_compiler_invocation(TestCase *test_case) {1020static void print_compiler_invocation(TestCase *test_case) {