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...@@ -32,7 +32,11 @@ zig | C equivalent | Description
32```32```
33Root : many(TopLevelDecl) token(EOF)33Root : many(TopLevelDecl) token(EOF)
3434
35TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use35TopLevelDecl : 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
37Use : many(Directive) token(Use) token(String) token(Semicolon)41Use : many(Directive) token(Use) token(String) token(Semicolon)
3842
...@@ -126,7 +130,9 @@ CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression...@@ -126,7 +130,9 @@ CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression
126130
127PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression131PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression
128132
129SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)133SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression)
134
135FieldAccessExpression : token(Dot) token(Symbol)
130136
131FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)137FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
132138
...@@ -146,7 +152,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)...@@ -146,7 +152,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
146## Operator Precedence152## Operator Precedence
147153
148```154```
149x() x[]155x() x[] x.y
150!x -x ~x156!x -x ~x
151as157as
152* / %158* / %
...@@ -165,11 +171,11 @@ as...@@ -165,11 +171,11 @@ as
165171
166### Characters and Strings172### Characters and Strings
167173
168 | Example | Characters | Escapes | Null Terminated174 | Example | Characters | Escapes | Null Term | Type
169-------------------------------------------------------------------------------175---------------------------------------------------------------------------------
170 Byte | 'H' | All ASCII | Byte | No176 Byte | 'H' | All ASCII | Byte | No | u8
171 UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No177 UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No | [5; u8]
172 UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes178 UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes | *const u8
173179
174### Byte Escapes180### Byte Escapes
175181
doc/vim/syntax/zig.vim+1-1
...@@ -9,7 +9,7 @@ endif...@@ -9,7 +9,7 @@ endif
99
10syn keyword zigKeyword fn return mut const extern unreachable export pub as use while asm10syn keyword zigKeyword fn return mut const extern unreachable export pub as use while asm
11syn keyword zigKeyword if else let void goto type enum struct continue break match volatile11syn 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 f12812syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string
1313
14syn keyword zigConstant null14syn keyword zigConstant null
1515
example/hello_world/hello2.zig+1-1
...@@ -3,6 +3,6 @@ export executable "hello";...@@ -3,6 +3,6 @@ export executable "hello";
3use "std.zig";3use "std.zig";
44
5export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {5export 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");
7 return 0;7 return 0;
8}8}
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 @@...@@ -13,6 +13,11 @@
13static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,13static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
14 TypeTableEntry *expected_type, AstNode *node);14 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
16static AstNode *first_executing_node(AstNode *node) {21static AstNode *first_executing_node(AstNode *node) {
17 switch (node->type) {22 switch (node->type) {
18 case NodeTypeFnCallExpr:23 case NodeTypeFnCallExpr:
...@@ -44,6 +49,9 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -44,6 +49,9 @@ static AstNode *first_executing_node(AstNode *node) {
44 case NodeTypeLabel:49 case NodeTypeLabel:
45 case NodeTypeGoto:50 case NodeTypeGoto:
46 case NodeTypeAsmExpr:51 case NodeTypeAsmExpr:
52 case NodeTypeFieldAccessExpr:
53 case NodeTypeStructDecl:
54 case NodeTypeStructField:
47 return node;55 return node;
48 }56 }
49 zig_panic("unreachable");57 zig_panic("unreachable");
...@@ -129,6 +137,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in...@@ -129,6 +137,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in
129 entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, entry->size_in_bits,137 entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, entry->size_in_bits,
130 entry->align_in_bits, child_type->di_type, array_size);138 entry->align_in_bits, child_type->di_type, array_size);
131 entry->data.array.child_type = child_type;139 entry->data.array.child_type = child_type;
140 entry->data.array.len = array_size;
132141
133 g->type_table.put(&entry->name, entry);142 g->type_table.put(&entry->name, entry);
134 child_type->arrays_by_size.put(array_size, entry);143 child_type->arrays_by_size.put(array_size, entry);
...@@ -143,8 +152,7 @@ static int parse_int(Buf *number) {...@@ -143,8 +152,7 @@ static int parse_int(Buf *number) {
143152
144static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {153static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
145 assert(node->type == NodeTypeType);154 assert(node->type == NodeTypeType);
146 assert(!node->codegen_node);155 alloc_codegen_node(node);
147 node->codegen_node = allocate<CodeGenNode>(1);
148 TypeNode *type_node = &node->codegen_node->data.type_node;156 TypeNode *type_node = &node->codegen_node->data.type_node;
149 switch (node->data.type.type) {157 switch (node->data.type.type) {
150 case AstNodeTypeTypePrimitive:158 case AstNodeTypeTypePrimitive:
...@@ -259,8 +267,7 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_...@@ -259,8 +267,7 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_
259 Buf *name = &label_node->data.label.name;267 Buf *name = &label_node->data.label.name;
260 fn_table_entry->label_table.put(name, label_entry);268 fn_table_entry->label_table.put(name, label_entry);
261269
262 assert(!label_node->codegen_node);270 alloc_codegen_node(label_node);
263 label_node->codegen_node = allocate<CodeGenNode>(1);
264 label_node->codegen_node->data.label_entry = label_entry;271 label_node->codegen_node->data.label_entry = label_entry;
265 }272 }
266}273}
...@@ -302,8 +309,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -302,8 +309,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
302 g->fn_table.put(name, fn_table_entry);309 g->fn_table.put(name, fn_table_entry);
303 }310 }
304311
305 assert(!fn_proto->codegen_node);312 alloc_codegen_node(fn_proto);
306 fn_proto->codegen_node = allocate<CodeGenNode>(1);
307 fn_proto->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;313 fn_proto->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
308 }314 }
309 break;315 break;
...@@ -319,8 +325,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -319,8 +325,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
319 if (entry) {325 if (entry) {
320 add_node_error(g, node,326 add_node_error(g, node,
321 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));327 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
322 assert(!node->codegen_node);328 alloc_codegen_node(node);
323 node->codegen_node = allocate<CodeGenNode>(1);
324 node->codegen_node->data.fn_def_node.skip = true;329 node->codegen_node->data.fn_def_node.skip = true;
325 skip = true;330 skip = true;
326 } else if (is_pub) {331 } else if (is_pub) {
...@@ -328,8 +333,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -328,8 +333,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
328 if (entry) {333 if (entry) {
329 add_node_error(g, node,334 add_node_error(g, node,
330 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));335 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
331 assert(!node->codegen_node);336 alloc_codegen_node(node);
332 node->codegen_node = allocate<CodeGenNode>(1);
333 node->codegen_node->data.fn_def_node.skip = true;337 node->codegen_node->data.fn_def_node.skip = true;
334 skip = true;338 skip = true;
335 }339 }
...@@ -358,8 +362,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -358,8 +362,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
358 resolve_function_proto(g, proto_node, fn_table_entry);362 resolve_function_proto(g, proto_node, fn_table_entry);
359363
360364
361 assert(!proto_node->codegen_node);365 alloc_codegen_node(proto_node);
362 proto_node->codegen_node = allocate<CodeGenNode>(1);
363 proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;366 proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
364367
365 preview_function_labels(g, node->data.fn_def.body, fn_table_entry);368 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,...@@ -409,6 +412,31 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
409 buf_sprintf("root export declaration only valid in root source file"));412 buf_sprintf("root export declaration only valid in root source file"));
410 }413 }
411 break;414 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 }
412 case NodeTypeUse:440 case NodeTypeUse:
413 // nothing to do here441 // nothing to do here
414 break;442 break;
...@@ -436,6 +464,68 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -436,6 +464,68 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
436 case NodeTypeLabel:464 case NodeTypeLabel:
437 case NodeTypeGoto:465 case NodeTypeGoto:
438 case NodeTypeAsmExpr:466 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:
439 zig_unreachable();529 zig_unreachable();
440 }530 }
441}531}
...@@ -460,7 +550,9 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) {...@@ -460,7 +550,9 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) {
460 return fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;550 return fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
461}551}
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{
464 if (expected_type == nullptr)556 if (expected_type == nullptr)
465 return; // anything will do557 return; // anything will do
466 if (expected_type == actual_type)558 if (expected_type == actual_type)
...@@ -471,7 +563,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *...@@ -471,7 +563,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *
471 return; // sorry toots; gotta run. good luck with that expected type.563 return; // sorry toots; gotta run. good luck with that expected type.
472564
473 add_node_error(g, node,565 add_node_error(g, node,
474 buf_sprintf("type mismatch. expected %s. got %s",566 buf_sprintf("expected type '%s', got '%s'",
475 buf_ptr(&expected_type->name),567 buf_ptr(&expected_type->name),
476 buf_ptr(&actual_type->name)));568 buf_ptr(&actual_type->name)));
477}569}
...@@ -507,6 +599,55 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {...@@ -507,6 +599,55 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
507 }599 }
508}600}
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
510static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,651static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
511 AstNode *node)652 AstNode *node)
512{653{
...@@ -554,8 +695,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -554,8 +695,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
554 TypeTableEntry *expected_type, AstNode *node)695 TypeTableEntry *expected_type, AstNode *node)
555{696{
556 TypeTableEntry *return_type = nullptr;697 TypeTableEntry *return_type = nullptr;
557 assert(!node->codegen_node);698 alloc_codegen_node(node);
558 node->codegen_node = allocate<CodeGenNode>(1);
559 switch (node->type) {699 switch (node->type) {
560 case NodeTypeBlock:700 case NodeTypeBlock:
561 {701 {
...@@ -698,9 +838,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -698,9 +838,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
698 }838 }
699 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {839 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
700 expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);840 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);
701 } else {843 } else {
702 add_node_error(g, lhs_node,844 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"));
704 }846 }
705 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);847 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
706 return_type = g->builtin_types.entry_void;848 return_type = g->builtin_types.entry_void;
...@@ -835,15 +977,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -835,15 +977,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
835 // for reading array access; assignment handled elsewhere977 // for reading array access; assignment handled elsewhere
836 return_type = analyze_array_access_expr(g, import, context, node);978 return_type = analyze_array_access_expr(g, import, context, node);
837 break;979 break;
980 case NodeTypeFieldAccessExpr:
981 return_type = analyze_field_access_expr(g, import, context, node);
982 break;
838 case NodeTypeNumberLiteral:983 case NodeTypeNumberLiteral:
839 // TODO: generic literal int type984 // TODO: generic literal int type
840 return_type = g->builtin_types.entry_i32;985 return_type = g->builtin_types.entry_i32;
841 break;986 break;
842987
843 case NodeTypeStringLiteral:988 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 }
845 break;994 break;
846
847 case NodeTypeUnreachable:995 case NodeTypeUnreachable:
848 return_type = g->builtin_types.entry_unreachable;996 return_type = g->builtin_types.entry_unreachable;
849 break;997 break;
...@@ -884,7 +1032,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -884,7 +1032,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
884 {1032 {
885 return_type = wanted_type;1033 return_type = wanted_type;
886 } else {1034 } 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;
888 }1039 }
889 break;1040 break;
890 }1041 }
...@@ -946,6 +1097,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -946,6 +1097,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
946 case NodeTypeFnDef:1097 case NodeTypeFnDef:
947 case NodeTypeUse:1098 case NodeTypeUse:
948 case NodeTypeLabel:1099 case NodeTypeLabel:
1100 case NodeTypeStructDecl:
1101 case NodeTypeStructField:
949 zig_unreachable();1102 zig_unreachable();
950 }1103 }
951 assert(return_type);1104 assert(return_type);
...@@ -970,8 +1123,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -970,8 +1123,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
970 AstNode *fn_proto_node = node->data.fn_def.fn_proto;1123 AstNode *fn_proto_node = node->data.fn_def.fn_proto;
971 assert(fn_proto_node->type == NodeTypeFnProto);1124 assert(fn_proto_node->type == NodeTypeFnProto);
9721125
973 assert(!node->codegen_node);1126 alloc_codegen_node(node);
974 node->codegen_node = allocate<CodeGenNode>(1);
975 BlockContext *context = new_block_context(node, nullptr);1127 BlockContext *context = new_block_context(node, nullptr);
976 node->codegen_node->data.fn_def_node.block_context = context;1128 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,...@@ -1044,6 +1196,9 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
1044 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));1196 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
1045 }1197 }
1046 break;1198 break;
1199 case NodeTypeStructDecl:
1200 // nothing to do
1201 break;
1047 case NodeTypeDirective:1202 case NodeTypeDirective:
1048 case NodeTypeParamDecl:1203 case NodeTypeParamDecl:
1049 case NodeTypeFnProto:1204 case NodeTypeFnProto:
...@@ -1068,6 +1223,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -1068,6 +1223,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
1068 case NodeTypeLabel:1223 case NodeTypeLabel:
1069 case NodeTypeGoto:1224 case NodeTypeGoto:
1070 case NodeTypeAsmExpr:1225 case NodeTypeAsmExpr:
1226 case NodeTypeFieldAccessExpr:
1227 case NodeTypeStructField:
1071 zig_unreachable();1228 zig_unreachable();
1072 }1229 }
1073}1230}
...@@ -1082,6 +1239,16 @@ static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import...@@ -1082,6 +1239,16 @@ static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import
10821239
1083}1240}
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
1085static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {1252static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1086 assert(node->type == NodeTypeRoot);1253 assert(node->type == NodeTypeRoot);
10871254
...@@ -1092,6 +1259,17 @@ static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, A...@@ -1092,6 +1259,17 @@ static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, A
1092}1259}
10931260
1094void semantic_analyze(CodeGen *g) {1261void 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 }
1095 {1273 {
1096 auto it = g->import_table.entry_iterator();1274 auto it = g->import_table.entry_iterator();
1097 for (;;) {1275 for (;;) {
src/analyze.hpp+22-1
...@@ -28,6 +28,18 @@ struct TypeTableEntryInt {...@@ -28,6 +28,18 @@ struct TypeTableEntryInt {
2828
29struct TypeTableEntryArray {29struct TypeTableEntryArray {
30 TypeTableEntry *child_type;30 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;
31};43};
3244
33enum TypeTableEntryId {45enum TypeTableEntryId {
...@@ -39,6 +51,7 @@ enum TypeTableEntryId {...@@ -39,6 +51,7 @@ enum TypeTableEntryId {
39 TypeTableEntryIdFloat,51 TypeTableEntryIdFloat,
40 TypeTableEntryIdPointer,52 TypeTableEntryIdPointer,
41 TypeTableEntryIdArray,53 TypeTableEntryIdArray,
54 TypeTableEntryIdStruct,
42};55};
4356
44struct TypeTableEntry {57struct TypeTableEntry {
...@@ -55,6 +68,7 @@ struct TypeTableEntry {...@@ -55,6 +68,7 @@ struct TypeTableEntry {
55 TypeTableEntryPointer pointer;68 TypeTableEntryPointer pointer;
56 TypeTableEntryInt integral;69 TypeTableEntryInt integral;
57 TypeTableEntryArray array;70 TypeTableEntryArray array;
71 TypeTableEntryStruct structure;
58 } data;72 } data;
5973
60 // use these fields to make sure we don't duplicate type table entries for the same type74 // use these fields to make sure we don't duplicate type table entries for the same type
...@@ -122,8 +136,10 @@ struct CodeGen {...@@ -122,8 +136,10 @@ struct CodeGen {
122 TypeTableEntry *entry_u8;136 TypeTableEntry *entry_u8;
123 TypeTableEntry *entry_i32;137 TypeTableEntry *entry_i32;
124 TypeTableEntry *entry_isize;138 TypeTableEntry *entry_isize;
139 TypeTableEntry *entry_usize;
125 TypeTableEntry *entry_f32;140 TypeTableEntry *entry_f32;
126 TypeTableEntry *entry_string_literal;141 TypeTableEntry *entry_c_string_literal;
142 TypeTableEntry *entry_string;
127 TypeTableEntry *entry_void;143 TypeTableEntry *entry_void;
128 TypeTableEntry *entry_unreachable;144 TypeTableEntry *entry_unreachable;
129 TypeTableEntry *entry_invalid;145 TypeTableEntry *entry_invalid;
...@@ -211,6 +227,10 @@ struct BlockNode {...@@ -211,6 +227,10 @@ struct BlockNode {
211 BlockContext *block_context;227 BlockContext *block_context;
212};228};
213229
230struct StructDeclNode {
231 TypeTableEntry *type_entry;
232};
233
214struct CodeGenNode {234struct CodeGenNode {
215 union {235 union {
216 TypeNode type_node; // for NodeTypeType236 TypeNode type_node; // for NodeTypeType
...@@ -219,6 +239,7 @@ struct CodeGenNode {...@@ -219,6 +239,7 @@ struct CodeGenNode {
219 LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel239 LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel
220 AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign240 AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign
221 BlockNode block_node; // for NodeTypeBlock241 BlockNode block_node; // for NodeTypeBlock
242 StructDeclNode struct_decl_node; // for NodeTypeStructDecl
222 } data;243 } data;
223 ExprNode expr_node; // for all the expression nodes244 ExprNode expr_node; // for all the expression nodes
224};245};
src/codegen.cpp+83-8
...@@ -106,12 +106,12 @@ static void add_debug_source_node(CodeGen *g, AstNode *node) {...@@ -106,12 +106,12 @@ static void add_debug_source_node(CodeGen *g, AstNode *node) {
106 g->cur_block_context->di_scope);106 g->cur_block_context->di_scope);
107}107}
108108
109static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) {109static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
110 auto entry = g->str_table.maybe_get(str);110 auto entry = g->str_table.maybe_get(str);
111 if (entry) {111 if (entry) {
112 return entry->value;112 return entry->value;
113 }113 }
114 LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), false);114 LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), !c);
115 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), "");115 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), "");
116 LLVMSetLinkage(global_value, LLVMPrivateLinkage);116 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
117 LLVMSetInitializer(global_value, text);117 LLVMSetInitializer(global_value, text);
...@@ -204,6 +204,28 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {...@@ -204,6 +204,28 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
204 return LLVMBuildLoad(g->builder, ptr, "");204 return LLVMBuildLoad(g->builder, ptr, "");
205}205}
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
207static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {229static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
208 assert(node->type == NodeTypePrefixOpExpr);230 assert(node->type == NodeTypePrefixOpExpr);
209 assert(node->data.prefix_op_expr.primary_expr);231 assert(node->data.prefix_op_expr.primary_expr);
...@@ -785,6 +807,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -785,6 +807,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
785 return gen_fn_call_expr(g, node);807 return gen_fn_call_expr(g, node);
786 case NodeTypeArrayAccessExpr:808 case NodeTypeArrayAccessExpr:
787 return gen_array_access_expr(g, node);809 return gen_array_access_expr(g, node);
810 case NodeTypeFieldAccessExpr:
811 return gen_field_access_expr(g, node);
788 case NodeTypeUnreachable:812 case NodeTypeUnreachable:
789 add_debug_source_node(g, node);813 add_debug_source_node(g, node);
790 return LLVMBuildUnreachable(g->builder);814 return LLVMBuildUnreachable(g->builder);
...@@ -809,8 +833,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -809,8 +833,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
809 }833 }
810 case NodeTypeStringLiteral:834 case NodeTypeStringLiteral:
811 {835 {
812 Buf *str = &node->data.string;836 Buf *str = &node->data.string_literal.buf;
813 LLVMValueRef str_val = find_or_create_string(g, str);837 LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c);
814 LLVMValueRef indices[] = {838 LLVMValueRef indices[] = {
815 LLVMConstInt(LLVMInt32Type(), 0, false),839 LLVMConstInt(LLVMInt32Type(), 0, false),
816 LLVMConstInt(LLVMInt32Type(), 0, false)840 LLVMConstInt(LLVMInt32Type(), 0, false)
...@@ -864,6 +888,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -864,6 +888,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
864 case NodeTypeExternBlock:888 case NodeTypeExternBlock:
865 case NodeTypeDirective:889 case NodeTypeDirective:
866 case NodeTypeUse:890 case NodeTypeUse:
891 case NodeTypeStructDecl:
892 case NodeTypeStructField:
867 zig_unreachable();893 zig_unreachable();
868 }894 }
869 zig_unreachable();895 zig_unreachable();
...@@ -1072,7 +1098,7 @@ static void do_code_gen(CodeGen *g) {...@@ -1072,7 +1098,7 @@ static void do_code_gen(CodeGen *g) {
1072#endif1098#endif
1073}1099}
10741100
1075static void define_primitive_types(CodeGen *g) {1101static void define_builtin_types(CodeGen *g) {
1076 {1102 {
1077 // if this type is anywhere in the AST, we should never hit codegen.1103 // if this type is anywhere in the AST, we should never hit codegen.
1078 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInvalid);1104 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInvalid);
...@@ -1103,7 +1129,7 @@ static void define_primitive_types(CodeGen *g) {...@@ -1103,7 +1129,7 @@ static void define_primitive_types(CodeGen *g) {
1103 g->type_table.put(&entry->name, entry);1129 g->type_table.put(&entry->name, entry);
1104 g->builtin_types.entry_u8 = entry;1130 g->builtin_types.entry_u8 = entry;
1105 }1131 }
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);
1107 {1133 {
1108 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);1134 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1109 entry->type_ref = LLVMInt32Type();1135 entry->type_ref = LLVMInt32Type();
...@@ -1130,6 +1156,19 @@ static void define_primitive_types(CodeGen *g) {...@@ -1130,6 +1156,19 @@ static void define_primitive_types(CodeGen *g) {
1130 g->type_table.put(&entry->name, entry);1156 g->type_table.put(&entry->name, entry);
1131 g->builtin_types.entry_isize = entry;1157 g->builtin_types.entry_isize = entry;
1132 }1158 }
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 }
1133 {1172 {
1134 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);1173 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
1135 entry->type_ref = LLVMFloatType();1174 entry->type_ref = LLVMFloatType();
...@@ -1160,6 +1199,43 @@ static void define_primitive_types(CodeGen *g) {...@@ -1160,6 +1199,43 @@ static void define_primitive_types(CodeGen *g) {
1160 g->type_table.put(&entry->name, entry);1199 g->type_table.put(&entry->name, entry);
1161 g->builtin_types.entry_unreachable = entry;1200 g->builtin_types.entry_unreachable = entry;
1162 }1201 }
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 }
1163}1239}
11641240
11651241
...@@ -1213,8 +1289,6 @@ static void init(CodeGen *g, Buf *source_path) {...@@ -1213,8 +1289,6 @@ static void init(CodeGen *g, Buf *source_path) {
1213 LLVMZigSetFastMath(g->builder, true);1289 LLVMZigSetFastMath(g->builder, true);
12141290
12151291
1216 define_primitive_types(g);
1217
1218 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);1292 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
1219 bool is_optimized = g->build_type == CodeGenBuildTypeRelease;1293 bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
1220 const char *flags = "";1294 const char *flags = "";
...@@ -1224,6 +1298,7 @@ static void init(CodeGen *g, Buf *source_path) {...@@ -1224,6 +1298,7 @@ static void init(CodeGen *g, Buf *source_path) {
1224 buf_ptr(producer), is_optimized, flags, runtime_version,1298 buf_ptr(producer), is_optimized, flags, runtime_version,
1225 "", 0, !g->strip_debug_symbols);1299 "", 0, !g->strip_debug_symbols);
12261300
1301 define_builtin_types(g);
12271302
1228}1303}
12291304
src/parser.cpp+126-30
...@@ -106,6 +106,12 @@ const char *node_type_str(NodeType node_type) {...@@ -106,6 +106,12 @@ const char *node_type_str(NodeType node_type) {
106 return "Label";106 return "Label";
107 case NodeTypeAsmExpr:107 case NodeTypeAsmExpr:
108 return "AsmExpr";108 return "AsmExpr";
109 case NodeTypeFieldAccessExpr:
110 return "FieldAccessExpr";
111 case NodeTypeStructDecl:
112 return "StructDecl";
113 case NodeTypeStructField:
114 return "StructField";
109 }115 }
110 zig_unreachable();116 zig_unreachable();
111}117}
...@@ -259,9 +265,12 @@ void ast_print(AstNode *node, int indent) {...@@ -259,9 +265,12 @@ void ast_print(AstNode *node, int indent) {
259 buf_ptr(&node->data.number));265 buf_ptr(&node->data.number));
260 break;266 break;
261 case NodeTypeStringLiteral:267 case NodeTypeStringLiteral:
262 fprintf(stderr, "StringLiteral '%s'\n",268 {
263 buf_ptr(&node->data.string));269 const char *c = node->data.string_literal.c ? "c" : "";
264 break;270 fprintf(stderr, "StringLiteral %s'%s'\n", c,
271 buf_ptr(&node->data.string_literal.buf));
272 break;
273 }
265 case NodeTypeUnreachable:274 case NodeTypeUnreachable:
266 fprintf(stderr, "Unreachable\n");275 fprintf(stderr, "Unreachable\n");
267 break;276 break;
...@@ -295,6 +304,19 @@ void ast_print(AstNode *node, int indent) {...@@ -295,6 +304,19 @@ void ast_print(AstNode *node, int indent) {
295 case NodeTypeAsmExpr:304 case NodeTypeAsmExpr:
296 fprintf(stderr, "%s\n", node_type_str(node->type));305 fprintf(stderr, "%s\n", node_type_str(node->type));
297 break;306 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;
298 }320 }
299}321}
300322
...@@ -475,18 +497,28 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {...@@ -475,18 +497,28 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
475 }497 }
476}498}
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{
479 // skip the double quotes at beginning and end503 // skip the double quotes at beginning and end
480 // convert escape sequences504 // convert escape sequences
505 // detect c string literal
481506
482 buf_resize(buf, 0);507 buf_resize(buf, 0);
483 bool escape = false;508 bool escape = false;
484 bool first = true;509 bool skip_quote;
485 SrcPos pos = {token->start_line, token->start_column};510 SrcPos pos = {token->start_line, token->start_column};
486 for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {511 for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {
487 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);512 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
488 if (first) {513 if (i == token->start_pos) {
489 first = false;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;
490 } else {522 } else {
491 if (escape) {523 if (escape) {
492 switch (c) {524 switch (c) {
...@@ -541,13 +573,20 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma...@@ -541,13 +573,20 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma
541static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);573static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);
542static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);574static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);
543575
544
545static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {576static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
546 if (token->id != token_id) {577 if (token->id != token_id) {
547 ast_invalid_token_error(pc, token);578 ast_invalid_token_error(pc, token);
548 }579 }
549}580}
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
551static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) {590static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) {
552 Token *number_sign = &pc->tokens->at(token_index);591 Token *number_sign = &pc->tokens->at(token_index);
553 token_index += 1;592 token_index += 1;
...@@ -569,7 +608,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_...@@ -569,7 +608,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_
569 token_index += 1;608 token_index += 1;
570 ast_expect_token(pc, param_str, TokenIdStringLiteral);609 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
574 Token *r_paren = &pc->tokens->at(token_index);613 Token *r_paren = &pc->tokens->at(token_index);
575 token_index += 1;614 token_index += 1;
...@@ -782,7 +821,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -782,7 +821,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
782 return node;821 return node;
783 } else if (token->id == TokenIdStringLiteral) {822 } else if (token->id == TokenIdStringLiteral) {
784 AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token);823 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);
786 *token_index += 1;825 *token_index += 1;
787 return node;826 return node;
788 } else if (token->id == TokenIdKeywordUnreachable) {827 } else if (token->id == TokenIdKeywordUnreachable) {
...@@ -832,9 +871,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -832,9 +871,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
832}871}
833872
834/*873/*
835SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)874SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression)
836FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)875FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
837ArrayAccessExpression : token(LBracket) Expression token(RBracket)876ArrayAccessExpression : token(LBracket) Expression token(RBracket)
877FieldAccessExpression : token(Dot) token(Symbol)
838*/878*/
839static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {879static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
840 AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);880 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...@@ -861,6 +901,16 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
861 *token_index += 1;901 *token_index += 1;
862 ast_expect_token(pc, r_bracket, TokenIdRBracket);902 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
864 return node;914 return node;
865 } else {915 } else {
866 return primary_expr;916 return primary_expr;
...@@ -1397,14 +1447,6 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand...@@ -1397,14 +1447,6 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
1397 return node;1447 return node;
1398}1448}
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
1408/*1450/*
1409AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)1451AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
1410*/1452*/
...@@ -1421,7 +1463,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode...@@ -1421,7 +1463,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode
14211463
1422 AsmInput *asm_input = allocate<AsmInput>(1);1464 AsmInput *asm_input = allocate<AsmInput>(1);
1423 ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name);1465 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);
1425 asm_input->expr = expr_node;1467 asm_input->expr = expr_node;
1426 node->data.asm_expr.input_list.append(asm_input);1468 node->data.asm_expr.input_list.append(asm_input);
1427}1469}
...@@ -1442,7 +1484,7 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod...@@ -1442,7 +1484,7 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod
14421484
1443 AsmOutput *asm_output = allocate<AsmOutput>(1);1485 AsmOutput *asm_output = allocate<AsmOutput>(1);
1444 ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);1486 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);
1446 ast_buf_from_token(pc, out_symbol, &asm_output->variable_name);1488 ast_buf_from_token(pc, out_symbol, &asm_output->variable_name);
1447 node->data.asm_expr.output_list.append(asm_output);1489 node->data.asm_expr.output_list.append(asm_output);
1448}1490}
...@@ -1464,7 +1506,7 @@ static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *...@@ -1464,7 +1506,7 @@ static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *
1464 *token_index += 1;1506 *token_index += 1;
14651507
1466 Buf *clobber_buf = buf_alloc();1508 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);
1468 node->data.asm_expr.clobber_list.append(clobber_buf);1510 node->data.asm_expr.clobber_list.append(clobber_buf);
14691511
1470 Token *comma = &pc->tokens->at(*token_index);1512 Token *comma = &pc->tokens->at(*token_index);
...@@ -1565,7 +1607,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand...@@ -1565,7 +1607,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
1565 ast_expect_token(pc, template_tok, TokenIdStringLiteral);1607 ast_expect_token(pc, template_tok, TokenIdStringLiteral);
1566 *token_index += 1;1608 *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,
1569 &node->data.asm_expr.offset_map);1611 &node->data.asm_expr.offset_map);
1570 parse_asm_template(pc, node);1612 parse_asm_template(pc, node);
15711613
...@@ -1877,7 +1919,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b...@@ -1877,7 +1919,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
1877 *token_index += 1;1919 *token_index += 1;
1878 ast_expect_token(pc, export_name, TokenIdStringLiteral);1920 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
1882 Token *semicolon = &pc->tokens->at(*token_index);1924 Token *semicolon = &pc->tokens->at(*token_index);
1883 *token_index += 1;1925 *token_index += 1;
...@@ -1889,9 +1931,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b...@@ -1889,9 +1931,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
1889/*1931/*
1890Use : many(Directive) token(Use) token(String) token(Semicolon)1932Use : many(Directive) token(Use) token(String) token(Semicolon)
1891*/1933*/
1892static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory) {1934static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
1893 assert(mandatory == false);
1894
1895 Token *use_kw = &pc->tokens->at(*token_index);1935 Token *use_kw = &pc->tokens->at(*token_index);
1896 if (use_kw->id != TokenIdKeywordUse)1936 if (use_kw->id != TokenIdKeywordUse)
1897 return nullptr;1937 return nullptr;
...@@ -1907,7 +1947,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory...@@ -1907,7 +1947,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
19071947
1908 AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);1948 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
1912 node->data.use.directives = pc->directive_list;1952 node->data.use.directives = pc->directive_list;
1913 pc->directive_list = nullptr;1953 pc->directive_list = nullptr;
...@@ -1916,7 +1956,57 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory...@@ -1916,7 +1956,57 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
1916}1956}
19171957
1918/*1958/*
1919TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use1959StructDecl : 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
1920*/2010*/
1921static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {2011static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
1922 for (;;) {2012 for (;;) {
...@@ -1943,12 +2033,18 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis...@@ -1943,12 +2033,18 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
1943 continue;2033 continue;
1944 }2034 }
19452035
1946 AstNode *use_node = ast_parse_use(pc, token_index, false);2036 AstNode *use_node = ast_parse_use(pc, token_index);
1947 if (use_node) {2037 if (use_node) {
1948 top_level_decls->append(use_node);2038 top_level_decls->append(use_node);
1949 continue;2039 continue;
1950 }2040 }
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
1952 if (pc->directive_list->length > 0) {2048 if (pc->directive_list->length > 0) {
1953 ast_error(pc, directive_token, "invalid directive");2049 ast_error(pc, directive_token, "invalid directive");
1954 }2050 }
src/parser.hpp+28-1
...@@ -40,6 +40,7 @@ enum NodeType {...@@ -40,6 +40,7 @@ enum NodeType {
40 NodeTypePrefixOpExpr,40 NodeTypePrefixOpExpr,
41 NodeTypeFnCallExpr,41 NodeTypeFnCallExpr,
42 NodeTypeArrayAccessExpr,42 NodeTypeArrayAccessExpr,
43 NodeTypeFieldAccessExpr,
43 NodeTypeUse,44 NodeTypeUse,
44 NodeTypeVoid,45 NodeTypeVoid,
45 NodeTypeBoolLiteral,46 NodeTypeBoolLiteral,
...@@ -47,6 +48,8 @@ enum NodeType {...@@ -47,6 +48,8 @@ enum NodeType {
47 NodeTypeLabel,48 NodeTypeLabel,
48 NodeTypeGoto,49 NodeTypeGoto,
49 NodeTypeAsmExpr,50 NodeTypeAsmExpr,
51 NodeTypeStructDecl,
52 NodeTypeStructField,
50};53};
5154
52struct AstNodeRoot {55struct AstNodeRoot {
...@@ -152,6 +155,11 @@ struct AstNodeArrayAccessExpr {...@@ -152,6 +155,11 @@ struct AstNodeArrayAccessExpr {
152 AstNode *subscript;155 AstNode *subscript;
153};156};
154157
158struct AstNodeFieldAccessExpr {
159 AstNode *struct_expr;
160 Buf field_name;
161};
162
155struct AstNodeExternBlock {163struct AstNodeExternBlock {
156 ZigList<AstNode *> *directives;164 ZigList<AstNode *> *directives;
157 ZigList<AstNode *> fn_decls;165 ZigList<AstNode *> fn_decls;
...@@ -231,6 +239,22 @@ struct AstNodeAsmExpr {...@@ -231,6 +239,22 @@ struct AstNodeAsmExpr {
231 ZigList<Buf*> clobber_list;239 ZigList<Buf*> clobber_list;
232};240};
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
234struct AstNode {258struct AstNode {
235 enum NodeType type;259 enum NodeType type;
236 int line;260 int line;
...@@ -260,8 +284,11 @@ struct AstNode {...@@ -260,8 +284,11 @@ struct AstNode {
260 AstNodeLabel label;284 AstNodeLabel label;
261 AstNodeGoto go_to;285 AstNodeGoto go_to;
262 AstNodeAsmExpr asm_expr;286 AstNodeAsmExpr asm_expr;
287 AstNodeFieldAccessExpr field_access_expr;
288 AstNodeStructDecl struct_decl;
289 AstNodeStructField struct_field;
290 AstNodeStringLiteral string_literal;
263 Buf number;291 Buf number;
264 Buf string;
265 Buf symbol;292 Buf symbol;
266 bool bool_literal;293 bool bool_literal;
267 } data;294 } data;
src/tokenizer.cpp+31-3
...@@ -28,10 +28,9 @@...@@ -28,10 +28,9 @@
28 case '8': \28 case '8': \
29 case '9'29 case '9'
3030
31#define ALPHA \31#define ALPHA_EXCEPT_C \
32 'a': \32 'a': \
33 case 'b': \33 case 'b': \
34 case 'c': \
35 case 'd': \34 case 'd': \
36 case 'e': \35 case 'e': \
37 case 'f': \36 case 'f': \
...@@ -82,6 +81,10 @@...@@ -82,6 +81,10 @@
82 case 'Y': \81 case 'Y': \
83 case 'Z'82 case 'Z'
8483
84#define ALPHA \
85 ALPHA_EXCEPT_C: \
86 case 'c'
87
85#define SYMBOL_CHAR \88#define SYMBOL_CHAR \
86 ALPHA: \89 ALPHA: \
87 case DIGIT: \90 case DIGIT: \
...@@ -90,6 +93,7 @@...@@ -90,6 +93,7 @@
90enum TokenizeState {93enum TokenizeState {
91 TokenizeStateStart,94 TokenizeStateStart,
92 TokenizeStateSymbol,95 TokenizeStateSymbol,
96 TokenizeStateSymbolFirst,
93 TokenizeStateNumber,97 TokenizeStateNumber,
94 TokenizeStateString,98 TokenizeStateString,
95 TokenizeStateSawDash,99 TokenizeStateSawDash,
...@@ -201,6 +205,8 @@ static void end_token(Tokenize *t) {...@@ -201,6 +205,8 @@ static void end_token(Tokenize *t) {
201 t->cur_tok->id = TokenIdKeywordVolatile;205 t->cur_tok->id = TokenIdKeywordVolatile;
202 } else if (mem_eql_str(token_mem, token_len, "asm")) {206 } else if (mem_eql_str(token_mem, token_len, "asm")) {
203 t->cur_tok->id = TokenIdKeywordAsm;207 t->cur_tok->id = TokenIdKeywordAsm;
208 } else if (mem_eql_str(token_mem, token_len, "struct")) {
209 t->cur_tok->id = TokenIdKeywordStruct;
204 }210 }
205211
206 t->cur_tok = nullptr;212 t->cur_tok = nullptr;
...@@ -224,7 +230,11 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -224,7 +230,11 @@ void tokenize(Buf *buf, Tokenization *out) {
224 switch (c) {230 switch (c) {
225 case WHITESPACE:231 case WHITESPACE:
226 break;232 break;
227 case ALPHA:233 case 'c':
234 t.state = TokenizeStateSymbolFirst;
235 begin_token(&t, TokenIdSymbol);
236 break;
237 case ALPHA_EXCEPT_C:
228 case '_':238 case '_':
229 t.state = TokenizeStateSymbol;239 t.state = TokenizeStateSymbol;
230 begin_token(&t, TokenIdSymbol);240 begin_token(&t, TokenIdSymbol);
...@@ -526,6 +536,22 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -526,6 +536,22 @@ void tokenize(Buf *buf, Tokenization *out) {
526 break;536 break;
527 }537 }
528 break;538 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;
529 case TokenizeStateSymbol:555 case TokenizeStateSymbol:
530 switch (c) {556 switch (c) {
531 case SYMBOL_CHAR:557 case SYMBOL_CHAR:
...@@ -589,6 +615,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -589,6 +615,7 @@ void tokenize(Buf *buf, Tokenization *out) {
589 tokenize_error(&t, "unterminated string");615 tokenize_error(&t, "unterminated string");
590 break;616 break;
591 case TokenizeStateSymbol:617 case TokenizeStateSymbol:
618 case TokenizeStateSymbolFirst:
592 case TokenizeStateNumber:619 case TokenizeStateNumber:
593 case TokenizeStateSawDash:620 case TokenizeStateSawDash:
594 case TokenizeStatePipe:621 case TokenizeStatePipe:
...@@ -643,6 +670,7 @@ static const char * token_name(Token *token) {...@@ -643,6 +670,7 @@ static const char * token_name(Token *token) {
643 case TokenIdKeywordGoto: return "Goto";670 case TokenIdKeywordGoto: return "Goto";
644 case TokenIdKeywordVolatile: return "Volatile";671 case TokenIdKeywordVolatile: return "Volatile";
645 case TokenIdKeywordAsm: return "Asm";672 case TokenIdKeywordAsm: return "Asm";
673 case TokenIdKeywordStruct: return "Struct";
646 case TokenIdLParen: return "LParen";674 case TokenIdLParen: return "LParen";
647 case TokenIdRParen: return "RParen";675 case TokenIdRParen: return "RParen";
648 case TokenIdComma: return "Comma";676 case TokenIdComma: return "Comma";
src/tokenizer.hpp+1
...@@ -32,6 +32,7 @@ enum TokenId {...@@ -32,6 +32,7 @@ enum TokenId {
32 TokenIdKeywordGoto,32 TokenIdKeywordGoto,
33 TokenIdKeywordAsm,33 TokenIdKeywordAsm,
34 TokenIdKeywordVolatile,34 TokenIdKeywordVolatile,
35 TokenIdKeywordStruct,
35 TokenIdLParen,36 TokenIdLParen,
36 TokenIdRParen,37 TokenIdRParen,
37 TokenIdComma,38 TokenIdComma,
src/zig_llvm.cpp+25
...@@ -161,6 +161,31 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder, uint64_t...@@ -161,6 +161,31 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder, uint64_t
161 return reinterpret_cast<LLVMZigDIType*>(di_type);161 return reinterpret_cast<LLVMZigDIType*>(di_type);
162}162}
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
164LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,189LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
165 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags)190 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags)
166{191{
src/zig_llvm.hpp+5
...@@ -49,6 +49,11 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder,...@@ -49,6 +49,11 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder,
49 uint64_t size_in_bits, uint64_t align_in_bits, LLVMZigDIType *elem_type,49 uint64_t size_in_bits, uint64_t align_in_bits, LLVMZigDIType *elem_type,
50 int elem_count);50 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
53LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,58LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
54 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags);59 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 {...@@ -17,8 +17,11 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
17// TODO zig strings instead of C strings17// TODO zig strings instead of C strings
18// TODO handle buffering and flushing18// TODO handle buffering and flushing
19// TODO non-i32 integer literals so we can remove the casts19// 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 {
21 let SYS_write = 1;23 let SYS_write = 1;
22 let stdout_fileno = 1;24 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);
24}27}
test/run_tests.cpp+30-30
...@@ -104,7 +104,7 @@ static void add_compiling_test_cases(void) {...@@ -104,7 +104,7 @@ static void add_compiling_test_cases(void) {
104 }104 }
105105
106 export fn _start() -> unreachable {106 export fn _start() -> unreachable {
107 puts("Hello, world!");107 puts(c"Hello, world!");
108 exit(0);108 exit(0);
109 }109 }
110 )SOURCE", "Hello, world!\n");110 )SOURCE", "Hello, world!\n");
...@@ -126,7 +126,7 @@ static void add_compiling_test_cases(void) {...@@ -126,7 +126,7 @@ static void add_compiling_test_cases(void) {
126 }126 }
127127
128 fn this_is_a_function() -> unreachable {128 fn this_is_a_function() -> unreachable {
129 puts("OK");129 puts(c"OK");
130 exit(0);130 exit(0);
131 }131 }
132 )SOURCE", "OK\n");132 )SOURCE", "OK\n");
...@@ -146,7 +146,7 @@ static void add_compiling_test_cases(void) {...@@ -146,7 +146,7 @@ static void add_compiling_test_cases(void) {
146 /// this is a documentation comment146 /// this is a documentation comment
147 /// doc comment line 2147 /// doc comment line 2
148 export fn _start() -> unreachable {148 export fn _start() -> unreachable {
149 puts(/* mid-line comment /* nested */ */ "OK");149 puts(/* mid-line comment /* nested */ */ c"OK");
150 exit(0);150 exit(0);
151 }151 }
152 )SOURCE", "OK\n");152 )SOURCE", "OK\n");
...@@ -180,7 +180,7 @@ static void add_compiling_test_cases(void) {...@@ -180,7 +180,7 @@ static void add_compiling_test_cases(void) {
180 // purposefully conflicting function with main source file180 // purposefully conflicting function with main source file
181 // but it's private so it should be OK181 // but it's private so it should be OK
182 fn private_function() {182 fn private_function() {
183 puts("OK");183 puts(c"OK");
184 }184 }
185185
186 pub fn print_text() {186 pub fn print_text() {
...@@ -198,17 +198,17 @@ static void add_compiling_test_cases(void) {...@@ -198,17 +198,17 @@ static void add_compiling_test_cases(void) {
198198
199 export fn _start() -> unreachable {199 export fn _start() -> unreachable {
200 if 1 != 0 {200 if 1 != 0 {
201 puts("1 is true");201 puts(c"1 is true");
202 } else {202 } else {
203 puts("1 is false");203 puts(c"1 is false");
204 }204 }
205 if 0 != 0 {205 if 0 != 0 {
206 puts("0 is true");206 puts(c"0 is true");
207 } else if 1 - 1 != 0 {207 } else if 1 - 1 != 0 {
208 puts("1 - 1 is true");208 puts(c"1 - 1 is true");
209 }209 }
210 if !(0 != 0) {210 if !(0 != 0) {
211 puts("!0 is true");211 puts(c"!0 is true");
212 }212 }
213 exit(0);213 exit(0);
214 }214 }
...@@ -227,7 +227,7 @@ static void add_compiling_test_cases(void) {...@@ -227,7 +227,7 @@ static void add_compiling_test_cases(void) {
227227
228 export fn _start() -> unreachable {228 export fn _start() -> unreachable {
229 if add(22, 11) == 33 {229 if add(22, 11) == 33 {
230 puts("pass");230 puts(c"pass");
231 }231 }
232 exit(0);232 exit(0);
233 }233 }
...@@ -244,7 +244,7 @@ static void add_compiling_test_cases(void) {...@@ -244,7 +244,7 @@ static void add_compiling_test_cases(void) {
244 if a == 0 {244 if a == 0 {
245 goto done;245 goto done;
246 }246 }
247 puts("loop");247 puts(c"loop");
248 loop(a - 1);248 loop(a - 1);
249249
250 done:250 done:
...@@ -268,7 +268,7 @@ export fn _start() -> unreachable {...@@ -268,7 +268,7 @@ export fn _start() -> unreachable {
268 let a : i32 = 1;268 let a : i32 = 1;
269 let b = 2;269 let b = 2;
270 if (a + b == 3) {270 if (a + b == 3) {
271 puts("OK");271 puts(c"OK");
272 }272 }
273 exit(0);273 exit(0);
274}274}
...@@ -282,10 +282,10 @@ extern {...@@ -282,10 +282,10 @@ extern {
282}282}
283283
284export fn _start() -> unreachable {284export fn _start() -> unreachable {
285 if (true) { puts("OK 1"); }285 if (true) { puts(c"OK 1"); }
286 if (false) { puts("BAD 1"); }286 if (false) { puts(c"BAD 1"); }
287 if (!true) { puts("BAD 2"); }287 if (!true) { puts(c"BAD 2"); }
288 if (!false) { puts("OK 2"); }288 if (!false) { puts(c"OK 2"); }
289 exit(0);289 exit(0);
290}290}
291 )SOURCE", "OK 1\nOK 2\n");291 )SOURCE", "OK 1\nOK 2\n");
...@@ -300,14 +300,14 @@ extern {...@@ -300,14 +300,14 @@ extern {
300export fn _start() -> unreachable {300export fn _start() -> unreachable {
301 if (true) {301 if (true) {
302 let no_conflict = 5;302 let no_conflict = 5;
303 if (no_conflict == 5) { puts("OK 1"); }303 if (no_conflict == 5) { puts(c"OK 1"); }
304 }304 }
305305
306 let c = {306 let c = {
307 let no_conflict = 10;307 let no_conflict = 10;
308 no_conflict308 no_conflict
309 };309 };
310 if (c == 10) { puts("OK 2"); }310 if (c == 10) { puts(c"OK 2"); }
311 exit(0);311 exit(0);
312}312}
313 )SOURCE", "OK 1\nOK 2\n");313 )SOURCE", "OK 1\nOK 2\n");
...@@ -327,7 +327,7 @@ export fn _start() -> unreachable {...@@ -327,7 +327,7 @@ export fn _start() -> unreachable {
327fn void_fun(a : i32, b : void, c : i32) {327fn void_fun(a : i32, b : void, c : i32) {
328 let v = b;328 let v = b;
329 let vv : void = if (a == 1) {v} else {};329 let vv : void = if (a == 1) {v} else {};
330 if (a + c == 3) { puts("OK"); }330 if (a + c == 3) { puts(c"OK"); }
331 return vv;331 return vv;
332}332}
333 )SOURCE", "OK\n");333 )SOURCE", "OK\n");
...@@ -341,14 +341,14 @@ extern {...@@ -341,14 +341,14 @@ extern {
341341
342export fn _start() -> unreachable {342export fn _start() -> unreachable {
343 let mut zero : i32;343 let mut zero : i32;
344 if (zero == 0) { puts("zero"); }344 if (zero == 0) { puts(c"zero"); }
345345
346 let mut i = 0;346 let mut i = 0;
347loop_start:347loop_start:
348 if i == 3 {348 if i == 3 {
349 goto done;349 goto done;
350 }350 }
351 puts("loop");351 puts(c"loop");
352 i = i + 1;352 i = i + 1;
353 goto loop_start;353 goto loop_start;
354done:354done:
...@@ -391,7 +391,7 @@ loop_2_start:...@@ -391,7 +391,7 @@ loop_2_start:
391loop_2_end:391loop_2_end:
392392
393 if accumulator == 15 {393 if accumulator == 15 {
394 puts("OK");394 puts(c"OK");
395 }395 }
396396
397 exit(0);397 exit(0);
...@@ -403,7 +403,7 @@ loop_2_end:...@@ -403,7 +403,7 @@ loop_2_end:
403use "std.zig";403use "std.zig";
404404
405export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {405export 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);
407 return 0;407 return 0;
408}408}
409 )SOURCE", "Hello, world!\n");409 )SOURCE", "Hello, world!\n");
...@@ -430,11 +430,11 @@ fn a() {}...@@ -430,11 +430,11 @@ fn a() {}
430430
431 add_compile_fail_case("unreachable with return", R"SOURCE(431 add_compile_fail_case("unreachable with return", R"SOURCE(
432fn a() -> unreachable {return;}432fn 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
435 add_compile_fail_case("control reaches end of non-void function", R"SOURCE(435 add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
436fn a() -> i32 {}436fn 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
439 add_compile_fail_case("undefined function call", R"SOURCE(439 add_compile_fail_case("undefined function call", R"SOURCE(
440fn a() {440fn a() {
...@@ -514,16 +514,16 @@ fn f(a : i32) {...@@ -514,16 +514,16 @@ fn f(a : i32) {
514514
515 add_compile_fail_case("variable has wrong type", R"SOURCE(515 add_compile_fail_case("variable has wrong type", R"SOURCE(
516fn f() -> i32 {516fn f() -> i32 {
517 let a = "a";517 let a = c"a";
518 a518 a
519}519}
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
522 add_compile_fail_case("if condition is bool, not int", R"SOURCE(522 add_compile_fail_case("if condition is bool, not int", R"SOURCE(
523fn f() {523fn f() {
524 if (0) {}524 if (0) {}
525}525}
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
528 add_compile_fail_case("assign unreachable", R"SOURCE(528 add_compile_fail_case("assign unreachable", R"SOURCE(
529fn f() {529fn f() {
...@@ -551,11 +551,11 @@ a_label:...@@ -551,11 +551,11 @@ a_label:
551}551}
552 )SOURCE", 1, ".tmp_source.zig:3:1: error: label 'a_label' defined but not used");552 )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(
555fn f() {555fn f() {
556 3 = 3;556 3 = 3;
557}557}
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
560 add_compile_fail_case("assign to constant variable", R"SOURCE(560 add_compile_fail_case("assign to constant variable", R"SOURCE(
561fn f() {561fn f() {