| author | |
| committer | |
| log | 3c43bc9208701af151a0346744e3bfc7eae43042 |
| tree | b3732004becc9b759ddad1a86813668059cfc8d9 |
| parent | 4ef062b9c819a2d7bfa9dd3394713ac9e8051660 |
8 files changed, 136 insertions(+), 82 deletions(-)
doc/langref.md+1-1| ... | ... | @@ -72,7 +72,7 @@ PointerType : token(Ampersand) option(token(Const)) Type |
| 72 | 72 | |
| 73 | 73 | MaybeType : token(Question) Type |
| 74 | 74 | |
| 75 | ArrayType : token(LBracket) option(Expression) token(RBracket) Type | |
| 75 | ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Type | |
| 76 | 76 | |
| 77 | 77 | Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) |
| 78 | 78 |
example/arrays/arrays.zig+11-2| ... | ... | @@ -19,9 +19,18 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 19 | 19 | i += 1; |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | if (accumulator == 15) { | |
| 23 | print_str("OK\n"); | |
| 22 | if (accumulator != 15) { | |
| 23 | print_str("BAD\n"); | |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | if (get_array_len(array) != 5) { | |
| 27 | print_str("BAD\n"); | |
| 28 | } | |
| 29 | ||
| 30 | print_str("OK\n"); | |
| 26 | 31 | return 0; |
| 27 | 32 | } |
| 33 | ||
| 34 | fn get_array_len(a: []u32) -> usize { | |
| 35 | a.len | |
| 36 | } |
example/rand/main.zig+10-6| ... | ... | @@ -7,8 +7,10 @@ const ARRAY_SIZE : u16 = 624; |
| 7 | 7 | |
| 8 | 8 | /// Use `rand_init` to initialize this state. |
| 9 | 9 | struct Rand { |
| 10 | array: [u32; ARRAY_SIZE], | |
| 11 | index: #typeof(ARRAY_SIZE), | |
| 10 | // TODO use ARRAY_SIZE here | |
| 11 | array: [624]u32, | |
| 12 | // TODO use ARRAY_SIZE here | |
| 13 | index: #typeof(624), | |
| 12 | 14 | |
| 13 | 15 | /// Get 32 bits of randomness. |
| 14 | 16 | pub fn get_u32(r: &Rand) -> u32 { |
| ... | ... | @@ -31,10 +33,11 @@ struct Rand { |
| 31 | 33 | pub fn get_bytes(r: &Rand, buf: []u8) { |
| 32 | 34 | var bytes_left = r.get_bytes_aligned(buf); |
| 33 | 35 | if (bytes_left > 0) { |
| 34 | var rand_val_array : [u8; #sizeof(u32)]; | |
| 36 | var rand_val_array : [#sizeof(u32)]u8; | |
| 35 | 37 | *(rand_val_array.ptr as &u32) = r.get_u32(); |
| 36 | 38 | while (bytes_left > 0) { |
| 37 | buf[buf.len - bytes_left] = rand_val_array[#sizeof(u32) - bytes_left]; | |
| 39 | // TODO array index operator so we can remove the .ptr | |
| 40 | buf.ptr[buf.len - bytes_left] = rand_val_array[#sizeof(u32) - bytes_left]; | |
| 38 | 41 | bytes_left -= 1; |
| 39 | 42 | } |
| 40 | 43 | } |
| ... | ... | @@ -46,7 +49,7 @@ struct Rand { |
| 46 | 49 | const range = end - start; |
| 47 | 50 | const leftover = #max_value(u64) % range; |
| 48 | 51 | const upper_bound = #max_value(u64) - leftover; |
| 49 | var rand_val_array : [u8; #sizeof(u64)]; | |
| 52 | var rand_val_array : [#sizeof(u64)]u8; | |
| 50 | 53 | |
| 51 | 54 | while (true) { |
| 52 | 55 | r.get_bytes_aligned(rand_val_array); |
| ... | ... | @@ -79,7 +82,8 @@ struct Rand { |
| 79 | 82 | fn get_bytes_aligned(r: &Rand, buf: []u8) -> usize { |
| 80 | 83 | var bytes_left = buf.len; |
| 81 | 84 | while (bytes_left > 4) { |
| 82 | *(&buf[buf.len - bytes_left] as &u32) = r.get_u32(); | |
| 85 | // TODO: array access so we can remove .ptr | |
| 86 | *(&buf.ptr[buf.len - bytes_left] as &u32) = r.get_u32(); | |
| 83 | 87 | bytes_left -= #sizeof(u32); |
| 84 | 88 | } |
| 85 | 89 | return bytes_left; |
src/analyze.cpp+88-28| ... | ... | @@ -219,7 +219,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import, |
| 219 | 219 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); |
| 220 | 220 | entry->type_ref = LLVMArrayType(child_type->type_ref, array_size); |
| 221 | 221 | buf_resize(&entry->name, 0); |
| 222 | buf_appendf(&entry->name, "[%s; %" PRIu64 "]", buf_ptr(&child_type->name), array_size); | |
| 222 | buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name)); | |
| 223 | 223 | |
| 224 | 224 | entry->size_in_bits = child_type->size_in_bits * array_size; |
| 225 | 225 | entry->align_in_bits = child_type->align_in_bits; |
| ... | ... | @@ -235,6 +235,55 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import, |
| 235 | 235 | } |
| 236 | 236 | } |
| 237 | 237 | |
| 238 | static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry *import, | |
| 239 | TypeTableEntry *child_type, bool is_const) | |
| 240 | { | |
| 241 | TypeTableEntry **parent_pointer = is_const ? | |
| 242 | &child_type->unknown_size_array_const_parent : | |
| 243 | &child_type->unknown_size_array_mut_parent; | |
| 244 | if (*parent_pointer) { | |
| 245 | return *parent_pointer; | |
| 246 | } else { | |
| 247 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); | |
| 248 | ||
| 249 | buf_resize(&entry->name, 0); | |
| 250 | buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); | |
| 251 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); | |
| 252 | ||
| 253 | TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); | |
| 254 | ||
| 255 | unsigned element_count = 2; | |
| 256 | LLVMTypeRef element_types[] = { | |
| 257 | pointer_type->type_ref, | |
| 258 | g->builtin_types.entry_usize->type_ref, | |
| 259 | }; | |
| 260 | LLVMStructSetBody(entry->type_ref, element_types, element_count, false); | |
| 261 | ||
| 262 | entry->size_in_bits = g->pointer_size_bytes * 2 * 8; | |
| 263 | entry->align_in_bits = g->pointer_size_bytes * 8; | |
| 264 | entry->data.structure.is_packed = false; | |
| 265 | entry->data.structure.is_unknown_size_array = true; | |
| 266 | entry->data.structure.field_count = element_count; | |
| 267 | entry->data.structure.fields = allocate<TypeStructField>(element_count); | |
| 268 | entry->data.structure.fields[0].name = buf_create_from_str("ptr"); | |
| 269 | entry->data.structure.fields[0].type_entry = pointer_type; | |
| 270 | entry->data.structure.fields[1].name = buf_create_from_str("len"); | |
| 271 | entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize; | |
| 272 | ||
| 273 | LLVMZigDIType *di_element_types[] = { | |
| 274 | pointer_type->di_type, | |
| 275 | g->builtin_types.entry_usize->di_type, | |
| 276 | }; | |
| 277 | LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit); | |
| 278 | entry->di_type = LLVMZigCreateDebugStructType(g->dbuilder, compile_unit_scope, | |
| 279 | buf_ptr(&entry->name), g->dummy_di_file, 0, entry->size_in_bits, entry->align_in_bits, 0, | |
| 280 | nullptr, di_element_types, element_count, 0, nullptr, ""); | |
| 281 | ||
| 282 | *parent_pointer = entry; | |
| 283 | return entry; | |
| 284 | } | |
| 285 | } | |
| 286 | ||
| 238 | 287 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 239 | 288 | AstNode *node, AstNodeNumberLiteral *out_number_literal) |
| 240 | 289 | { |
| ... | ... | @@ -313,38 +362,47 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry |
| 313 | 362 | } |
| 314 | 363 | case AstNodeTypeTypeArray: |
| 315 | 364 | { |
| 316 | resolve_type(g, node->data.type.child_type, import, context); | |
| 317 | TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; | |
| 365 | TypeTableEntry *child_type = resolve_type(g, node->data.type.child_type, import, context); | |
| 318 | 366 | if (child_type->id == TypeTableEntryIdUnreachable) { |
| 319 | 367 | add_node_error(g, node, |
| 320 | 368 | buf_create_from_str("array of unreachable not allowed")); |
| 321 | } | |
| 322 | ||
| 323 | AstNode *size_node = node->data.type.array_size; | |
| 324 | TypeTableEntry *size_type = analyze_expression(g, import, context, | |
| 325 | g->builtin_types.entry_usize, size_node); | |
| 326 | if (size_type->id == TypeTableEntryIdInvalid) { | |
| 327 | 369 | type_node->entry = g->builtin_types.entry_invalid; |
| 328 | 370 | return type_node->entry; |
| 329 | 371 | } |
| 330 | 372 | |
| 331 | AstNodeNumberLiteral number_literal; | |
| 332 | TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal); | |
| 373 | AstNode *size_node = node->data.type.array_size; | |
| 333 | 374 | |
| 334 | if (resolved_type->id == TypeTableEntryIdInt) { | |
| 335 | if (resolved_type->data.integral.is_signed) { | |
| 336 | add_node_error(g, size_node, | |
| 337 | buf_create_from_str("array size must be unsigned integer")); | |
| 375 | if (size_node) { | |
| 376 | TypeTableEntry *size_type = analyze_expression(g, import, context, | |
| 377 | g->builtin_types.entry_usize, size_node); | |
| 378 | if (size_type->id == TypeTableEntryIdInvalid) { | |
| 338 | 379 | type_node->entry = g->builtin_types.entry_invalid; |
| 380 | return type_node->entry; | |
| 381 | } | |
| 382 | ||
| 383 | AstNodeNumberLiteral number_literal; | |
| 384 | TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal); | |
| 385 | ||
| 386 | if (resolved_type->id == TypeTableEntryIdInt) { | |
| 387 | if (resolved_type->data.integral.is_signed) { | |
| 388 | add_node_error(g, size_node, | |
| 389 | buf_create_from_str("array size must be unsigned integer")); | |
| 390 | type_node->entry = g->builtin_types.entry_invalid; | |
| 391 | } else { | |
| 392 | type_node->entry = get_array_type(g, import, child_type, number_literal.data.x_uint); | |
| 393 | } | |
| 339 | 394 | } else { |
| 340 | type_node->entry = get_array_type(g, import, child_type, number_literal.data.x_uint); | |
| 395 | add_node_error(g, size_node, | |
| 396 | buf_create_from_str("unable to resolve constant expression")); | |
| 397 | type_node->entry = g->builtin_types.entry_invalid; | |
| 341 | 398 | } |
| 399 | return type_node->entry; | |
| 342 | 400 | } else { |
| 343 | add_node_error(g, size_node, | |
| 344 | buf_create_from_str("unable to resolve constant expression")); | |
| 345 | type_node->entry = g->builtin_types.entry_invalid; | |
| 401 | type_node->entry = get_unknown_size_array_type(g, import, child_type, | |
| 402 | node->data.type.is_const); | |
| 403 | return type_node->entry; | |
| 346 | 404 | } |
| 347 | return type_node->entry; | |
| 405 | ||
| 348 | 406 | } |
| 349 | 407 | case AstNodeTypeTypeMaybe: |
| 350 | 408 | { |
| ... | ... | @@ -1016,13 +1074,14 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont |
| 1016 | 1074 | return expected_type; |
| 1017 | 1075 | } |
| 1018 | 1076 | |
| 1019 | // implicit constant sized array to string conversion | |
| 1020 | if (expected_type == g->builtin_types.entry_string && | |
| 1077 | // implicit constant sized array to unknown size array conversion | |
| 1078 | if (expected_type->id == TypeTableEntryIdStruct && | |
| 1079 | expected_type->data.structure.is_unknown_size_array && | |
| 1021 | 1080 | actual_type->id == TypeTableEntryIdArray && |
| 1022 | actual_type->data.array.child_type == g->builtin_types.entry_u8) | |
| 1081 | actual_type->data.array.child_type == expected_type->data.structure.fields[0].type_entry->data.pointer.child_type) | |
| 1023 | 1082 | { |
| 1024 | 1083 | node->codegen_node->expr_node.implicit_cast.after_type = expected_type; |
| 1025 | node->codegen_node->expr_node.implicit_cast.op = CastOpArrayToString; | |
| 1084 | node->codegen_node->expr_node.implicit_cast.op = CastOpToUnknownSizeArray; | |
| 1026 | 1085 | node->codegen_node->expr_node.implicit_cast.source_node = node; |
| 1027 | 1086 | context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_cast); |
| 1028 | 1087 | return expected_type; |
| ... | ... | @@ -1292,11 +1351,12 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 1292 | 1351 | { |
| 1293 | 1352 | cast_node->op = CastOpIntWidenOrShorten; |
| 1294 | 1353 | return wanted_type; |
| 1295 | } else if (wanted_type == g->builtin_types.entry_string && | |
| 1296 | actual_type->id == TypeTableEntryIdArray && | |
| 1297 | actual_type->data.array.child_type == g->builtin_types.entry_u8) | |
| 1354 | } else if (wanted_type->id == TypeTableEntryIdStruct && | |
| 1355 | wanted_type->data.structure.is_unknown_size_array && | |
| 1356 | actual_type->id == TypeTableEntryIdArray && | |
| 1357 | actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry) | |
| 1298 | 1358 | { |
| 1299 | cast_node->op = CastOpArrayToString; | |
| 1359 | cast_node->op = CastOpToUnknownSizeArray; | |
| 1300 | 1360 | context->cast_expr_alloca_list.append(cast_node); |
| 1301 | 1361 | return wanted_type; |
| 1302 | 1362 | } else if (actual_type->id == TypeTableEntryIdNumberLiteral && |
src/analyze.hpp+4-2| ... | ... | @@ -46,6 +46,7 @@ struct TypeTableEntryStruct { |
| 46 | 46 | TypeStructField *fields; |
| 47 | 47 | uint64_t size_bytes; |
| 48 | 48 | bool is_invalid; // true if any fields are invalid |
| 49 | bool is_unknown_size_array; | |
| 49 | 50 | // reminder: hash tables must be initialized before use |
| 50 | 51 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; |
| 51 | 52 | |
| ... | ... | @@ -100,6 +101,8 @@ struct TypeTableEntry { |
| 100 | 101 | TypeTableEntry *pointer_mut_parent; |
| 101 | 102 | HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size; |
| 102 | 103 | TypeTableEntry *maybe_parent; |
| 104 | TypeTableEntry *unknown_size_array_const_parent; | |
| 105 | TypeTableEntry *unknown_size_array_mut_parent; | |
| 103 | 106 | |
| 104 | 107 | }; |
| 105 | 108 | |
| ... | ... | @@ -175,7 +178,6 @@ struct CodeGen { |
| 175 | 178 | TypeTableEntry *entry_f32; |
| 176 | 179 | TypeTableEntry *entry_f64; |
| 177 | 180 | TypeTableEntry *entry_c_string_literal; |
| 178 | TypeTableEntry *entry_string; | |
| 179 | 181 | TypeTableEntry *entry_void; |
| 180 | 182 | TypeTableEntry *entry_unreachable; |
| 181 | 183 | TypeTableEntry *entry_invalid; |
| ... | ... | @@ -283,7 +285,7 @@ enum CastOp { |
| 283 | 285 | CastOpNothing, |
| 284 | 286 | CastOpPtrToInt, |
| 285 | 287 | CastOpIntWidenOrShorten, |
| 286 | CastOpArrayToString, | |
| 288 | CastOpToUnknownSizeArray, | |
| 287 | 289 | CastOpMaybeWrap, |
| 288 | 290 | CastOpPointerReinterpret, |
| 289 | 291 | }; |
src/codegen.cpp+5-38| ... | ... | @@ -462,14 +462,17 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v |
| 462 | 462 | add_debug_source_node(g, node); |
| 463 | 463 | return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); |
| 464 | 464 | } |
| 465 | case CastOpArrayToString: | |
| 465 | case CastOpToUnknownSizeArray: | |
| 466 | 466 | { |
| 467 | 467 | assert(cast_node->ptr); |
| 468 | 468 | |
| 469 | TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry; | |
| 470 | ||
| 469 | 471 | add_debug_source_node(g, node); |
| 470 | 472 | |
| 471 | 473 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, ""); |
| 472 | LLVMBuildStore(g->builder, expr_val, ptr_ptr); | |
| 474 | LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, ""); | |
| 475 | LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr); | |
| 473 | 476 | |
| 474 | 477 | LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, ""); |
| 475 | 478 | LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, |
| ... | ... | @@ -1925,41 +1928,6 @@ static void define_builtin_types(CodeGen *g) { |
| 1925 | 1928 | entry->di_type = g->builtin_types.entry_void->di_type; |
| 1926 | 1929 | g->builtin_types.entry_unreachable = entry; |
| 1927 | 1930 | } |
| 1928 | { | |
| 1929 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); | |
| 1930 | ||
| 1931 | TypeTableEntry *const_pointer_to_u8 = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | |
| 1932 | ||
| 1933 | unsigned element_count = 2; | |
| 1934 | LLVMTypeRef element_types[] = { | |
| 1935 | const_pointer_to_u8->type_ref, | |
| 1936 | g->builtin_types.entry_usize->type_ref | |
| 1937 | }; | |
| 1938 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), "string"); | |
| 1939 | LLVMStructSetBody(entry->type_ref, element_types, element_count, false); | |
| 1940 | ||
| 1941 | buf_init_from_str(&entry->name, "string"); | |
| 1942 | entry->size_in_bits = g->pointer_size_bytes * 2 * 8; | |
| 1943 | entry->align_in_bits = g->pointer_size_bytes; | |
| 1944 | entry->data.structure.is_packed = false; | |
| 1945 | entry->data.structure.field_count = element_count; | |
| 1946 | entry->data.structure.fields = allocate<TypeStructField>(element_count); | |
| 1947 | entry->data.structure.fields[0].name = buf_create_from_str("ptr"); | |
| 1948 | entry->data.structure.fields[0].type_entry = const_pointer_to_u8; | |
| 1949 | entry->data.structure.fields[1].name = buf_create_from_str("len"); | |
| 1950 | entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize; | |
| 1951 | ||
| 1952 | LLVMZigDIType *di_element_types[] = { | |
| 1953 | const_pointer_to_u8->di_type, | |
| 1954 | g->builtin_types.entry_usize->di_type | |
| 1955 | }; | |
| 1956 | LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit); | |
| 1957 | entry->di_type = LLVMZigCreateDebugStructType(g->dbuilder, compile_unit_scope, | |
| 1958 | "string", g->dummy_di_file, 0, entry->size_in_bits, entry->align_in_bits, 0, | |
| 1959 | nullptr, di_element_types, element_count, 0, nullptr, ""); | |
| 1960 | ||
| 1961 | g->builtin_types.entry_string = entry; | |
| 1962 | } | |
| 1963 | 1931 | } |
| 1964 | 1932 | |
| 1965 | 1933 | |
| ... | ... | @@ -2103,7 +2071,6 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, |
| 2103 | 2071 | import_entry->type_table.put(&g->builtin_types.entry_f64->name, g->builtin_types.entry_f64); |
| 2104 | 2072 | import_entry->type_table.put(&g->builtin_types.entry_void->name, g->builtin_types.entry_void); |
| 2105 | 2073 | import_entry->type_table.put(&g->builtin_types.entry_unreachable->name, g->builtin_types.entry_unreachable); |
| 2106 | import_entry->type_table.put(&g->builtin_types.entry_string->name, g->builtin_types.entry_string); | |
| 2107 | 2074 | |
| 2108 | 2075 | import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color); |
| 2109 | 2076 | assert(import_entry->root); |
src/parser.cpp+11-3| ... | ... | @@ -219,7 +219,7 @@ void ast_print(AstNode *node, int indent) { |
| 219 | 219 | } |
| 220 | 220 | case AstNodeTypeTypePointer: |
| 221 | 221 | { |
| 222 | const char *const_or_mut_str = node->data.type.is_const ? "const" : "mut"; | |
| 222 | const char *const_or_mut_str = node->data.type.is_const ? "const" : "var"; | |
| 223 | 223 | fprintf(stderr, "'%s' PointerType\n", const_or_mut_str); |
| 224 | 224 | |
| 225 | 225 | ast_print(node->data.type.child_type, indent + 2); |
| ... | ... | @@ -227,9 +227,11 @@ void ast_print(AstNode *node, int indent) { |
| 227 | 227 | } |
| 228 | 228 | case AstNodeTypeTypeArray: |
| 229 | 229 | { |
| 230 | fprintf(stderr, "ArrayType\n"); | |
| 230 | const char *const_or_mut_str = node->data.type.is_const ? "const" : "var"; | |
| 231 | fprintf(stderr, "'%s' ArrayType\n", const_or_mut_str); | |
| 232 | if (node->data.type.array_size) | |
| 233 | ast_print(node->data.type.array_size, indent + 2); | |
| 231 | 234 | ast_print(node->data.type.child_type, indent + 2); |
| 232 | ast_print(node->data.type.array_size, indent + 2); | |
| 233 | 235 | break; |
| 234 | 236 | } |
| 235 | 237 | case AstNodeTypeTypeMaybe: |
| ... | ... | @@ -1107,6 +1109,12 @@ static AstNode *ast_parse_type(ParseContext *pc, int *token_index) { |
| 1107 | 1109 | |
| 1108 | 1110 | ast_eat_token(pc, token_index, TokenIdRBracket); |
| 1109 | 1111 | |
| 1112 | Token *const_tok = &pc->tokens->at(*token_index); | |
| 1113 | if (const_tok->id == TokenIdKeywordConst) { | |
| 1114 | *token_index += 1; | |
| 1115 | node->data.type.is_const = true; | |
| 1116 | } | |
| 1117 | ||
| 1110 | 1118 | node->data.type.child_type = ast_parse_type(pc, token_index); |
| 1111 | 1119 | } else { |
| 1112 | 1120 | ast_invalid_token_error(pc, token); |
std/std.zig+6-2| ... | ... | @@ -39,13 +39,13 @@ pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize { |
| 39 | 39 | |
| 40 | 40 | // TODO error handling |
| 41 | 41 | // TODO handle buffering and flushing (mutex protected) |
| 42 | pub fn print_str(str: string) -> isize { | |
| 42 | pub fn print_str(str: []const u8) -> isize { | |
| 43 | 43 | fprint_str(stdout_fileno, str) |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | 46 | // TODO error handling |
| 47 | 47 | // TODO handle buffering and flushing (mutex protected) |
| 48 | pub fn fprint_str(fd: isize, str: string) -> isize { | |
| 48 | pub fn fprint_str(fd: isize, str: []const u8) -> isize { | |
| 49 | 49 | write(fd, str.ptr, str.len) |
| 50 | 50 | } |
| 51 | 51 | |
| ... | ... | @@ -73,6 +73,9 @@ fn digit_to_char(digit: u64) -> u8 { |
| 73 | 73 | |
| 74 | 74 | const max_u64_base10_digits: usize = 20; |
| 75 | 75 | |
| 76 | // TODO use an array for out_buf instead of pointer. this should give bounds checking in | |
| 77 | // debug mode and length can get optimized out in release mode. requires array slicing syntax | |
| 78 | // for the buf_print_u64 call. | |
| 76 | 79 | fn buf_print_i64(out_buf: &u8, x: i64) -> usize { |
| 77 | 80 | if (x < 0) { |
| 78 | 81 | out_buf[0] = '-'; |
| ... | ... | @@ -82,6 +85,7 @@ fn buf_print_i64(out_buf: &u8, x: i64) -> usize { |
| 82 | 85 | } |
| 83 | 86 | } |
| 84 | 87 | |
| 88 | // TODO use an array for out_buf instead of pointer. | |
| 85 | 89 | fn buf_print_u64(out_buf: &u8, x: u64) -> usize { |
| 86 | 90 | var buf: [max_u64_base10_digits]u8; |
| 87 | 91 | var a = x; |