authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-14 02:46:37-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-14 02:46:37-07:00
loge411467e1dd4557bb11698f2a5d979dfcbaea444
tree8b9bf14a1dee5310a8e18099fc354e1b9b1d2152
parent3d8eb10897a86b2616c6a1aa843b7ebe4134ac51

add number literal type

it gets implicitly casted to whatever is needed. closes #24

17 files changed, 892 insertions(+), 235 deletions(-)

doc/langref.md+8-7
......@@ -200,10 +200,11 @@ as
200200
201201### Numbers
202202
203 Number literals | Example | Exponentiation
204-------------------------------------------
205 Decimal integer | 98222 | N/A
206 Hex integer | 0xff | N/A
207 Octal integer | 0o77 | N/A
208 Binary integer | 0b11110000 | N/A
209 Floating-point | 123.0E+77 | Optional
203 Number literals | Example | Exponentiation
204--------------------------------------------------
205 Decimal integer | 98222 | N/A
206 Hex integer | 0xff | N/A
207 Octal integer | 0o77 | N/A
208 Binary integer | 0b11110000 | N/A
209 Floating-point | 123.0E+77 | Optional
210 Hex floating point | TODO | TODO
example/arrays/arrays.zig+8-11
......@@ -1,15 +1,11 @@
11export executable "arrays";
22
3#link("c")
4extern {
5 fn puts(s: *const u8) -> i32;
6 fn exit(code: i32) -> unreachable;
7}
3use "std.zig";
84
9export fn _start() -> unreachable {
5export fn main(argc: isize, argv: *mut *mut u8, env: *mut *mut u8) -> i32 {
106 let mut array : [i32; 5];
117
12 let mut i = 0;
8 let mut i : i32 = 0;
139loop_start:
1410 if i == 5 {
1511 goto loop_end;
......@@ -21,21 +17,22 @@ loop_start:
2117loop_end:
2218
2319 i = 0;
24 let mut accumulator = 0;
20 let mut accumulator : i32 = 0;
2521loop_2_start:
2622 if i == 5 {
2723 goto loop_2_end;
2824 }
2925
30 accumulator = accumulator + array[i];
26 accumulator += array[i];
3127
3228 i = i + 1;
3329 goto loop_2_start;
3430loop_2_end:
3531
3632 if accumulator == 15 {
37 puts("OK");
33 print_str("OK" as string);
3834 }
3935
40 exit(0);
36
37 return 0;
4138}
example/expressions/expressions.zig+7-7
......@@ -14,19 +14,19 @@ fn other_exit() -> unreachable {
1414
1515export fn _start() -> unreachable {
1616 let a : i32 = 1;
17 let b = 2;
17 let b = 2 as i32;
1818 // let c : i32; // not yet support for const variables
1919 // let d; // parse error
2020 if (a + b == 3) {
21 let no_conflict = 5;
22 if (no_conflict == 5) { puts("OK 1"); }
21 let no_conflict : i32 = 5;
22 if (no_conflict == 5) { puts(c"OK 1"); }
2323 }
2424
2525 let c = {
26 let no_conflict = 10;
26 let no_conflict : i32 = 10;
2727 no_conflict
2828 };
29 if (c == 10) { puts("OK 2"); }
29 if (c == 10) { puts(c"OK 2"); }
3030
3131 void_fun(1, void, 2);
3232
......@@ -44,12 +44,12 @@ fn void_fun(a : i32, b : void, c : i32) -> void {
4444}
4545
4646fn test_mutable_vars() {
47 let mut i = 0;
47 let mut i : i32 = 0;
4848loop_start:
4949 if i == 3 {
5050 goto done;
5151 }
52 puts("loop");
52 puts(c"loop");
5353 i = i + 1;
5454 goto loop_start;
5555done:
example/hello_world/hello_libc.zig+1-1
......@@ -7,6 +7,6 @@ extern {
77}
88
99export fn _start() -> unreachable {
10 printf("Hello, world!\n");
10 printf(c"Hello, world!\n");
1111 exit(0);
1212}
example/multiple_files/foo.zig+1-1
......@@ -3,7 +3,7 @@ use "libc.zig";
33// purposefully conflicting function with main.zig
44// but it's private so it should be OK
55fn private_function() {
6 puts("it works!");
6 puts(c"it works!");
77}
88
99pub fn print_text() {
example/multiple_files/libc.zig+1-1
......@@ -1,5 +1,5 @@
11#link("c")
22extern {
3 pub fn puts(s: *mut u8) -> i32;
3 pub fn puts(s: *const u8) -> i32;
44 pub fn exit(code: i32) -> unreachable;
55}
example/structs/structs.zig+1-1
......@@ -22,6 +22,6 @@ struct Foo {
2222
2323fn test_foo(foo : Foo) {
2424 if foo.b {
25 print_str("OK" as string);
25 print_str("OK\n" as string);
2626 }
2727}
src/analyze.cpp+370-177
......@@ -122,7 +122,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
122122 }
123123}
124124
125static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, int array_size) {
125static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size) {
126126 auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);
127127 if (existing_entry) {
128128 return existing_entry->value;
......@@ -130,7 +130,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in
130130 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
131131 entry->type_ref = LLVMArrayType(child_type->type_ref, array_size);
132132 buf_resize(&entry->name, 0);
133 buf_appendf(&entry->name, "[%s; %d]", buf_ptr(&child_type->name), array_size);
133 buf_appendf(&entry->name, "[%s; %" PRIu64 "]", buf_ptr(&child_type->name), array_size);
134134
135135 entry->size_in_bits = child_type->size_in_bits * array_size;
136136 entry->align_in_bits = child_type->align_in_bits;
......@@ -145,11 +145,6 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in
145145 }
146146}
147147
148static int parse_int(Buf *number) {
149 // TODO: think about integer size of array sizes
150 return atoi(buf_ptr(number));
151}
152
153148static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
154149 assert(node->type == NodeTypeType);
155150 alloc_codegen_node(node);
......@@ -192,16 +187,15 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
192187 }
193188
194189 AstNode *size_node = node->data.type.array_size;
195 int size; // TODO: think about integer size of array sizes
196 if (size_node->type != NodeTypeNumberLiteral) {
197 add_node_error(g, size_node,
198 buf_create_from_str("array size must be literal number"));
199 size = -1;
190 if (size_node->type == NodeTypeNumberLiteral &&
191 is_num_lit_unsigned(size_node->data.number_literal.kind))
192 {
193 type_node->entry = get_array_type(g, child_type, size_node->data.number_literal.data.x_uint);
200194 } else {
201 size = parse_int(&size_node->data.number);
195 add_node_error(g, size_node,
196 buf_create_from_str("array size must be literal unsigned integer"));
197 type_node->entry = g->builtin_types.entry_invalid;
202198 }
203
204 type_node->entry = get_array_type(g, child_type, size);
205199 return type_node->entry;
206200 }
207201 }
......@@ -625,6 +619,44 @@ static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructF
625619 *out_i = -1;
626620}
627621
622static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) {
623 NumLit num_lit = literal_type->data.num_lit.kind;
624 uint64_t lit_size_in_bits = num_lit_bit_count(num_lit);
625
626 switch (other_type->id) {
627 case TypeTableEntryIdInvalid:
628 case TypeTableEntryIdNumberLiteral:
629 zig_unreachable();
630 case TypeTableEntryIdVoid:
631 case TypeTableEntryIdBool:
632 case TypeTableEntryIdUnreachable:
633 case TypeTableEntryIdPointer:
634 case TypeTableEntryIdArray:
635 case TypeTableEntryIdStruct:
636 return false;
637 case TypeTableEntryIdInt:
638 if (is_num_lit_signed(num_lit)) {
639 if (!other_type->data.integral.is_signed) {
640 return false;
641 }
642
643 return lit_size_in_bits <= other_type->size_in_bits;
644 } else if (is_num_lit_unsigned(num_lit)) {
645
646 return lit_size_in_bits <= other_type->size_in_bits;
647 } else {
648 return false;
649 }
650 case TypeTableEntryIdFloat:
651 if (is_num_lit_float(num_lit)) {
652 return lit_size_in_bits <= other_type->size_in_bits;
653 } else {
654 return false;
655 }
656 }
657}
658
659
628660static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
629661 AstNode *node)
630662{
......@@ -790,6 +822,16 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
790822 cast_node->op = CastOpArrayToString;
791823 context->cast_expr_alloca_list.append(node);
792824 return wanted_type;
825 } else if (actual_type->id == TypeTableEntryIdNumberLiteral &&
826 num_lit_fits_in_other_type(g, actual_type, wanted_type))
827 {
828 AstNode *literal_node = node->data.cast_expr.expr;
829 assert(literal_node->codegen_node);
830 NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node;
831 assert(!codegen_num_lit->resolved_type);
832 codegen_num_lit->resolved_type = wanted_type;
833 cast_node->op = CastOpNothing;
834 return wanted_type;
793835 } else {
794836 add_node_error(g, node,
795837 buf_sprintf("invalid cast from type '%s' to '%s'",
......@@ -799,6 +841,314 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
799841 }
800842}
801843
844static TypeTableEntry * resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node,
845 TypeTableEntry *non_literal_type, AstNode *literal_node, TypeTableEntry *literal_type)
846{
847 assert(literal_node->codegen_node);
848 NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node;
849
850 if (num_lit_fits_in_other_type(g, literal_type, non_literal_type)) {
851 assert(!codegen_num_lit->resolved_type);
852 codegen_num_lit->resolved_type = non_literal_type;
853 return non_literal_type;
854 } else {
855 return nullptr;
856 }
857}
858
859static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstNode *node2) {
860 TypeTableEntry *type1 = node1->codegen_node->expr_node.type_entry;
861 TypeTableEntry *type2 = node2->codegen_node->expr_node.type_entry;
862
863 if (type1->id == TypeTableEntryIdNumberLiteral &&
864 type2->id == TypeTableEntryIdNumberLiteral)
865 {
866 assert(node1->codegen_node);
867 assert(node2->codegen_node);
868
869 NumberLiteralNode *codegen_num_lit_1 = &node1->codegen_node->data.num_lit_node;
870 NumberLiteralNode *codegen_num_lit_2 = &node2->codegen_node->data.num_lit_node;
871
872 assert(!codegen_num_lit_1->resolved_type);
873 assert(!codegen_num_lit_2->resolved_type);
874
875 if (is_num_lit_float(type1->data.num_lit.kind) &&
876 is_num_lit_float(type2->data.num_lit.kind))
877 {
878 codegen_num_lit_1->resolved_type = g->builtin_types.entry_f64;
879 codegen_num_lit_2->resolved_type = g->builtin_types.entry_f64;
880 return g->builtin_types.entry_f64;
881 } else if (is_num_lit_signed(type1->data.num_lit.kind) &&
882 is_num_lit_signed(type2->data.num_lit.kind))
883 {
884 codegen_num_lit_1->resolved_type = g->builtin_types.entry_i64;
885 codegen_num_lit_2->resolved_type = g->builtin_types.entry_i64;
886 return g->builtin_types.entry_i64;
887 } else if (is_num_lit_unsigned(type1->data.num_lit.kind) &&
888 is_num_lit_unsigned(type2->data.num_lit.kind))
889 {
890 codegen_num_lit_1->resolved_type = g->builtin_types.entry_u64;
891 codegen_num_lit_2->resolved_type = g->builtin_types.entry_u64;
892 return g->builtin_types.entry_u64;
893 } else {
894 return nullptr;
895 }
896 } else if (type1->id == TypeTableEntryIdNumberLiteral) {
897 return resolve_rhs_number_literal(g, node2, type2, node1, type1);
898 } else {
899 assert(type2->id == TypeTableEntryIdNumberLiteral);
900 return resolve_rhs_number_literal(g, node1, type1, node2, type2);
901 }
902}
903
904static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
905 TypeTableEntry *expected_type, AstNode *node)
906{
907 switch (node->data.bin_op_expr.bin_op) {
908 case BinOpTypeAssign:
909 case BinOpTypeAssignTimes:
910 case BinOpTypeAssignDiv:
911 case BinOpTypeAssignMod:
912 case BinOpTypeAssignPlus:
913 case BinOpTypeAssignMinus:
914 case BinOpTypeAssignBitShiftLeft:
915 case BinOpTypeAssignBitShiftRight:
916 case BinOpTypeAssignBitAnd:
917 case BinOpTypeAssignBitXor:
918 case BinOpTypeAssignBitOr:
919 case BinOpTypeAssignBoolAnd:
920 case BinOpTypeAssignBoolOr:
921 {
922 AstNode *lhs_node = node->data.bin_op_expr.op1;
923 TypeTableEntry *expected_rhs_type = nullptr;
924 if (lhs_node->type == NodeTypeSymbol) {
925 Buf *name = &lhs_node->data.symbol;
926 LocalVariableTableEntry *var = find_local_variable(context, name);
927 if (var) {
928 if (var->is_const) {
929 add_node_error(g, lhs_node,
930 buf_sprintf("cannot assign to constant variable"));
931 } else {
932 if (!is_op_allowed(var->type, node->data.bin_op_expr.bin_op)) {
933 if (var->type->id != TypeTableEntryIdInvalid) {
934 add_node_error(g, lhs_node,
935 buf_sprintf("operator not allowed for type '%s'",
936 buf_ptr(&var->type->name)));
937 }
938 } else {
939 expected_rhs_type = var->type;
940 }
941 }
942 } else {
943 add_node_error(g, lhs_node,
944 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
945 }
946 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
947 expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);
948 } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
949 alloc_codegen_node(lhs_node);
950 expected_rhs_type = analyze_field_access_expr(g, import, context, lhs_node);
951 } else {
952 add_node_error(g, lhs_node,
953 buf_sprintf("assignment target must be variable, field, or array element"));
954 }
955 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
956 return g->builtin_types.entry_void;
957 }
958 case BinOpTypeBoolOr:
959 case BinOpTypeBoolAnd:
960 analyze_expression(g, import, context, g->builtin_types.entry_bool,
961 node->data.bin_op_expr.op1);
962 analyze_expression(g, import, context, g->builtin_types.entry_bool,
963 node->data.bin_op_expr.op2);
964 return g->builtin_types.entry_bool;
965 case BinOpTypeCmpEq:
966 case BinOpTypeCmpNotEq:
967 case BinOpTypeCmpLessThan:
968 case BinOpTypeCmpGreaterThan:
969 case BinOpTypeCmpLessOrEq:
970 case BinOpTypeCmpGreaterOrEq:
971 {
972 AstNode *op1 = node->data.bin_op_expr.op1;
973 AstNode *op2 = node->data.bin_op_expr.op2;
974 TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);
975 TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2);
976 bool cmp_ok = false;
977 if (lhs_type->id == TypeTableEntryIdInvalid || rhs_type->id == TypeTableEntryIdInvalid) {
978 cmp_ok = true;
979 } else if (lhs_type->id == TypeTableEntryIdNumberLiteral ||
980 rhs_type->id == TypeTableEntryIdNumberLiteral)
981 {
982 cmp_ok = resolve_number_literals(g, op1, op2);
983 } else if (lhs_type->id == TypeTableEntryIdInt) {
984 if (rhs_type->id == TypeTableEntryIdInt &&
985 lhs_type->data.integral.is_signed == rhs_type->data.integral.is_signed &&
986 lhs_type->size_in_bits == rhs_type->size_in_bits)
987 {
988 cmp_ok = true;
989 }
990 } else if (lhs_type->id == TypeTableEntryIdFloat) {
991 if (rhs_type->id == TypeTableEntryIdFloat &&
992 lhs_type->size_in_bits == rhs_type->size_in_bits)
993 {
994 cmp_ok = true;
995 }
996 }
997 if (!cmp_ok) {
998 add_node_error(g, node, buf_sprintf("unable to compare '%s' with '%s'",
999 buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name)));
1000 }
1001 return g->builtin_types.entry_bool;
1002 }
1003 case BinOpTypeBinOr:
1004 case BinOpTypeBinXor:
1005 case BinOpTypeBinAnd:
1006 {
1007 // TODO: don't require i32
1008 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op1);
1009 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op2);
1010 return g->builtin_types.entry_i32;
1011 }
1012 case BinOpTypeBitShiftLeft:
1013 case BinOpTypeBitShiftRight:
1014 {
1015 // TODO: don't require i32
1016 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op1);
1017 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op2);
1018 return g->builtin_types.entry_i32;
1019 }
1020 case BinOpTypeAdd:
1021 case BinOpTypeSub:
1022 {
1023 AstNode *op1 = node->data.bin_op_expr.op1;
1024 AstNode *op2 = node->data.bin_op_expr.op2;
1025 TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);
1026 TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2);
1027
1028 TypeTableEntry *return_type = nullptr;
1029
1030 if (lhs_type->id == TypeTableEntryIdInvalid || rhs_type->id == TypeTableEntryIdInvalid) {
1031 return_type = g->builtin_types.entry_invalid;
1032 } else if (lhs_type->id == TypeTableEntryIdNumberLiteral ||
1033 rhs_type->id == TypeTableEntryIdNumberLiteral)
1034 {
1035 return_type = resolve_number_literals(g, op1, op2);
1036 } else if (lhs_type->id == TypeTableEntryIdInt &&
1037 lhs_type == rhs_type)
1038 {
1039 return_type = lhs_type;
1040 } else if (lhs_type->id == TypeTableEntryIdFloat &&
1041 lhs_type == rhs_type)
1042 {
1043 return_type = lhs_type;
1044 }
1045 if (!return_type) {
1046 if (node->data.bin_op_expr.bin_op == BinOpTypeAdd) {
1047 add_node_error(g, node, buf_sprintf("unable to add '%s' and '%s'",
1048 buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name)));
1049 } else {
1050 add_node_error(g, node, buf_sprintf("unable to subtract '%s' and '%s'",
1051 buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name)));
1052 }
1053 return g->builtin_types.entry_invalid;
1054 }
1055 return return_type;
1056 }
1057 case BinOpTypeMult:
1058 case BinOpTypeDiv:
1059 case BinOpTypeMod:
1060 {
1061 // TODO: don't require i32
1062 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op1);
1063 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op2);
1064 return g->builtin_types.entry_i32;
1065 }
1066 case BinOpTypeInvalid:
1067 zig_unreachable();
1068 }
1069 zig_unreachable();
1070}
1071
1072static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1073 TypeTableEntry *expected_type, AstNode *node)
1074{
1075 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
1076
1077 TypeTableEntry *explicit_type = nullptr;
1078 if (variable_declaration->type != nullptr) {
1079 explicit_type = resolve_type(g, variable_declaration->type);
1080 if (explicit_type->id == TypeTableEntryIdUnreachable) {
1081 add_node_error(g, variable_declaration->type,
1082 buf_sprintf("variable of type 'unreachable' not allowed"));
1083 explicit_type = g->builtin_types.entry_invalid;
1084 }
1085 }
1086
1087 TypeTableEntry *implicit_type = nullptr;
1088 if (variable_declaration->expr != nullptr) {
1089 implicit_type = analyze_expression(g, import, context, explicit_type, variable_declaration->expr);
1090 if (implicit_type->id == TypeTableEntryIdUnreachable) {
1091 add_node_error(g, node,
1092 buf_sprintf("variable initialization is unreachable"));
1093 implicit_type = g->builtin_types.entry_invalid;
1094 } else if (implicit_type->id == TypeTableEntryIdNumberLiteral) {
1095 add_node_error(g, node,
1096 buf_sprintf("unable to infer variable type"));
1097 implicit_type = g->builtin_types.entry_invalid;
1098 }
1099 }
1100
1101 if (implicit_type == nullptr && variable_declaration->is_const) {
1102 add_node_error(g, node, buf_sprintf("variables must have initial values or be declared 'mut'."));
1103 implicit_type = g->builtin_types.entry_invalid;
1104 }
1105
1106 TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
1107 assert(type != nullptr); // should have been caught by the parser
1108
1109 LocalVariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);
1110 if (existing_variable) {
1111 add_node_error(g, node,
1112 buf_sprintf("redeclaration of variable '%s'", buf_ptr(&variable_declaration->symbol)));
1113 } else {
1114 LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1);
1115 buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol);
1116 variable_entry->type = type;
1117 variable_entry->is_const = variable_declaration->is_const;
1118 variable_entry->is_ptr = true;
1119 variable_entry->decl_node = node;
1120 context->variable_table.put(&variable_entry->name, variable_entry);
1121 }
1122 return g->builtin_types.entry_void;
1123}
1124
1125static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1126 TypeTableEntry *expected_type, AstNode *node)
1127{
1128 TypeTableEntry *num_lit_type = g->num_lit_types[node->data.number_literal.kind];
1129 if (node->data.number_literal.overflow) {
1130 add_node_error(g, node,
1131 buf_sprintf("number literal too large to be represented in any type"));
1132 return g->builtin_types.entry_invalid;
1133 } else if (expected_type) {
1134 if (expected_type->id == TypeTableEntryIdInvalid) {
1135 return g->builtin_types.entry_invalid;
1136 } else if (num_lit_fits_in_other_type(g, num_lit_type, expected_type)) {
1137 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
1138 assert(!codegen_num_lit->resolved_type);
1139 codegen_num_lit->resolved_type = expected_type;
1140
1141 return expected_type;
1142 } else {
1143 add_node_error(g, node, buf_sprintf("expected type '%s', got '%s'",
1144 buf_ptr(&expected_type->name), buf_ptr(&num_lit_type->name)));
1145 return g->builtin_types.entry_invalid;
1146 }
1147 } else {
1148 return num_lit_type;
1149 }
1150}
1151
8021152static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
8031153 TypeTableEntry *expected_type, AstNode *node)
8041154{
......@@ -854,51 +1204,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
8541204 break;
8551205 }
8561206 case NodeTypeVariableDeclaration:
857 {
858 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;;
859
860 TypeTableEntry *explicit_type = nullptr;
861 if (variable_declaration->type != nullptr) {
862 explicit_type = resolve_type(g, variable_declaration->type);
863 if (explicit_type->id == TypeTableEntryIdUnreachable) {
864 add_node_error(g, variable_declaration->type,
865 buf_sprintf("variable of type 'unreachable' not allowed"));
866 }
867 }
868
869 TypeTableEntry *implicit_type = nullptr;
870 if (variable_declaration->expr != nullptr) {
871 implicit_type = analyze_expression(g, import, context, explicit_type, variable_declaration->expr);
872 if (implicit_type->id == TypeTableEntryIdUnreachable) {
873 add_node_error(g, node,
874 buf_sprintf("variable initialization is unreachable"));
875 }
876 }
877
878 if (implicit_type == nullptr && variable_declaration->is_const) {
879 add_node_error(g, node, buf_sprintf("variables must have initial values or be declared 'mut'."));
880 }
881
882 TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
883 assert(type != nullptr); // should have been caught by the parser
884
885 LocalVariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);
886 if (existing_variable) {
887 add_node_error(g, node,
888 buf_sprintf("redeclaration of variable '%s'", buf_ptr(&variable_declaration->symbol)));
889 } else {
890 LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1);
891 buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol);
892 variable_entry->type = type;
893 variable_entry->is_const = variable_declaration->is_const;
894 variable_entry->is_ptr = true;
895 variable_entry->decl_node = node;
896 context->variable_table.put(&variable_entry->name, variable_entry);
897 }
898 return_type = g->builtin_types.entry_void;
899 break;
900 }
901
1207 return_type = analyze_variable_declaration(g, import, context, expected_type, node);
1208 break;
9021209 case NodeTypeGoto:
9031210 {
9041211 FnTableEntry *fn_table_entry = get_context_fn_entry(context);
......@@ -928,120 +1235,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
9281235 break;
9291236 }
9301237 case NodeTypeBinOpExpr:
931 {
932 switch (node->data.bin_op_expr.bin_op) {
933 case BinOpTypeAssign:
934 case BinOpTypeAssignTimes:
935 case BinOpTypeAssignDiv:
936 case BinOpTypeAssignMod:
937 case BinOpTypeAssignPlus:
938 case BinOpTypeAssignMinus:
939 case BinOpTypeAssignBitShiftLeft:
940 case BinOpTypeAssignBitShiftRight:
941 case BinOpTypeAssignBitAnd:
942 case BinOpTypeAssignBitXor:
943 case BinOpTypeAssignBitOr:
944 case BinOpTypeAssignBoolAnd:
945 case BinOpTypeAssignBoolOr:
946 {
947 AstNode *lhs_node = node->data.bin_op_expr.op1;
948 TypeTableEntry *expected_rhs_type = nullptr;
949 if (lhs_node->type == NodeTypeSymbol) {
950 Buf *name = &lhs_node->data.symbol;
951 LocalVariableTableEntry *var = find_local_variable(context, name);
952 if (var) {
953 if (var->is_const) {
954 add_node_error(g, lhs_node,
955 buf_sprintf("cannot assign to constant variable"));
956 } else {
957 if (!is_op_allowed(var->type, node->data.bin_op_expr.bin_op)) {
958 add_node_error(g, lhs_node,
959 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&var->type->name)));
960 } else {
961 expected_rhs_type = var->type;
962 }
963 }
964 } else {
965 add_node_error(g, lhs_node,
966 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
967 }
968 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
969 expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);
970 } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
971 alloc_codegen_node(lhs_node);
972 expected_rhs_type = analyze_field_access_expr(g, import, context, lhs_node);
973 } else {
974 add_node_error(g, lhs_node,
975 buf_sprintf("assignment target must be variable, field, or array element"));
976 }
977 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
978 return_type = g->builtin_types.entry_void;
979 break;
980 }
981 case BinOpTypeBoolOr:
982 case BinOpTypeBoolAnd:
983 analyze_expression(g, import, context, g->builtin_types.entry_bool,
984 node->data.bin_op_expr.op1);
985 analyze_expression(g, import, context, g->builtin_types.entry_bool,
986 node->data.bin_op_expr.op2);
987 return_type = g->builtin_types.entry_bool;
988 break;
989 case BinOpTypeCmpEq:
990 case BinOpTypeCmpNotEq:
991 case BinOpTypeCmpLessThan:
992 case BinOpTypeCmpGreaterThan:
993 case BinOpTypeCmpLessOrEq:
994 case BinOpTypeCmpGreaterOrEq:
995 // TODO think how should type checking for these work?
996 analyze_expression(g, import, context, g->builtin_types.entry_i32,
997 node->data.bin_op_expr.op1);
998 analyze_expression(g, import, context, g->builtin_types.entry_i32,
999 node->data.bin_op_expr.op2);
1000 return_type = g->builtin_types.entry_bool;
1001 break;
1002 case BinOpTypeBinOr:
1003 case BinOpTypeBinXor:
1004 case BinOpTypeBinAnd:
1005 {
1006 // TODO: don't require i32
1007 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op1);
1008 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op2);
1009 return_type = g->builtin_types.entry_i32;
1010 break;
1011 }
1012 case BinOpTypeBitShiftLeft:
1013 case BinOpTypeBitShiftRight:
1014 {
1015 // TODO: don't require i32
1016 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op1);
1017 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op2);
1018 return_type = g->builtin_types.entry_i32;
1019 break;
1020 }
1021 case BinOpTypeAdd:
1022 case BinOpTypeSub:
1023 // TODO think how should type checking for these work?
1024 analyze_expression(g, import, context, g->builtin_types.entry_i32,
1025 node->data.bin_op_expr.op1);
1026 analyze_expression(g, import, context, g->builtin_types.entry_i32,
1027 node->data.bin_op_expr.op2);
1028 return_type = g->builtin_types.entry_i32;
1029 break;
1030 case BinOpTypeMult:
1031 case BinOpTypeDiv:
1032 case BinOpTypeMod:
1033 {
1034 // TODO: don't require i32
1035 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op1);
1036 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op2);
1037 return_type = g->builtin_types.entry_i32;
1038 break;
1039 }
1040 case BinOpTypeInvalid:
1041 zig_unreachable();
1042 }
1043 break;
1044 }
1238 return_type = analyze_bin_op_expr(g, import, context, expected_type, node);
1239 break;
10451240
10461241 case NodeTypeFnCallExpr:
10471242 {
......@@ -1116,10 +1311,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
11161311 return_type = analyze_field_access_expr(g, import, context, node);
11171312 break;
11181313 case NodeTypeNumberLiteral:
1119 // TODO: generic literal int type
1120 return_type = g->builtin_types.entry_i32;
1314 return_type = analyze_number_literal_expr(g, import, context, expected_type, node);
11211315 break;
1122
11231316 case NodeTypeStringLiteral:
11241317 if (node->data.string_literal.c) {
11251318 return_type = g->builtin_types.entry_c_string_literal;
src/analyze.hpp+18-1
......@@ -42,6 +42,10 @@ struct TypeTableEntryStruct {
4242 TypeStructField *fields;
4343};
4444
45struct TypeTableEntryNumLit {
46 NumLit kind;
47};
48
4549enum TypeTableEntryId {
4650 TypeTableEntryIdInvalid,
4751 TypeTableEntryIdVoid,
......@@ -52,6 +56,7 @@ enum TypeTableEntryId {
5256 TypeTableEntryIdPointer,
5357 TypeTableEntryIdArray,
5458 TypeTableEntryIdStruct,
59 TypeTableEntryIdNumberLiteral,
5560};
5661
5762struct TypeTableEntry {
......@@ -69,12 +74,13 @@ struct TypeTableEntry {
6974 TypeTableEntryInt integral;
7075 TypeTableEntryArray array;
7176 TypeTableEntryStruct structure;
77 TypeTableEntryNumLit num_lit;
7278 } data;
7379
7480 // use these fields to make sure we don't duplicate type table entries for the same type
7581 TypeTableEntry *pointer_const_parent;
7682 TypeTableEntry *pointer_mut_parent;
77 HashMap<int, TypeTableEntry *, int_hash, int_eq> arrays_by_size;
83 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
7884
7985};
8086
......@@ -134,10 +140,13 @@ struct CodeGen {
134140 struct {
135141 TypeTableEntry *entry_bool;
136142 TypeTableEntry *entry_u8;
143 TypeTableEntry *entry_u64;
137144 TypeTableEntry *entry_i32;
145 TypeTableEntry *entry_i64;
138146 TypeTableEntry *entry_isize;
139147 TypeTableEntry *entry_usize;
140148 TypeTableEntry *entry_f32;
149 TypeTableEntry *entry_f64;
141150 TypeTableEntry *entry_c_string_literal;
142151 TypeTableEntry *entry_string;
143152 TypeTableEntry *entry_void;
......@@ -145,6 +154,8 @@ struct CodeGen {
145154 TypeTableEntry *entry_invalid;
146155 } builtin_types;
147156
157 TypeTableEntry *num_lit_types[NumLitCount];
158
148159 LLVMTargetDataRef target_data_ref;
149160 unsigned pointer_size_bytes;
150161 bool is_static;
......@@ -242,6 +253,7 @@ enum CastOp {
242253 CastOpPtrToInt,
243254 CastOpIntWidenOrShorten,
244255 CastOpArrayToString,
256 CastOpNothing,
245257};
246258
247259struct CastNode {
......@@ -251,6 +263,10 @@ struct CastNode {
251263 LLVMValueRef ptr;
252264};
253265
266struct NumberLiteralNode {
267 TypeTableEntry *resolved_type;
268};
269
254270struct CodeGenNode {
255271 union {
256272 TypeNode type_node; // for NodeTypeType
......@@ -262,6 +278,7 @@ struct CodeGenNode {
262278 StructDeclNode struct_decl_node; // for NodeTypeStructDecl
263279 FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr
264280 CastNode cast_node; // for NodeTypeCastExpr
281 NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral
265282 } data;
266283 ExprNode expr_node; // for all the expression nodes
267284};
src/codegen.cpp+90-5
......@@ -279,6 +279,8 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
279279 CastNode *cast_node = &node->codegen_node->data.cast_node;
280280
281281 switch (cast_node->op) {
282 case CastOpNothing:
283 return expr_val;
282284 case CastOpPtrToInt:
283285 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
284286 case CastOpIntWidenOrShorten:
......@@ -901,11 +903,29 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
901903 return gen_asm_expr(g, node);
902904 case NodeTypeNumberLiteral:
903905 {
904 Buf *number_str = &node->data.number;
905 LLVMTypeRef number_type = LLVMInt32Type();
906 LLVMValueRef number_val = LLVMConstIntOfStringAndSize(number_type,
907 buf_ptr(number_str), buf_len(number_str), 10);
908 return number_val;
906 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
907 assert(codegen_num_lit);
908 TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
909 assert(type_entry);
910
911 // TODO this is kinda iffy. make sure josh is on board with this
912 node->codegen_node->expr_node.type_entry = type_entry;
913
914 if (type_entry->id == TypeTableEntryIdInt) {
915 // here the union has int64_t and uint64_t and we purposefully read
916 // the uint64_t value in either case, because we want the twos
917 // complement representation
918
919 return LLVMConstInt(type_entry->type_ref,
920 node->data.number_literal.data.x_uint,
921 type_entry->data.integral.is_signed);
922 } else if (type_entry->id == TypeTableEntryIdFloat) {
923
924 return LLVMConstReal(type_entry->type_ref,
925 node->data.number_literal.data.x_float);
926 } else {
927 zig_panic("bad number literal type");
928 }
909929 }
910930 case NodeTypeStringLiteral:
911931 {
......@@ -1186,6 +1206,20 @@ static void do_code_gen(CodeGen *g) {
11861206#endif
11871207}
11881208
1209static const NumLit num_lit_kinds[] = {
1210 NumLitF32,
1211 NumLitF64,
1212 NumLitF128,
1213 NumLitI8,
1214 NumLitU8,
1215 NumLitI16,
1216 NumLitU16,
1217 NumLitI32,
1218 NumLitU32,
1219 NumLitI64,
1220 NumLitU64,
1221};
1222
11891223static void define_builtin_types(CodeGen *g) {
11901224 {
11911225 // if this type is anywhere in the AST, we should never hit codegen.
......@@ -1193,6 +1227,19 @@ static void define_builtin_types(CodeGen *g) {
11931227 buf_init_from_str(&entry->name, "(invalid)");
11941228 g->builtin_types.entry_invalid = entry;
11951229 }
1230
1231 assert(NumLitCount == array_length(num_lit_kinds));
1232 for (int i = 0; i < NumLitCount; i += 1) {
1233 NumLit num_lit_kind = num_lit_kinds[i];
1234 // This type should just create a constant with whatever actual number
1235 // type is expected at the time.
1236 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumberLiteral);
1237 buf_resize(&entry->name, 0);
1238 buf_appendf(&entry->name, "(%s literal)", num_lit_str(num_lit_kind));
1239 entry->data.num_lit.kind = num_lit_kind;
1240 g->num_lit_types[i] = entry;
1241 }
1242
11961243 {
11971244 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
11981245 entry->type_ref = LLVMInt1Type();
......@@ -1217,6 +1264,19 @@ static void define_builtin_types(CodeGen *g) {
12171264 g->type_table.put(&entry->name, entry);
12181265 g->builtin_types.entry_u8 = entry;
12191266 }
1267 {
1268 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1269 entry->type_ref = LLVMInt64Type();
1270 buf_init_from_str(&entry->name, "u64");
1271 entry->size_in_bits = 64;
1272 entry->align_in_bits = 64;
1273 entry->data.integral.is_signed = false;
1274 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1275 entry->size_in_bits, entry->align_in_bits,
1276 LLVMZigEncoding_DW_ATE_unsigned());
1277 g->type_table.put(&entry->name, entry);
1278 g->builtin_types.entry_u64 = entry;
1279 }
12201280 g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
12211281 {
12221282 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
......@@ -1231,6 +1291,19 @@ static void define_builtin_types(CodeGen *g) {
12311291 g->type_table.put(&entry->name, entry);
12321292 g->builtin_types.entry_i32 = entry;
12331293 }
1294 {
1295 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1296 entry->type_ref = LLVMInt64Type();
1297 buf_init_from_str(&entry->name, "i64");
1298 entry->size_in_bits = 64;
1299 entry->align_in_bits = 64;
1300 entry->data.integral.is_signed = true;
1301 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1302 entry->size_in_bits, entry->align_in_bits,
1303 LLVMZigEncoding_DW_ATE_signed());
1304 g->type_table.put(&entry->name, entry);
1305 g->builtin_types.entry_i64 = entry;
1306 }
12341307 {
12351308 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
12361309 entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
......@@ -1269,6 +1342,18 @@ static void define_builtin_types(CodeGen *g) {
12691342 g->type_table.put(&entry->name, entry);
12701343 g->builtin_types.entry_f32 = entry;
12711344 }
1345 {
1346 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
1347 entry->type_ref = LLVMFloatType();
1348 buf_init_from_str(&entry->name, "f64");
1349 entry->size_in_bits = 64;
1350 entry->align_in_bits = 64;
1351 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1352 entry->size_in_bits, entry->align_in_bits,
1353 LLVMZigEncoding_DW_ATE_float());
1354 g->type_table.put(&entry->name, entry);
1355 g->builtin_types.entry_f64 = entry;
1356 }
12721357 {
12731358 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
12741359 entry->type_ref = LLVMVoidType();
src/parseh.cpp+1-1
......@@ -544,7 +544,7 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI
544544
545545 char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS");
546546 if (ZIG_PARSEH_CFLAGS) {
547 Buf tmp_buf = {0};
547 Buf tmp_buf = BUF_INIT;
548548 char *start = ZIG_PARSEH_CFLAGS;
549549 char *space = strstr(start, " ");
550550 while (space) {
src/parser.cpp+313-4
......@@ -12,6 +12,7 @@
1212#include <stdarg.h>
1313#include <stdio.h>
1414
15
1516static const char *bin_op_str(BinOpType bin_op) {
1617 switch (bin_op) {
1718 case BinOpTypeInvalid: return "(invalid)";
......@@ -273,9 +274,19 @@ void ast_print(AstNode *node, int indent) {
273274 ast_print(node->data.prefix_op_expr.primary_expr, indent + 2);
274275 break;
275276 case NodeTypeNumberLiteral:
276 fprintf(stderr, "NumberLiteral %s\n",
277 buf_ptr(&node->data.number));
278 break;
277 {
278 NumLit num_lit = node->data.number_literal.kind;
279 const char *name = node_type_str(node->type);
280 const char *kind_str = num_lit_str(num_lit);
281 if (is_num_lit_signed(num_lit)) {
282 fprintf(stderr, "%s %s %" PRId64 "\n", name, kind_str, node->data.number_literal.data.x_int);
283 } else if (is_num_lit_unsigned(num_lit)) {
284 fprintf(stderr, "%s %s %" PRIu64 "\n", name, kind_str, node->data.number_literal.data.x_uint);
285 } else {
286 fprintf(stderr, "%s %s %f\n", name, kind_str, node->data.number_literal.data.x_float);
287 }
288 break;
289 }
279290 case NodeTypeStringLiteral:
280291 {
281292 const char *c = node->data.string_literal.c ? "c" : "";
......@@ -574,6 +585,186 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool
574585 if (offset_map) offset_map->append(pos);
575586}
576587
588enum ParseNumLitState {
589 ParseNumLitStateStart,
590 ParseNumLitStateBase,
591 ParseNumLitStateDigits,
592 ParseNumLitStateExpectFirstDigit,
593 ParseNumLitStateDecimal,
594 ParseNumLitStateESign,
595 ParseNumLitStateEDigit,
596};
597
598static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLiteral *num_lit) {
599 ParseNumLitState state = ParseNumLitStateStart;
600 unsigned long long base = 10;
601 bool negative = false;
602 int digits_start;
603 int digits_end;
604 int decimal_start = -1;
605 int decimal_end;
606 bool e_present = false;
607 bool e_positive;
608 int e_digit_start;
609 int e_digit_end;
610
611 for (int i = token->start_pos; i < token->end_pos; i += 1) {
612 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
613 switch (state) {
614 case ParseNumLitStateStart:
615 if (c == '-') {
616 negative = true;
617 } else if (c == '0') {
618 state = ParseNumLitStateBase;
619 } else if (c >= '1' && c <= '9') {
620 digits_start = i;
621 state = ParseNumLitStateDigits;
622 } else {
623 zig_unreachable();
624 }
625 break;
626 case ParseNumLitStateBase:
627 if (c == 'x') {
628 base = 16;
629 state = ParseNumLitStateExpectFirstDigit;
630 } else if (c == 'o') {
631 base = 8;
632 state = ParseNumLitStateExpectFirstDigit;
633 } else if (c == 'b') {
634 base = 2;
635 state = ParseNumLitStateExpectFirstDigit;
636 } else {
637 zig_unreachable();
638 }
639 break;
640
641 case ParseNumLitStateExpectFirstDigit:
642 state = ParseNumLitStateDigits;
643 break;
644
645 case ParseNumLitStateDigits:
646 if (c == '.') {
647 assert(base == 10);
648 digits_end = i;
649 decimal_start = i + 1;
650 state = ParseNumLitStateDecimal;
651 }
652 break;
653 case ParseNumLitStateDecimal:
654 if (c == 'E') {
655 e_present = false;
656 decimal_end = i;
657 state = ParseNumLitStateESign;
658 }
659 break;
660 case ParseNumLitStateESign:
661 if (c == '+') {
662 e_positive = true;
663 e_digit_start = i + 1;
664 state = ParseNumLitStateEDigit;
665 } else if (c == '-') {
666 e_positive = false;
667 e_digit_start = i + 1;
668 state = ParseNumLitStateEDigit;
669 } else {
670 zig_unreachable();
671 }
672 break;
673 case ParseNumLitStateEDigit:
674 assert(c >= '0' && c <= '9');
675 break;
676 }
677 }
678
679 switch (state) {
680 case ParseNumLitStateDigits:
681 digits_end = token->end_pos;
682 break;
683 case ParseNumLitStateDecimal:
684 decimal_end = token->end_pos;
685 break;
686 case ParseNumLitStateEDigit:
687 e_digit_end = token->end_pos;
688 break;
689 case ParseNumLitStateBase:
690 num_lit->kind = NumLitU8;
691 num_lit->data.x_uint = 0;
692 return;
693 case ParseNumLitStateESign:
694 case ParseNumLitStateExpectFirstDigit:
695 case ParseNumLitStateStart:
696 zig_unreachable();
697 }
698
699 if (decimal_start >= 0) {
700 // float
701 double x;
702
703 (void)x;
704 zig_panic("TODO parse float");
705 } else {
706 // integer
707 unsigned long long x = 0;
708
709 unsigned long long mult = 1;
710 for (int i = digits_end - 1; ; i -= 1) {
711 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
712 unsigned long long digit = (c - '0');
713
714 // digit *= mult
715 if (__builtin_umulll_overflow(digit, mult, &digit)) {
716 num_lit->overflow = true;
717 return;
718 }
719
720 // x += digit
721 if (__builtin_uaddll_overflow(x, digit, &x)) {
722 num_lit->overflow = true;
723 return;
724 }
725
726 if (i == digits_start)
727 break;
728
729 // mult *= base
730 if (__builtin_umulll_overflow(mult, base, &mult)) {
731 num_lit->overflow = true;
732 return;
733 }
734 }
735
736 if (negative) {
737 if (x <= 128ull) {
738 num_lit->kind = NumLitI8;
739 } else if (x <= 32768ull) {
740 num_lit->kind = NumLitI16;
741 } else if (x <= 2147483648ull) {
742 num_lit->kind = NumLitI32;
743 } else if (x <= 9223372036854775808ull) {
744 num_lit->kind = NumLitI64;
745 } else {
746 num_lit->overflow = true;
747 return;
748 }
749
750 num_lit->data.x_int = -((int64_t)x);
751 } else {
752 num_lit->data.x_uint = x;
753
754 if (x <= UINT8_MAX) {
755 num_lit->kind = NumLitU8;
756 } else if (x <= UINT16_MAX) {
757 num_lit->kind = NumLitU16;
758 } else if (x <= UINT32_MAX) {
759 num_lit->kind = NumLitU32;
760 } else {
761 num_lit->kind = NumLitU64;
762 }
763 }
764 }
765}
766
767
577768__attribute__ ((noreturn))
578769static void ast_invalid_token_error(ParseContext *pc, Token *token) {
579770 Buf token_value = BUF_INIT;
......@@ -829,7 +1020,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
8291020
8301021 if (token->id == TokenIdNumberLiteral) {
8311022 AstNode *node = ast_create_node(pc, NodeTypeNumberLiteral, token);
832 ast_buf_from_token(pc, token, &node->data.number);
1023 parse_number_literal(pc, token, &node->data.number_literal);
8331024 *token_index += 1;
8341025 return node;
8351026 } else if (token->id == TokenIdStringLiteral) {
......@@ -2152,3 +2343,121 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, Er
21522343 pc.root = ast_parse_root(&pc, &token_index);
21532344 return pc.root;
21542345}
2346
2347const char *num_lit_str(NumLit num_lit) {
2348 switch (num_lit) {
2349 case NumLitF32:
2350 return "f32";
2351 case NumLitF64:
2352 return "f64";
2353 case NumLitF128:
2354 return "f128";
2355 case NumLitI8:
2356 return "i8";
2357 case NumLitI16:
2358 return "i16";
2359 case NumLitI32:
2360 return "i32";
2361 case NumLitI64:
2362 return "i64";
2363 case NumLitU8:
2364 return "u8";
2365 case NumLitU16:
2366 return "u16";
2367 case NumLitU32:
2368 return "u32";
2369 case NumLitU64:
2370 return "u64";
2371 case NumLitCount:
2372 zig_unreachable();
2373 }
2374 zig_unreachable();
2375}
2376
2377bool is_num_lit_signed(NumLit num_lit) {
2378 switch (num_lit) {
2379 case NumLitI8:
2380 case NumLitI16:
2381 case NumLitI32:
2382 case NumLitI64:
2383 return true;
2384
2385 case NumLitF32:
2386 case NumLitF64:
2387 case NumLitF128:
2388 case NumLitU8:
2389 case NumLitU16:
2390 case NumLitU32:
2391 case NumLitU64:
2392 return false;
2393 case NumLitCount:
2394 zig_unreachable();
2395 }
2396 zig_unreachable();
2397}
2398
2399bool is_num_lit_unsigned(NumLit num_lit) {
2400 switch (num_lit) {
2401 case NumLitF32:
2402 case NumLitF64:
2403 case NumLitF128:
2404 case NumLitI8:
2405 case NumLitI16:
2406 case NumLitI32:
2407 case NumLitI64:
2408 return false;
2409 case NumLitU8:
2410 case NumLitU16:
2411 case NumLitU32:
2412 case NumLitU64:
2413 return true;
2414 case NumLitCount:
2415 zig_unreachable();
2416 }
2417 zig_unreachable();
2418}
2419
2420bool is_num_lit_float(NumLit num_lit) {
2421 switch (num_lit) {
2422 case NumLitF32:
2423 case NumLitF64:
2424 case NumLitF128:
2425 return true;
2426 case NumLitI8:
2427 case NumLitI16:
2428 case NumLitI32:
2429 case NumLitI64:
2430 case NumLitU8:
2431 case NumLitU16:
2432 case NumLitU32:
2433 case NumLitU64:
2434 return false;
2435 case NumLitCount:
2436 zig_unreachable();
2437 }
2438 zig_unreachable();
2439}
2440
2441uint64_t num_lit_bit_count(NumLit num_lit) {
2442 switch (num_lit) {
2443 case NumLitI8:
2444 case NumLitU8:
2445 return 8;
2446 case NumLitI16:
2447 case NumLitU16:
2448 return 16;
2449 case NumLitI32:
2450 case NumLitU32:
2451 case NumLitF32:
2452 return 32;
2453 case NumLitI64:
2454 case NumLitU64:
2455 case NumLitF64:
2456 return 64;
2457 case NumLitF128:
2458 return 128;
2459 case NumLitCount:
2460 zig_unreachable();
2461 }
2462 zig_unreachable();
2463}
src/parser.hpp+38-1
......@@ -267,6 +267,36 @@ struct AstNodeStringLiteral {
267267 bool c;
268268};
269269
270enum NumLit {
271 NumLitF32,
272 NumLitF64,
273 NumLitF128,
274 NumLitI8,
275 NumLitU8,
276 NumLitI16,
277 NumLitU16,
278 NumLitI32,
279 NumLitU32,
280 NumLitI64,
281 NumLitU64,
282
283 NumLitCount
284};
285
286struct AstNodeNumberLiteral {
287 NumLit kind;
288
289 // overflow is true if when parsing the number, we discovered it would not
290 // fit without losing data in a uint64_t, int64_t, or double
291 bool overflow;
292
293 union {
294 uint64_t x_uint;
295 int64_t x_int;
296 double x_float;
297 } data;
298};
299
270300struct AstNode {
271301 enum NodeType type;
272302 int line;
......@@ -300,7 +330,7 @@ struct AstNode {
300330 AstNodeStructDecl struct_decl;
301331 AstNodeStructField struct_field;
302332 AstNodeStringLiteral string_literal;
303 Buf number;
333 AstNodeNumberLiteral number_literal;
304334 Buf symbol;
305335 bool bool_literal;
306336 } data;
......@@ -329,4 +359,11 @@ const char *node_type_str(NodeType node_type);
329359
330360void ast_print(AstNode *node, int indent);
331361
362const char *num_lit_str(NumLit num_lit);
363bool is_num_lit_signed(NumLit num_lit);
364bool is_num_lit_unsigned(NumLit num_lit);
365bool is_num_lit_float(NumLit num_lit);
366uint64_t num_lit_bit_count(NumLit num_lit);
367
368
332369#endif
src/util.cpp+9-1
......@@ -21,8 +21,16 @@ void zig_panic(const char *format, ...) {
2121}
2222
2323uint32_t int_hash(int i) {
24 return *reinterpret_cast<uint32_t*>(&i);
24 return (uint32_t)(i % UINT32_MAX);
2525}
2626bool int_eq(int a, int b) {
2727 return a == b;
2828}
29
30uint32_t uint64_hash(uint64_t i) {
31 return (uint32_t)(i % UINT32_MAX);
32}
33
34bool uint64_eq(uint64_t a, uint64_t b) {
35 return a == b;
36}
src/util.hpp+2
......@@ -81,5 +81,7 @@ static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str)
8181
8282uint32_t int_hash(int i);
8383bool int_eq(int a, int b);
84uint32_t uint64_hash(uint64_t i);
85bool uint64_eq(uint64_t a, uint64_t b);
8486
8587#endif
std/std.zig+3-4
......@@ -15,10 +15,9 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
1515
1616// TODO error handling
1717// TODO handle buffering and flushing
18// TODO non-i32 integer literals so we can remove the casts
1918// TODO constants for SYS_write and stdout_fileno
2019pub fn print_str(str : string) -> isize {
21 let SYS_write = 1;
22 let stdout_fileno = 1;
23 return syscall3(SYS_write as isize, stdout_fileno as isize, str.ptr as isize, str.len as isize);
20 let SYS_write : isize = 1;
21 let stdout_fileno : isize = 1;
22 return syscall3(SYS_write, stdout_fileno, str.ptr as isize, str.len as isize);
2423}
test/run_tests.cpp+21-12
......@@ -266,7 +266,7 @@ extern {
266266
267267export fn _start() -> unreachable {
268268 let a : i32 = 1;
269 let b = 2;
269 let b = 2 as i32;
270270 if (a + b == 3) {
271271 puts(c"OK");
272272 }
......@@ -299,12 +299,12 @@ extern {
299299
300300export fn _start() -> unreachable {
301301 if (true) {
302 let no_conflict = 5;
302 let no_conflict : i32 = 5;
303303 if (no_conflict == 5) { puts(c"OK 1"); }
304304 }
305305
306306 let c = {
307 let no_conflict = 10;
307 let no_conflict = 10 as i32;
308308 no_conflict
309309 };
310310 if (c == 10) { puts(c"OK 2"); }
......@@ -343,7 +343,7 @@ export fn _start() -> unreachable {
343343 let mut zero : i32;
344344 if (zero == 0) { puts(c"zero"); }
345345
346 let mut i = 0;
346 let mut i = 0 as i32;
347347loop_start:
348348 if i == 3 {
349349 goto done;
......@@ -366,7 +366,7 @@ extern {
366366export fn _start() -> unreachable {
367367 let mut array : [i32; 5];
368368
369 let mut i = 0;
369 let mut i : i32 = 0;
370370loop_start:
371371 if i == 5 {
372372 goto loop_end;
......@@ -378,7 +378,7 @@ loop_start:
378378loop_end:
379379
380380 i = 0;
381 let mut accumulator = 0;
381 let mut accumulator = 0 as i32;
382382loop_2_start:
383383 if i == 5 {
384384 goto loop_2_end;
......@@ -611,7 +611,7 @@ fn f() -> i32 {
611611fn f() {
612612 if (0) {}
613613}
614 )SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got 'i32'");
614 )SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got '(u8 literal)'");
615615
616616 add_compile_fail_case("assign unreachable", R"SOURCE(
617617fn f() {
......@@ -685,13 +685,12 @@ fn f(...) {}
685685
686686}
687687
688static void print_compiler_invocation(TestCase *test_case, Buf *zig_stderr) {
688static void print_compiler_invocation(TestCase *test_case) {
689689 printf("%s", zig_exe);
690690 for (int i = 0; i < test_case->compiler_args.length; i += 1) {
691691 printf(" %s", test_case->compiler_args.at(i));
692692 }
693693 printf("\n");
694 printf("%s\n", buf_ptr(zig_stderr));
695694}
696695
697696static void run_test(TestCase *test_case) {
......@@ -716,21 +715,24 @@ static void run_test(TestCase *test_case) {
716715 printf("========= Expected this compile error: =========\n");
717716 printf("%s\n", err_text);
718717 printf("================================================\n");
719 print_compiler_invocation(test_case, &zig_stderr);
718 print_compiler_invocation(test_case);
719 printf("%s\n", buf_ptr(&zig_stderr));
720720 exit(1);
721721 }
722722 }
723723 return; // success
724724 } else {
725725 printf("\nCompile failed with return code 0 (Expected failure):\n");
726 print_compiler_invocation(test_case, &zig_stderr);
726 print_compiler_invocation(test_case);
727 printf("%s\n", buf_ptr(&zig_stderr));
727728 exit(1);
728729 }
729730 }
730731
731732 if (return_code != 0) {
732733 printf("\nCompile failed with return code %d:\n", return_code);
733 print_compiler_invocation(test_case, &zig_stderr);
734 print_compiler_invocation(test_case);
735 printf("%s\n", buf_ptr(&zig_stderr));
734736 exit(1);
735737 }
736738
......@@ -740,6 +742,7 @@ static void run_test(TestCase *test_case) {
740742
741743 if (return_code != 0) {
742744 printf("\nProgram exited with return code %d:\n", return_code);
745 print_compiler_invocation(test_case);
743746 printf("%s", tmp_exe_path);
744747 for (int i = 0; i < test_case->program_args.length; i += 1) {
745748 printf(" %s", test_case->program_args.at(i));
......@@ -750,6 +753,12 @@ static void run_test(TestCase *test_case) {
750753 }
751754
752755 if (!buf_eql_str(&program_stdout, test_case->output)) {
756 printf("\n");
757 print_compiler_invocation(test_case);
758 printf("%s", tmp_exe_path);
759 for (int i = 0; i < test_case->program_args.length; i += 1) {
760 printf(" %s", test_case->program_args.at(i));
761 }
753762 printf("\n");
754763 printf("==== Test failed. Expected output: ====\n");
755764 printf("%s\n", test_case->output);