authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-12 00:10:37-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-12 00:10:37-07:00
loga10277bd949d47370e427d4457d93e907de9a6f7
tree4f5ca4247559c679a5a04ea0816c2c78f90211ed
parent4c16eaa6401786e6c2de84d7c9f231107d6f2cb7

prepare codebase for struct and string support

parsing code for structs, strings, and c string literals partial semantic analyzing code for structs, strings, and c string literals

15 files changed, 599 insertions(+), 107 deletions(-)

doc/langref.md+14-8
......@@ -32,7 +32,11 @@ zig | C equivalent | Description
3232```
3333Root : many(TopLevelDecl) token(EOF)
3434
35TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
35TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl
36
37StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace)
38
39StructField : token(Symbol) token(Colon) Type token(Comma)
3640
3741Use : many(Directive) token(Use) token(String) token(Semicolon)
3842
......@@ -126,7 +130,9 @@ CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression
126130
127131PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression
128132
129SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)
133SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression)
134
135FieldAccessExpression : token(Dot) token(Symbol)
130136
131137FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
132138
......@@ -146,7 +152,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
146152## Operator Precedence
147153
148154```
149x() x[]
155x() x[] x.y
150156!x -x ~x
151157as
152158* / %
......@@ -165,11 +171,11 @@ as
165171
166172### Characters and Strings
167173
168 | Example | Characters | Escapes | Null Terminated
169-------------------------------------------------------------------------------
170 Byte | 'H' | All ASCII | Byte | No
171 UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No
172 UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes
174 | Example | Characters | Escapes | Null Term | Type
175---------------------------------------------------------------------------------
176 Byte | 'H' | All ASCII | Byte | No | u8
177 UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No | [5; u8]
178 UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes | *const u8
173179
174180### Byte Escapes
175181
doc/vim/syntax/zig.vim+1-1
......@@ -9,7 +9,7 @@ endif
99
1010syn keyword zigKeyword fn return mut const extern unreachable export pub as use while asm
1111syn keyword zigKeyword if else let void goto type enum struct continue break match volatile
12syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
12syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string
1313
1414syn keyword zigConstant null
1515
example/hello_world/hello2.zig+1-1
......@@ -3,6 +3,6 @@ export executable "hello";
33use "std.zig";
44
55export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
6 print_str("Hello, world!\n", 14 as isize);
6 print_str("Hello, world!\n");
77 return 0;
88}
example/structs/structs.zig created+27
......@@ -0,0 +1,27 @@
1export executable "structs";
2
3use "std.zig";
4
5export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
6 let mut foo : Foo;
7
8 foo.a = foo.a + 1;
9
10 foo.b = foo.a == 1;
11
12 test_foo(foo);
13
14 return 0;
15}
16
17struct Foo {
18 a : i32,
19 b : bool,
20 c : f32,
21}
22
23fn test_foo(foo : Foo) {
24 if foo.b {
25 print_str("OK");
26 }
27}
src/analyze.cpp+200-22
......@@ -13,6 +13,11 @@
1313static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1414 TypeTableEntry *expected_type, AstNode *node);
1515
16static void alloc_codegen_node(AstNode *node) {
17 assert(!node->codegen_node);
18 node->codegen_node = allocate<CodeGenNode>(1);
19}
20
1621static AstNode *first_executing_node(AstNode *node) {
1722 switch (node->type) {
1823 case NodeTypeFnCallExpr:
......@@ -44,6 +49,9 @@ static AstNode *first_executing_node(AstNode *node) {
4449 case NodeTypeLabel:
4550 case NodeTypeGoto:
4651 case NodeTypeAsmExpr:
52 case NodeTypeFieldAccessExpr:
53 case NodeTypeStructDecl:
54 case NodeTypeStructField:
4755 return node;
4856 }
4957 zig_panic("unreachable");
......@@ -129,6 +137,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in
129137 entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, entry->size_in_bits,
130138 entry->align_in_bits, child_type->di_type, array_size);
131139 entry->data.array.child_type = child_type;
140 entry->data.array.len = array_size;
132141
133142 g->type_table.put(&entry->name, entry);
134143 child_type->arrays_by_size.put(array_size, entry);
......@@ -143,8 +152,7 @@ static int parse_int(Buf *number) {
143152
144153static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
145154 assert(node->type == NodeTypeType);
146 assert(!node->codegen_node);
147 node->codegen_node = allocate<CodeGenNode>(1);
155 alloc_codegen_node(node);
148156 TypeNode *type_node = &node->codegen_node->data.type_node;
149157 switch (node->data.type.type) {
150158 case AstNodeTypeTypePrimitive:
......@@ -259,8 +267,7 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_
259267 Buf *name = &label_node->data.label.name;
260268 fn_table_entry->label_table.put(name, label_entry);
261269
262 assert(!label_node->codegen_node);
263 label_node->codegen_node = allocate<CodeGenNode>(1);
270 alloc_codegen_node(label_node);
264271 label_node->codegen_node->data.label_entry = label_entry;
265272 }
266273}
......@@ -302,8 +309,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
302309 g->fn_table.put(name, fn_table_entry);
303310 }
304311
305 assert(!fn_proto->codegen_node);
306 fn_proto->codegen_node = allocate<CodeGenNode>(1);
312 alloc_codegen_node(fn_proto);
307313 fn_proto->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
308314 }
309315 break;
......@@ -319,8 +325,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
319325 if (entry) {
320326 add_node_error(g, node,
321327 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
322 assert(!node->codegen_node);
323 node->codegen_node = allocate<CodeGenNode>(1);
328 alloc_codegen_node(node);
324329 node->codegen_node->data.fn_def_node.skip = true;
325330 skip = true;
326331 } else if (is_pub) {
......@@ -328,8 +333,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
328333 if (entry) {
329334 add_node_error(g, node,
330335 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
331 assert(!node->codegen_node);
332 node->codegen_node = allocate<CodeGenNode>(1);
336 alloc_codegen_node(node);
333337 node->codegen_node->data.fn_def_node.skip = true;
334338 skip = true;
335339 }
......@@ -358,8 +362,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
358362 resolve_function_proto(g, proto_node, fn_table_entry);
359363
360364
361 assert(!proto_node->codegen_node);
362 proto_node->codegen_node = allocate<CodeGenNode>(1);
365 alloc_codegen_node(proto_node);
363366 proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
364367
365368 preview_function_labels(g, node->data.fn_def.body, fn_table_entry);
......@@ -409,6 +412,31 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
409412 buf_sprintf("root export declaration only valid in root source file"));
410413 }
411414 break;
415 case NodeTypeStructDecl:
416 {
417 StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node;
418 TypeTableEntry *type_entry = struct_codegen->type_entry;
419
420 int field_count = node->data.struct_decl.fields.length;;
421 type_entry->data.structure.field_count = field_count;
422 type_entry->data.structure.fields = allocate<TypeStructField>(field_count);
423
424 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
425
426 for (int i = 0; i < field_count; i += 1) {
427 AstNode *field_node = node->data.struct_decl.fields.at(i);
428 TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
429 type_struct_field->name = &field_node->data.struct_field.name;
430 type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type);
431
432 element_types[i] = type_struct_field->type_entry->type_ref;
433 }
434 // TODO align_in_bits and size_in_bits
435 // TODO set up ditype for the struct
436 LLVMStructSetBody(type_entry->type_ref, element_types, field_count, false);
437
438 break;
439 }
412440 case NodeTypeUse:
413441 // nothing to do here
414442 break;
......@@ -436,6 +464,68 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
436464 case NodeTypeLabel:
437465 case NodeTypeGoto:
438466 case NodeTypeAsmExpr:
467 case NodeTypeFieldAccessExpr:
468 case NodeTypeStructField:
469 zig_unreachable();
470 }
471}
472
473static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
474 switch (node->type) {
475 case NodeTypeStructDecl:
476 {
477 alloc_codegen_node(node);
478 StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node;
479
480 Buf *name = &node->data.struct_decl.name;
481 auto table_entry = g->type_table.maybe_get(name);
482 if (table_entry) {
483 struct_codegen->type_entry = table_entry->value;
484 add_node_error(g, node,
485 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
486 } else {
487 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
488 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name));
489 buf_init_from_buf(&entry->name, name);
490 // put off adding the debug type until we do the full struct body
491 // this type is incomplete until we do another pass
492 g->type_table.put(&entry->name, entry);
493 struct_codegen->type_entry = entry;
494 }
495 break;
496 }
497 case NodeTypeExternBlock:
498 case NodeTypeFnDef:
499 case NodeTypeRootExportDecl:
500 case NodeTypeUse:
501 // nothing to do
502 break;
503 case NodeTypeDirective:
504 case NodeTypeParamDecl:
505 case NodeTypeFnProto:
506 case NodeTypeType:
507 case NodeTypeFnDecl:
508 case NodeTypeReturnExpr:
509 case NodeTypeVariableDeclaration:
510 case NodeTypeRoot:
511 case NodeTypeBlock:
512 case NodeTypeBinOpExpr:
513 case NodeTypeFnCallExpr:
514 case NodeTypeArrayAccessExpr:
515 case NodeTypeNumberLiteral:
516 case NodeTypeStringLiteral:
517 case NodeTypeUnreachable:
518 case NodeTypeVoid:
519 case NodeTypeBoolLiteral:
520 case NodeTypeSymbol:
521 case NodeTypeCastExpr:
522 case NodeTypePrefixOpExpr:
523 case NodeTypeIfExpr:
524 case NodeTypeLabel:
525 case NodeTypeGoto:
526 case NodeTypeAsmExpr:
527 case NodeTypeFieldAccessExpr:
528 case NodeTypeStructField:
439529 zig_unreachable();
440530 }
441531}
......@@ -460,7 +550,9 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) {
460550 return fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
461551}
462552
463static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
553static void check_type_compatibility(CodeGen *g, AstNode *node,
554 TypeTableEntry *expected_type, TypeTableEntry *actual_type)
555{
464556 if (expected_type == nullptr)
465557 return; // anything will do
466558 if (expected_type == actual_type)
......@@ -471,7 +563,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *
471563 return; // sorry toots; gotta run. good luck with that expected type.
472564
473565 add_node_error(g, node,
474 buf_sprintf("type mismatch. expected %s. got %s",
566 buf_sprintf("expected type '%s', got '%s'",
475567 buf_ptr(&expected_type->name),
476568 buf_ptr(&actual_type->name)));
477569}
......@@ -507,6 +599,55 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
507599 }
508600}
509601
602static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) {
603 for (int i = 0; i < struct_type->data.structure.field_count; i += 1) {
604 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
605 if (buf_eql_buf(type_struct_field->name, name)) {
606 return type_struct_field;
607 }
608 }
609 return nullptr;
610}
611
612static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
613 AstNode *node)
614{
615 TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr,
616 node->data.field_access_expr.struct_expr);
617
618 TypeTableEntry *return_type;
619
620 if (struct_type->id == TypeTableEntryIdStruct) {
621 Buf *field_name = &node->data.field_access_expr.field_name;
622 TypeStructField *type_struct_field = get_struct_field(struct_type, field_name);
623 if (type_struct_field) {
624 return_type = type_struct_field->type_entry;
625 } else {
626 add_node_error(g, node,
627 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name)));
628 return_type = g->builtin_types.entry_invalid;
629 }
630 } else if (struct_type->id == TypeTableEntryIdArray) {
631 Buf *name = &node->data.field_access_expr.field_name;
632 if (buf_eql_str(name, "len")) {
633 return_type = g->builtin_types.entry_usize;
634 } else {
635 add_node_error(g, node,
636 buf_sprintf("no member named '%s' in '%s'", buf_ptr(name),
637 buf_ptr(&struct_type->name)));
638 return_type = g->builtin_types.entry_invalid;
639 }
640 } else {
641 if (struct_type->id != TypeTableEntryIdInvalid) {
642 add_node_error(g, node,
643 buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
644 }
645 return_type = g->builtin_types.entry_invalid;
646 }
647
648 return return_type;
649}
650
510651static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
511652 AstNode *node)
512653{
......@@ -554,8 +695,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
554695 TypeTableEntry *expected_type, AstNode *node)
555696{
556697 TypeTableEntry *return_type = nullptr;
557 assert(!node->codegen_node);
558 node->codegen_node = allocate<CodeGenNode>(1);
698 alloc_codegen_node(node);
559699 switch (node->type) {
560700 case NodeTypeBlock:
561701 {
......@@ -698,9 +838,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
698838 }
699839 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
700840 expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);
841 } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
842 expected_rhs_type = analyze_field_access_expr(g, import, context, lhs_node);
701843 } else {
702844 add_node_error(g, lhs_node,
703 buf_sprintf("expected a bare identifier"));
845 buf_sprintf("assignment target must be variable, field, or array element"));
704846 }
705847 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
706848 return_type = g->builtin_types.entry_void;
......@@ -835,15 +977,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
835977 // for reading array access; assignment handled elsewhere
836978 return_type = analyze_array_access_expr(g, import, context, node);
837979 break;
980 case NodeTypeFieldAccessExpr:
981 return_type = analyze_field_access_expr(g, import, context, node);
982 break;
838983 case NodeTypeNumberLiteral:
839984 // TODO: generic literal int type
840985 return_type = g->builtin_types.entry_i32;
841986 break;
842987
843988 case NodeTypeStringLiteral:
844 return_type = g->builtin_types.entry_string_literal;
989 if (node->data.string_literal.c) {
990 return_type = g->builtin_types.entry_c_string_literal;
991 } else {
992 return_type = get_array_type(g, g->builtin_types.entry_u8, buf_len(&node->data.string_literal.buf));
993 }
845994 break;
846
847995 case NodeTypeUnreachable:
848996 return_type = g->builtin_types.entry_unreachable;
849997 break;
......@@ -884,7 +1032,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
8841032 {
8851033 return_type = wanted_type;
8861034 } else {
887 zig_panic("TODO analyze_expression cast expr");
1035 add_node_error(g, node,
1036 buf_sprintf("TODO handle cast from '%s' to '%s'",
1037 buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
1038 return_type = g->builtin_types.entry_invalid;
8881039 }
8891040 break;
8901041 }
......@@ -946,6 +1097,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
9461097 case NodeTypeFnDef:
9471098 case NodeTypeUse:
9481099 case NodeTypeLabel:
1100 case NodeTypeStructDecl:
1101 case NodeTypeStructField:
9491102 zig_unreachable();
9501103 }
9511104 assert(return_type);
......@@ -970,8 +1123,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
9701123 AstNode *fn_proto_node = node->data.fn_def.fn_proto;
9711124 assert(fn_proto_node->type == NodeTypeFnProto);
9721125
973 assert(!node->codegen_node);
974 node->codegen_node = allocate<CodeGenNode>(1);
1126 alloc_codegen_node(node);
9751127 BlockContext *context = new_block_context(node, nullptr);
9761128 node->codegen_node->data.fn_def_node.block_context = context;
9771129
......@@ -1044,6 +1196,9 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
10441196 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
10451197 }
10461198 break;
1199 case NodeTypeStructDecl:
1200 // nothing to do
1201 break;
10471202 case NodeTypeDirective:
10481203 case NodeTypeParamDecl:
10491204 case NodeTypeFnProto:
......@@ -1068,6 +1223,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
10681223 case NodeTypeLabel:
10691224 case NodeTypeGoto:
10701225 case NodeTypeAsmExpr:
1226 case NodeTypeFieldAccessExpr:
1227 case NodeTypeStructField:
10711228 zig_unreachable();
10721229 }
10731230}
......@@ -1082,6 +1239,16 @@ static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import
10821239
10831240}
10841241
1242static void preview_types_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1243 assert(node->type == NodeTypeRoot);
1244
1245 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
1246 AstNode *child = node->data.root.top_level_decls.at(i);
1247 preview_types(g, import, child);
1248 }
1249
1250}
1251
10851252static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
10861253 assert(node->type == NodeTypeRoot);
10871254
......@@ -1092,6 +1259,17 @@ static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, A
10921259}
10931260
10941261void semantic_analyze(CodeGen *g) {
1262 {
1263 auto it = g->import_table.entry_iterator();
1264 for (;;) {
1265 auto *entry = it.next();
1266 if (!entry)
1267 break;
1268
1269 ImportTableEntry *import = entry->value;
1270 preview_types_root(g, import, import->root);
1271 }
1272 }
10951273 {
10961274 auto it = g->import_table.entry_iterator();
10971275 for (;;) {
src/analyze.hpp+22-1
......@@ -28,6 +28,18 @@ struct TypeTableEntryInt {
2828
2929struct TypeTableEntryArray {
3030 TypeTableEntry *child_type;
31 uint64_t len;
32};
33
34struct TypeStructField {
35 Buf *name;
36 TypeTableEntry *type_entry;
37};
38
39struct TypeTableEntryStruct {
40 bool is_packed;
41 int field_count;
42 TypeStructField *fields;
3143};
3244
3345enum TypeTableEntryId {
......@@ -39,6 +51,7 @@ enum TypeTableEntryId {
3951 TypeTableEntryIdFloat,
4052 TypeTableEntryIdPointer,
4153 TypeTableEntryIdArray,
54 TypeTableEntryIdStruct,
4255};
4356
4457struct TypeTableEntry {
......@@ -55,6 +68,7 @@ struct TypeTableEntry {
5568 TypeTableEntryPointer pointer;
5669 TypeTableEntryInt integral;
5770 TypeTableEntryArray array;
71 TypeTableEntryStruct structure;
5872 } data;
5973
6074 // use these fields to make sure we don't duplicate type table entries for the same type
......@@ -122,8 +136,10 @@ struct CodeGen {
122136 TypeTableEntry *entry_u8;
123137 TypeTableEntry *entry_i32;
124138 TypeTableEntry *entry_isize;
139 TypeTableEntry *entry_usize;
125140 TypeTableEntry *entry_f32;
126 TypeTableEntry *entry_string_literal;
141 TypeTableEntry *entry_c_string_literal;
142 TypeTableEntry *entry_string;
127143 TypeTableEntry *entry_void;
128144 TypeTableEntry *entry_unreachable;
129145 TypeTableEntry *entry_invalid;
......@@ -211,6 +227,10 @@ struct BlockNode {
211227 BlockContext *block_context;
212228};
213229
230struct StructDeclNode {
231 TypeTableEntry *type_entry;
232};
233
214234struct CodeGenNode {
215235 union {
216236 TypeNode type_node; // for NodeTypeType
......@@ -219,6 +239,7 @@ struct CodeGenNode {
219239 LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel
220240 AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign
221241 BlockNode block_node; // for NodeTypeBlock
242 StructDeclNode struct_decl_node; // for NodeTypeStructDecl
222243 } data;
223244 ExprNode expr_node; // for all the expression nodes
224245};
src/codegen.cpp+83-8
......@@ -106,12 +106,12 @@ static void add_debug_source_node(CodeGen *g, AstNode *node) {
106106 g->cur_block_context->di_scope);
107107}
108108
109static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) {
109static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
110110 auto entry = g->str_table.maybe_get(str);
111111 if (entry) {
112112 return entry->value;
113113 }
114 LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), false);
114 LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), !c);
115115 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), "");
116116 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
117117 LLVMSetInitializer(global_value, text);
......@@ -204,6 +204,28 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
204204 return LLVMBuildLoad(g->builder, ptr, "");
205205}
206206
207static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
208 assert(node->type == NodeTypeFieldAccessExpr);
209
210 TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr);
211 LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr);
212 Buf *name = &node->data.field_access_expr.field_name;
213
214 // TODO add struct support
215 (void)struct_ptr;
216
217 if (struct_type->id == TypeTableEntryIdArray) {
218 if (buf_eql_str(name, "len")) {
219 return LLVMConstInt(g->builtin_types.entry_usize->type_ref,
220 struct_type->data.array.len, false);
221 } else {
222 zig_panic("gen_field_access_expr bad array field");
223 }
224 } else {
225 zig_panic("gen_field_access_expr bad struct type");
226 }
227}
228
207229static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
208230 assert(node->type == NodeTypePrefixOpExpr);
209231 assert(node->data.prefix_op_expr.primary_expr);
......@@ -785,6 +807,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
785807 return gen_fn_call_expr(g, node);
786808 case NodeTypeArrayAccessExpr:
787809 return gen_array_access_expr(g, node);
810 case NodeTypeFieldAccessExpr:
811 return gen_field_access_expr(g, node);
788812 case NodeTypeUnreachable:
789813 add_debug_source_node(g, node);
790814 return LLVMBuildUnreachable(g->builder);
......@@ -809,8 +833,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
809833 }
810834 case NodeTypeStringLiteral:
811835 {
812 Buf *str = &node->data.string;
813 LLVMValueRef str_val = find_or_create_string(g, str);
836 Buf *str = &node->data.string_literal.buf;
837 LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c);
814838 LLVMValueRef indices[] = {
815839 LLVMConstInt(LLVMInt32Type(), 0, false),
816840 LLVMConstInt(LLVMInt32Type(), 0, false)
......@@ -864,6 +888,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
864888 case NodeTypeExternBlock:
865889 case NodeTypeDirective:
866890 case NodeTypeUse:
891 case NodeTypeStructDecl:
892 case NodeTypeStructField:
867893 zig_unreachable();
868894 }
869895 zig_unreachable();
......@@ -1072,7 +1098,7 @@ static void do_code_gen(CodeGen *g) {
10721098#endif
10731099}
10741100
1075static void define_primitive_types(CodeGen *g) {
1101static void define_builtin_types(CodeGen *g) {
10761102 {
10771103 // if this type is anywhere in the AST, we should never hit codegen.
10781104 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInvalid);
......@@ -1103,7 +1129,7 @@ static void define_primitive_types(CodeGen *g) {
11031129 g->type_table.put(&entry->name, entry);
11041130 g->builtin_types.entry_u8 = entry;
11051131 }
1106 g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
1132 g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
11071133 {
11081134 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
11091135 entry->type_ref = LLVMInt32Type();
......@@ -1130,6 +1156,19 @@ static void define_primitive_types(CodeGen *g) {
11301156 g->type_table.put(&entry->name, entry);
11311157 g->builtin_types.entry_isize = entry;
11321158 }
1159 {
1160 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1161 entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
1162 buf_init_from_str(&entry->name, "usize");
1163 entry->size_in_bits = g->pointer_size_bytes * 8;
1164 entry->align_in_bits = g->pointer_size_bytes * 8;
1165 entry->data.integral.is_signed = false;
1166 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1167 entry->size_in_bits, entry->align_in_bits,
1168 LLVMZigEncoding_DW_ATE_unsigned());
1169 g->type_table.put(&entry->name, entry);
1170 g->builtin_types.entry_usize = entry;
1171 }
11331172 {
11341173 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
11351174 entry->type_ref = LLVMFloatType();
......@@ -1160,6 +1199,43 @@ static void define_primitive_types(CodeGen *g) {
11601199 g->type_table.put(&entry->name, entry);
11611200 g->builtin_types.entry_unreachable = entry;
11621201 }
1202 {
1203 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
1204
1205 TypeTableEntry *const_pointer_to_u8 = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
1206
1207 unsigned element_count = 2;
1208 LLVMTypeRef element_types[] = {
1209 const_pointer_to_u8->type_ref,
1210 g->builtin_types.entry_usize->type_ref
1211 };
1212 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), "string");
1213 LLVMStructSetBody(entry->type_ref, element_types, element_count, false);
1214
1215 buf_init_from_str(&entry->name, "string");
1216 entry->size_in_bits = g->pointer_size_bytes * 2 * 8;
1217 entry->align_in_bits = g->pointer_size_bytes;
1218 entry->data.structure.is_packed = false;
1219 entry->data.structure.field_count = element_count;
1220 entry->data.structure.fields = allocate<TypeStructField>(element_count);
1221 entry->data.structure.fields[0].name = buf_create_from_str("ptr");
1222 entry->data.structure.fields[0].type_entry = const_pointer_to_u8;
1223 entry->data.structure.fields[1].name = buf_create_from_str("len");
1224 entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize;
1225
1226 LLVMZigDIType *di_element_types[] = {
1227 const_pointer_to_u8->di_type,
1228 g->builtin_types.entry_usize->di_type
1229 };
1230 LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
1231 LLVMZigDIFile *difile = nullptr; // TODO make sure this ok
1232 entry->di_type = LLVMZigCreateDebugStructType(g->dbuilder, compile_unit_scope,
1233 "string", difile, 0, entry->size_in_bits, entry->align_in_bits, 0,
1234 nullptr, di_element_types, element_count, 0, nullptr, "");
1235
1236 g->type_table.put(&entry->name, entry);
1237 g->builtin_types.entry_string = entry;
1238 }
11631239}
11641240
11651241
......@@ -1213,8 +1289,6 @@ static void init(CodeGen *g, Buf *source_path) {
12131289 LLVMZigSetFastMath(g->builder, true);
12141290
12151291
1216 define_primitive_types(g);
1217
12181292 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
12191293 bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
12201294 const char *flags = "";
......@@ -1224,6 +1298,7 @@ static void init(CodeGen *g, Buf *source_path) {
12241298 buf_ptr(producer), is_optimized, flags, runtime_version,
12251299 "", 0, !g->strip_debug_symbols);
12261300
1301 define_builtin_types(g);
12271302
12281303}
12291304
src/parser.cpp+126-30
......@@ -106,6 +106,12 @@ const char *node_type_str(NodeType node_type) {
106106 return "Label";
107107 case NodeTypeAsmExpr:
108108 return "AsmExpr";
109 case NodeTypeFieldAccessExpr:
110 return "FieldAccessExpr";
111 case NodeTypeStructDecl:
112 return "StructDecl";
113 case NodeTypeStructField:
114 return "StructField";
109115 }
110116 zig_unreachable();
111117}
......@@ -259,9 +265,12 @@ void ast_print(AstNode *node, int indent) {
259265 buf_ptr(&node->data.number));
260266 break;
261267 case NodeTypeStringLiteral:
262 fprintf(stderr, "StringLiteral '%s'\n",
263 buf_ptr(&node->data.string));
264 break;
268 {
269 const char *c = node->data.string_literal.c ? "c" : "";
270 fprintf(stderr, "StringLiteral %s'%s'\n", c,
271 buf_ptr(&node->data.string_literal.buf));
272 break;
273 }
265274 case NodeTypeUnreachable:
266275 fprintf(stderr, "Unreachable\n");
267276 break;
......@@ -295,6 +304,19 @@ void ast_print(AstNode *node, int indent) {
295304 case NodeTypeAsmExpr:
296305 fprintf(stderr, "%s\n", node_type_str(node->type));
297306 break;
307 case NodeTypeFieldAccessExpr:
308 fprintf(stderr, "%s '%s'\n", node_type_str(node->type),
309 buf_ptr(&node->data.field_access_expr.field_name));
310 ast_print(node->data.field_access_expr.struct_expr, indent + 2);
311 break;
312 case NodeTypeStructDecl:
313 fprintf(stderr, "%s '%s'\n",
314 node_type_str(node->type), buf_ptr(&node->data.struct_decl.name));
315 break;
316 case NodeTypeStructField:
317 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name));
318 ast_print(node->data.struct_field.type, indent + 2);
319 break;
298320 }
299321}
300322
......@@ -475,18 +497,28 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
475497 }
476498}
477499
478static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, ZigList<SrcPos> *offset_map) {
500static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str,
501 ZigList<SrcPos> *offset_map)
502{
479503 // skip the double quotes at beginning and end
480504 // convert escape sequences
505 // detect c string literal
481506
482507 buf_resize(buf, 0);
483508 bool escape = false;
484 bool first = true;
509 bool skip_quote;
485510 SrcPos pos = {token->start_line, token->start_column};
486511 for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {
487512 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
488 if (first) {
489 first = false;
513 if (i == token->start_pos) {
514 skip_quote = (c == 'c');
515 if (out_c_str) {
516 *out_c_str = skip_quote;
517 } else if (skip_quote) {
518 ast_error(pc, token, "C string literal not allowed here");
519 }
520 } else if (skip_quote) {
521 skip_quote = false;
490522 } else {
491523 if (escape) {
492524 switch (c) {
......@@ -541,13 +573,20 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma
541573static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);
542574static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);
543575
544
545576static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
546577 if (token->id != token_id) {
547578 ast_invalid_token_error(pc, token);
548579 }
549580}
550581
582static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id) {
583 Token *token = &pc->tokens->at(*token_index);
584 ast_expect_token(pc, token, token_id);
585 *token_index += 1;
586 return token;
587}
588
589
551590static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) {
552591 Token *number_sign = &pc->tokens->at(token_index);
553592 token_index += 1;
......@@ -569,7 +608,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_
569608 token_index += 1;
570609 ast_expect_token(pc, param_str, TokenIdStringLiteral);
571610
572 parse_string_literal(pc, param_str, &node->data.directive.param, nullptr);
611 parse_string_literal(pc, param_str, &node->data.directive.param, nullptr, nullptr);
573612
574613 Token *r_paren = &pc->tokens->at(token_index);
575614 token_index += 1;
......@@ -782,7 +821,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
782821 return node;
783822 } else if (token->id == TokenIdStringLiteral) {
784823 AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token);
785 parse_string_literal(pc, token, &node->data.string, nullptr);
824 parse_string_literal(pc, token, &node->data.string_literal.buf, &node->data.string_literal.c, nullptr);
786825 *token_index += 1;
787826 return node;
788827 } else if (token->id == TokenIdKeywordUnreachable) {
......@@ -832,9 +871,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
832871}
833872
834873/*
835SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)
874SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression)
836875FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
837876ArrayAccessExpression : token(LBracket) Expression token(RBracket)
877FieldAccessExpression : token(Dot) token(Symbol)
838878*/
839879static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
840880 AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
......@@ -861,6 +901,16 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
861901 *token_index += 1;
862902 ast_expect_token(pc, r_bracket, TokenIdRBracket);
863903
904 return node;
905 } else if (token->id == TokenIdDot) {
906 *token_index += 1;
907
908 Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
909
910 AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, token);
911 node->data.field_access_expr.struct_expr = primary_expr;
912 ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
913
864914 return node;
865915 } else {
866916 return primary_expr;
......@@ -1397,14 +1447,6 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
13971447 return node;
13981448}
13991449
1400static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id) {
1401 Token *token = &pc->tokens->at(*token_index);
1402 ast_expect_token(pc, token, token_id);
1403 *token_index += 1;
1404 return token;
1405}
1406
1407
14081450/*
14091451AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
14101452*/
......@@ -1421,7 +1463,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode
14211463
14221464 AsmInput *asm_input = allocate<AsmInput>(1);
14231465 ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name);
1424 parse_string_literal(pc, constraint, &asm_input->constraint, nullptr);
1466 parse_string_literal(pc, constraint, &asm_input->constraint, nullptr, nullptr);
14251467 asm_input->expr = expr_node;
14261468 node->data.asm_expr.input_list.append(asm_input);
14271469}
......@@ -1442,7 +1484,7 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod
14421484
14431485 AsmOutput *asm_output = allocate<AsmOutput>(1);
14441486 ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);
1445 parse_string_literal(pc, constraint, &asm_output->constraint, nullptr);
1487 parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr);
14461488 ast_buf_from_token(pc, out_symbol, &asm_output->variable_name);
14471489 node->data.asm_expr.output_list.append(asm_output);
14481490}
......@@ -1464,7 +1506,7 @@ static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *
14641506 *token_index += 1;
14651507
14661508 Buf *clobber_buf = buf_alloc();
1467 parse_string_literal(pc, string_tok, clobber_buf, nullptr);
1509 parse_string_literal(pc, string_tok, clobber_buf, nullptr, nullptr);
14681510 node->data.asm_expr.clobber_list.append(clobber_buf);
14691511
14701512 Token *comma = &pc->tokens->at(*token_index);
......@@ -1565,7 +1607,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
15651607 ast_expect_token(pc, template_tok, TokenIdStringLiteral);
15661608 *token_index += 1;
15671609
1568 parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template,
1610 parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, nullptr,
15691611 &node->data.asm_expr.offset_map);
15701612 parse_asm_template(pc, node);
15711613
......@@ -1877,7 +1919,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
18771919 *token_index += 1;
18781920 ast_expect_token(pc, export_name, TokenIdStringLiteral);
18791921
1880 parse_string_literal(pc, export_name, &node->data.root_export_decl.name, nullptr);
1922 parse_string_literal(pc, export_name, &node->data.root_export_decl.name, nullptr, nullptr);
18811923
18821924 Token *semicolon = &pc->tokens->at(*token_index);
18831925 *token_index += 1;
......@@ -1889,9 +1931,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
18891931/*
18901932Use : many(Directive) token(Use) token(String) token(Semicolon)
18911933*/
1892static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory) {
1893 assert(mandatory == false);
1894
1934static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
18951935 Token *use_kw = &pc->tokens->at(*token_index);
18961936 if (use_kw->id != TokenIdKeywordUse)
18971937 return nullptr;
......@@ -1907,7 +1947,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
19071947
19081948 AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
19091949
1910 parse_string_literal(pc, use_name, &node->data.use.path, nullptr);
1950 parse_string_literal(pc, use_name, &node->data.use.path, nullptr, nullptr);
19111951
19121952 node->data.use.directives = pc->directive_list;
19131953 pc->directive_list = nullptr;
......@@ -1916,7 +1956,57 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
19161956}
19171957
19181958/*
1919TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
1959StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace)
1960StructField : token(Symbol) token(Colon) Type token(Comma)
1961*/
1962static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
1963 Token *struct_kw = &pc->tokens->at(*token_index);
1964 if (struct_kw->id != TokenIdKeywordStruct)
1965 return nullptr;
1966 *token_index += 1;
1967
1968 Token *struct_name = &pc->tokens->at(*token_index);
1969 *token_index += 1;
1970 ast_expect_token(pc, struct_name, TokenIdSymbol);
1971
1972 AstNode *node = ast_create_node(pc, NodeTypeStructDecl, struct_kw);
1973 ast_buf_from_token(pc, struct_name, &node->data.struct_decl.name);
1974
1975 ast_eat_token(pc, token_index, TokenIdLBrace);
1976
1977 for (;;) {
1978 Token *token = &pc->tokens->at(*token_index);
1979
1980 if (token->id == TokenIdRBrace) {
1981 *token_index += 1;
1982 break;
1983 } else if (token->id == TokenIdSymbol) {
1984 AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
1985 *token_index += 1;
1986
1987 ast_buf_from_token(pc, token, &field_node->data.struct_field.name);
1988
1989 ast_eat_token(pc, token_index, TokenIdColon);
1990
1991 field_node->data.struct_field.type = ast_parse_type(pc, *token_index, token_index);
1992
1993 ast_eat_token(pc, token_index, TokenIdComma);
1994
1995 node->data.struct_decl.fields.append(field_node);
1996 } else {
1997 ast_invalid_token_error(pc, token);
1998 }
1999 }
2000
2001
2002 node->data.struct_decl.directives = pc->directive_list;
2003 pc->directive_list = nullptr;
2004
2005 return node;
2006}
2007
2008/*
2009TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl
19202010*/
19212011static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
19222012 for (;;) {
......@@ -1943,12 +2033,18 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
19432033 continue;
19442034 }
19452035
1946 AstNode *use_node = ast_parse_use(pc, token_index, false);
2036 AstNode *use_node = ast_parse_use(pc, token_index);
19472037 if (use_node) {
19482038 top_level_decls->append(use_node);
19492039 continue;
19502040 }
19512041
2042 AstNode *struct_node = ast_parse_struct_decl(pc, token_index);
2043 if (struct_node) {
2044 top_level_decls->append(struct_node);
2045 continue;
2046 }
2047
19522048 if (pc->directive_list->length > 0) {
19532049 ast_error(pc, directive_token, "invalid directive");
19542050 }
src/parser.hpp+28-1
......@@ -40,6 +40,7 @@ enum NodeType {
4040 NodeTypePrefixOpExpr,
4141 NodeTypeFnCallExpr,
4242 NodeTypeArrayAccessExpr,
43 NodeTypeFieldAccessExpr,
4344 NodeTypeUse,
4445 NodeTypeVoid,
4546 NodeTypeBoolLiteral,
......@@ -47,6 +48,8 @@ enum NodeType {
4748 NodeTypeLabel,
4849 NodeTypeGoto,
4950 NodeTypeAsmExpr,
51 NodeTypeStructDecl,
52 NodeTypeStructField,
5053};
5154
5255struct AstNodeRoot {
......@@ -152,6 +155,11 @@ struct AstNodeArrayAccessExpr {
152155 AstNode *subscript;
153156};
154157
158struct AstNodeFieldAccessExpr {
159 AstNode *struct_expr;
160 Buf field_name;
161};
162
155163struct AstNodeExternBlock {
156164 ZigList<AstNode *> *directives;
157165 ZigList<AstNode *> fn_decls;
......@@ -231,6 +239,22 @@ struct AstNodeAsmExpr {
231239 ZigList<Buf*> clobber_list;
232240};
233241
242struct AstNodeStructDecl {
243 Buf name;
244 ZigList<AstNode *> fields;
245 ZigList<AstNode *> *directives;
246};
247
248struct AstNodeStructField {
249 Buf name;
250 AstNode *type;
251};
252
253struct AstNodeStringLiteral {
254 Buf buf;
255 bool c;
256};
257
234258struct AstNode {
235259 enum NodeType type;
236260 int line;
......@@ -260,8 +284,11 @@ struct AstNode {
260284 AstNodeLabel label;
261285 AstNodeGoto go_to;
262286 AstNodeAsmExpr asm_expr;
287 AstNodeFieldAccessExpr field_access_expr;
288 AstNodeStructDecl struct_decl;
289 AstNodeStructField struct_field;
290 AstNodeStringLiteral string_literal;
263291 Buf number;
264 Buf string;
265292 Buf symbol;
266293 bool bool_literal;
267294 } data;
src/tokenizer.cpp+31-3
......@@ -28,10 +28,9 @@
2828 case '8': \
2929 case '9'
3030
31#define ALPHA \
31#define ALPHA_EXCEPT_C \
3232 'a': \
3333 case 'b': \
34 case 'c': \
3534 case 'd': \
3635 case 'e': \
3736 case 'f': \
......@@ -82,6 +81,10 @@
8281 case 'Y': \
8382 case 'Z'
8483
84#define ALPHA \
85 ALPHA_EXCEPT_C: \
86 case 'c'
87
8588#define SYMBOL_CHAR \
8689 ALPHA: \
8790 case DIGIT: \
......@@ -90,6 +93,7 @@
9093enum TokenizeState {
9194 TokenizeStateStart,
9295 TokenizeStateSymbol,
96 TokenizeStateSymbolFirst,
9397 TokenizeStateNumber,
9498 TokenizeStateString,
9599 TokenizeStateSawDash,
......@@ -201,6 +205,8 @@ static void end_token(Tokenize *t) {
201205 t->cur_tok->id = TokenIdKeywordVolatile;
202206 } else if (mem_eql_str(token_mem, token_len, "asm")) {
203207 t->cur_tok->id = TokenIdKeywordAsm;
208 } else if (mem_eql_str(token_mem, token_len, "struct")) {
209 t->cur_tok->id = TokenIdKeywordStruct;
204210 }
205211
206212 t->cur_tok = nullptr;
......@@ -224,7 +230,11 @@ void tokenize(Buf *buf, Tokenization *out) {
224230 switch (c) {
225231 case WHITESPACE:
226232 break;
227 case ALPHA:
233 case 'c':
234 t.state = TokenizeStateSymbolFirst;
235 begin_token(&t, TokenIdSymbol);
236 break;
237 case ALPHA_EXCEPT_C:
228238 case '_':
229239 t.state = TokenizeStateSymbol;
230240 begin_token(&t, TokenIdSymbol);
......@@ -526,6 +536,22 @@ void tokenize(Buf *buf, Tokenization *out) {
526536 break;
527537 }
528538 break;
539 case TokenizeStateSymbolFirst:
540 switch (c) {
541 case '"':
542 t.cur_tok->id = TokenIdStringLiteral;
543 t.state = TokenizeStateString;
544 break;
545 case SYMBOL_CHAR:
546 t.state = TokenizeStateSymbol;
547 break;
548 default:
549 t.pos -= 1;
550 end_token(&t);
551 t.state = TokenizeStateStart;
552 continue;
553 }
554 break;
529555 case TokenizeStateSymbol:
530556 switch (c) {
531557 case SYMBOL_CHAR:
......@@ -589,6 +615,7 @@ void tokenize(Buf *buf, Tokenization *out) {
589615 tokenize_error(&t, "unterminated string");
590616 break;
591617 case TokenizeStateSymbol:
618 case TokenizeStateSymbolFirst:
592619 case TokenizeStateNumber:
593620 case TokenizeStateSawDash:
594621 case TokenizeStatePipe:
......@@ -643,6 +670,7 @@ static const char * token_name(Token *token) {
643670 case TokenIdKeywordGoto: return "Goto";
644671 case TokenIdKeywordVolatile: return "Volatile";
645672 case TokenIdKeywordAsm: return "Asm";
673 case TokenIdKeywordStruct: return "Struct";
646674 case TokenIdLParen: return "LParen";
647675 case TokenIdRParen: return "RParen";
648676 case TokenIdComma: return "Comma";
src/tokenizer.hpp+1
......@@ -32,6 +32,7 @@ enum TokenId {
3232 TokenIdKeywordGoto,
3333 TokenIdKeywordAsm,
3434 TokenIdKeywordVolatile,
35 TokenIdKeywordStruct,
3536 TokenIdLParen,
3637 TokenIdRParen,
3738 TokenIdComma,
src/zig_llvm.cpp+25
......@@ -161,6 +161,31 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder, uint64_t
161161 return reinterpret_cast<LLVMZigDIType*>(di_type);
162162}
163163
164
165LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,
166 const char *name, LLVMZigDIFile *file, unsigned line_number, uint64_t size_in_bits,
167 uint64_t align_in_bits, unsigned flags, LLVMZigDIType *derived_from,
168 LLVMZigDIType **types_array, int types_array_len, unsigned run_time_lang, LLVMZigDIType *vtable_holder,
169 const char *unique_id)
170{
171 SmallVector<Metadata *, 8> fields;
172 for (int i = 0; i < types_array_len; i += 1) {
173 DIType *ditype = reinterpret_cast<DIType*>(types_array[i]);
174 fields.push_back(ditype);
175 }
176 DIType *di_type = reinterpret_cast<DIBuilder*>(dibuilder)->createStructType(
177 reinterpret_cast<DIScope*>(scope),
178 name,
179 reinterpret_cast<DIFile*>(file),
180 line_number, size_in_bits, align_in_bits, flags,
181 reinterpret_cast<DIType*>(derived_from),
182 reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(fields),
183 run_time_lang,
184 reinterpret_cast<DIType*>(vtable_holder),
185 unique_id);
186 return reinterpret_cast<LLVMZigDIType*>(di_type);
187}
188
164189LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
165190 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags)
166191{
src/zig_llvm.hpp+5
......@@ -49,6 +49,11 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder,
4949 uint64_t size_in_bits, uint64_t align_in_bits, LLVMZigDIType *elem_type,
5050 int elem_count);
5151
52LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,
53 const char *name, LLVMZigDIFile *file, unsigned line_number, uint64_t size_in_bits,
54 uint64_t align_in_bits, unsigned flags, LLVMZigDIType *derived_from,
55 LLVMZigDIType **types_array, int types_array_len, unsigned run_time_lang, LLVMZigDIType *vtable_holder,
56 const char *unique_id);
5257
5358LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
5459 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags);
std/std.zig+5-2
......@@ -17,8 +17,11 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
1717// TODO zig strings instead of C strings
1818// TODO handle buffering and flushing
1919// TODO non-i32 integer literals so we can remove the casts
20pub fn print_str(str : *const u8, len: isize) {
20// TODO constants for SYS_write and stdout_fileno
21//pub fn print_str(str : string) -> isize {
22pub fn print_str(str : *const u8, len: isize) -> isize {
2123 let SYS_write = 1;
2224 let stdout_fileno = 1;
23 syscall3(SYS_write as isize, stdout_fileno as isize, str as isize, len);
25 //return syscall3(SYS_write as isize, stdout_fileno as isize, str.ptr as isize, str.len as isize);
26 return syscall3(SYS_write as isize, stdout_fileno as isize, str as isize, len);
2427}
test/run_tests.cpp+30-30
......@@ -104,7 +104,7 @@ static void add_compiling_test_cases(void) {
104104 }
105105
106106 export fn _start() -> unreachable {
107 puts("Hello, world!");
107 puts(c"Hello, world!");
108108 exit(0);
109109 }
110110 )SOURCE", "Hello, world!\n");
......@@ -126,7 +126,7 @@ static void add_compiling_test_cases(void) {
126126 }
127127
128128 fn this_is_a_function() -> unreachable {
129 puts("OK");
129 puts(c"OK");
130130 exit(0);
131131 }
132132 )SOURCE", "OK\n");
......@@ -146,7 +146,7 @@ static void add_compiling_test_cases(void) {
146146 /// this is a documentation comment
147147 /// doc comment line 2
148148 export fn _start() -> unreachable {
149 puts(/* mid-line comment /* nested */ */ "OK");
149 puts(/* mid-line comment /* nested */ */ c"OK");
150150 exit(0);
151151 }
152152 )SOURCE", "OK\n");
......@@ -180,7 +180,7 @@ static void add_compiling_test_cases(void) {
180180 // purposefully conflicting function with main source file
181181 // but it's private so it should be OK
182182 fn private_function() {
183 puts("OK");
183 puts(c"OK");
184184 }
185185
186186 pub fn print_text() {
......@@ -198,17 +198,17 @@ static void add_compiling_test_cases(void) {
198198
199199 export fn _start() -> unreachable {
200200 if 1 != 0 {
201 puts("1 is true");
201 puts(c"1 is true");
202202 } else {
203 puts("1 is false");
203 puts(c"1 is false");
204204 }
205205 if 0 != 0 {
206 puts("0 is true");
206 puts(c"0 is true");
207207 } else if 1 - 1 != 0 {
208 puts("1 - 1 is true");
208 puts(c"1 - 1 is true");
209209 }
210210 if !(0 != 0) {
211 puts("!0 is true");
211 puts(c"!0 is true");
212212 }
213213 exit(0);
214214 }
......@@ -227,7 +227,7 @@ static void add_compiling_test_cases(void) {
227227
228228 export fn _start() -> unreachable {
229229 if add(22, 11) == 33 {
230 puts("pass");
230 puts(c"pass");
231231 }
232232 exit(0);
233233 }
......@@ -244,7 +244,7 @@ static void add_compiling_test_cases(void) {
244244 if a == 0 {
245245 goto done;
246246 }
247 puts("loop");
247 puts(c"loop");
248248 loop(a - 1);
249249
250250 done:
......@@ -268,7 +268,7 @@ export fn _start() -> unreachable {
268268 let a : i32 = 1;
269269 let b = 2;
270270 if (a + b == 3) {
271 puts("OK");
271 puts(c"OK");
272272 }
273273 exit(0);
274274}
......@@ -282,10 +282,10 @@ extern {
282282}
283283
284284export fn _start() -> unreachable {
285 if (true) { puts("OK 1"); }
286 if (false) { puts("BAD 1"); }
287 if (!true) { puts("BAD 2"); }
288 if (!false) { puts("OK 2"); }
285 if (true) { puts(c"OK 1"); }
286 if (false) { puts(c"BAD 1"); }
287 if (!true) { puts(c"BAD 2"); }
288 if (!false) { puts(c"OK 2"); }
289289 exit(0);
290290}
291291 )SOURCE", "OK 1\nOK 2\n");
......@@ -300,14 +300,14 @@ extern {
300300export fn _start() -> unreachable {
301301 if (true) {
302302 let no_conflict = 5;
303 if (no_conflict == 5) { puts("OK 1"); }
303 if (no_conflict == 5) { puts(c"OK 1"); }
304304 }
305305
306306 let c = {
307307 let no_conflict = 10;
308308 no_conflict
309309 };
310 if (c == 10) { puts("OK 2"); }
310 if (c == 10) { puts(c"OK 2"); }
311311 exit(0);
312312}
313313 )SOURCE", "OK 1\nOK 2\n");
......@@ -327,7 +327,7 @@ export fn _start() -> unreachable {
327327fn void_fun(a : i32, b : void, c : i32) {
328328 let v = b;
329329 let vv : void = if (a == 1) {v} else {};
330 if (a + c == 3) { puts("OK"); }
330 if (a + c == 3) { puts(c"OK"); }
331331 return vv;
332332}
333333 )SOURCE", "OK\n");
......@@ -341,14 +341,14 @@ extern {
341341
342342export fn _start() -> unreachable {
343343 let mut zero : i32;
344 if (zero == 0) { puts("zero"); }
344 if (zero == 0) { puts(c"zero"); }
345345
346346 let mut i = 0;
347347loop_start:
348348 if i == 3 {
349349 goto done;
350350 }
351 puts("loop");
351 puts(c"loop");
352352 i = i + 1;
353353 goto loop_start;
354354done:
......@@ -391,7 +391,7 @@ loop_2_start:
391391loop_2_end:
392392
393393 if accumulator == 15 {
394 puts("OK");
394 puts(c"OK");
395395 }
396396
397397 exit(0);
......@@ -403,7 +403,7 @@ loop_2_end:
403403use "std.zig";
404404
405405export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
406 print_str("Hello, world!\n", 14 as isize);
406 print_str(c"Hello, world!\n", 14 as isize);
407407 return 0;
408408}
409409 )SOURCE", "Hello, world!\n");
......@@ -430,11 +430,11 @@ fn a() {}
430430
431431 add_compile_fail_case("unreachable with return", R"SOURCE(
432432fn a() -> unreachable {return;}
433 )SOURCE", 1, ".tmp_source.zig:2:24: error: type mismatch. expected unreachable. got void");
433 )SOURCE", 1, ".tmp_source.zig:2:24: error: expected type 'unreachable', got 'void'");
434434
435435 add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
436436fn a() -> i32 {}
437 )SOURCE", 1, ".tmp_source.zig:2:15: error: type mismatch. expected i32. got void");
437 )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got 'void'");
438438
439439 add_compile_fail_case("undefined function call", R"SOURCE(
440440fn a() {
......@@ -514,16 +514,16 @@ fn f(a : i32) {
514514
515515 add_compile_fail_case("variable has wrong type", R"SOURCE(
516516fn f() -> i32 {
517 let a = "a";
517 let a = c"a";
518518 a
519519}
520 )SOURCE", 1, ".tmp_source.zig:2:15: error: type mismatch. expected i32. got *const u8");
520 )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '*const u8'");
521521
522522 add_compile_fail_case("if condition is bool, not int", R"SOURCE(
523523fn f() {
524524 if (0) {}
525525}
526 )SOURCE", 1, ".tmp_source.zig:3:9: error: type mismatch. expected bool. got i32");
526 )SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got 'i32'");
527527
528528 add_compile_fail_case("assign unreachable", R"SOURCE(
529529fn f() {
......@@ -551,11 +551,11 @@ a_label:
551551}
552552 )SOURCE", 1, ".tmp_source.zig:3:1: error: label 'a_label' defined but not used");
553553
554 add_compile_fail_case("expected bare identifier", R"SOURCE(
554 add_compile_fail_case("bad assignment target", R"SOURCE(
555555fn f() {
556556 3 = 3;
557557}
558 )SOURCE", 1, ".tmp_source.zig:3:5: error: expected a bare identifier");
558 )SOURCE", 1, ".tmp_source.zig:3:5: error: assignment target must be variable, field, or array element");
559559
560560 add_compile_fail_case("assign to constant variable", R"SOURCE(
561561fn f() {