| author | |
| committer | |
| log | 968b85ad77892da945d478799d4e775222248f1f |
| tree | d7ad6b71f1f80e27d5443c9faee41e480705757b |
| parent | 724dcdd384c6c00b9e39ed67867d364287e45f0a |
11 files changed, 359 insertions(+), 20 deletions(-)
doc/langref.md+2-2| ... | @@ -34,7 +34,7 @@ Root : many(TopLevelDecl) token(EOF) | ... | @@ -34,7 +34,7 @@ Root : many(TopLevelDecl) token(EOF) |
| 34 | 34 | ||
| 35 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration | 35 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration |
| 36 | 36 | ||
| 37 | VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | 37 | VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) |
| 38 | 38 | ||
| 39 | StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace) | 39 | StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace) |
| 40 | 40 | ||
| ... | @@ -150,7 +150,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket) | ... | @@ -150,7 +150,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 150 | 150 | ||
| 151 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const))) | 151 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const))) |
| 152 | 152 | ||
| 153 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | 153 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression |
| 154 | 154 | ||
| 155 | StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) | 155 | StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) |
| 156 | 156 |
example/guess_number/main.zig+19-4| ... | @@ -2,19 +2,33 @@ export executable "guess_number"; | ... | @@ -2,19 +2,33 @@ export executable "guess_number"; |
| 2 | 2 | ||
| 3 | use "std.zig"; | 3 | use "std.zig"; |
| 4 | 4 | ||
| 5 | fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 5 | // TODO don't duplicate these; implement pub const |
| 6 | const stdout_fileno : isize = 1; | ||
| 7 | const stderr_fileno : isize = 2; | ||
| 8 | |||
| 9 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ||
| 6 | print_str("Welcome to the Guess Number Game in Zig.\n"); | 10 | print_str("Welcome to the Guess Number Game in Zig.\n"); |
| 7 | 11 | ||
| 8 | var seed : u32; | 12 | var seed : u32; |
| 9 | ok_or_panic(os_get_random_bytes(&seed, 4)); | 13 | if (os_get_random_bytes(&seed as &u8, 4) != 0) { |
| 14 | // TODO full error message | ||
| 15 | fprint_str(stderr_fileno, "unable to get random bytes"); | ||
| 16 | return 1; | ||
| 17 | } | ||
| 18 | |||
| 19 | print_str("Seed: "); | ||
| 20 | print_u64(seed); | ||
| 21 | print_str("\n"); | ||
| 22 | |||
| 23 | /* | ||
| 10 | var rand_state = rand_init(seed); | 24 | var rand_state = rand_init(seed); |
| 11 | 25 | ||
| 12 | const answer = rand_int(&rand_state, 0, 100) + 1; | 26 | const answer = rand_int(&rand_state, 0, 100) + 1; |
| 13 | 27 | ||
| 14 | while true { | 28 | while (true) { |
| 15 | const line = readline("\nGuess a number between 1 and 100: "); | 29 | const line = readline("\nGuess a number between 1 and 100: "); |
| 16 | 30 | ||
| 17 | if const guess ?= parse_number(line) { | 31 | if (const guess ?= parse_number(line)) { |
| 18 | if (guess > answer) { | 32 | if (guess > answer) { |
| 19 | print_str("Guess lower.\n"); | 33 | print_str("Guess lower.\n"); |
| 20 | } else if (guess < answer) { | 34 | } else if (guess < answer) { |
| ... | @@ -27,6 +41,7 @@ fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -27,6 +41,7 @@ fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 27 | print_str("Invalid number format.\n"); | 41 | print_str("Invalid number format.\n"); |
| 28 | } | 42 | } |
| 29 | } | 43 | } |
| 44 | */ | ||
| 30 | 45 | ||
| 31 | return 0; | 46 | return 0; |
| 32 | } | 47 | } |
src/analyze.cpp+29-9| ... | @@ -38,6 +38,7 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -38,6 +38,7 @@ static AstNode *first_executing_node(AstNode *node) { |
| 38 | case NodeTypeCastExpr: | 38 | case NodeTypeCastExpr: |
| 39 | case NodeTypeNumberLiteral: | 39 | case NodeTypeNumberLiteral: |
| 40 | case NodeTypeStringLiteral: | 40 | case NodeTypeStringLiteral: |
| 41 | case NodeTypeCharLiteral: | ||
| 41 | case NodeTypeUnreachable: | 42 | case NodeTypeUnreachable: |
| 42 | case NodeTypeSymbol: | 43 | case NodeTypeSymbol: |
| 43 | case NodeTypePrefixOpExpr: | 44 | case NodeTypePrefixOpExpr: |
| ... | @@ -588,6 +589,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -588,6 +589,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 588 | case NodeTypeArrayAccessExpr: | 589 | case NodeTypeArrayAccessExpr: |
| 589 | case NodeTypeNumberLiteral: | 590 | case NodeTypeNumberLiteral: |
| 590 | case NodeTypeStringLiteral: | 591 | case NodeTypeStringLiteral: |
| 592 | case NodeTypeCharLiteral: | ||
| 591 | case NodeTypeUnreachable: | 593 | case NodeTypeUnreachable: |
| 592 | case NodeTypeVoid: | 594 | case NodeTypeVoid: |
| 593 | case NodeTypeBoolLiteral: | 595 | case NodeTypeBoolLiteral: |
| ... | @@ -659,6 +661,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { | ... | @@ -659,6 +661,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 659 | case NodeTypeArrayAccessExpr: | 661 | case NodeTypeArrayAccessExpr: |
| 660 | case NodeTypeNumberLiteral: | 662 | case NodeTypeNumberLiteral: |
| 661 | case NodeTypeStringLiteral: | 663 | case NodeTypeStringLiteral: |
| 664 | case NodeTypeCharLiteral: | ||
| 662 | case NodeTypeUnreachable: | 665 | case NodeTypeUnreachable: |
| 663 | case NodeTypeVoid: | 666 | case NodeTypeVoid: |
| 664 | case NodeTypeBoolLiteral: | 667 | case NodeTypeBoolLiteral: |
| ... | @@ -891,6 +894,17 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont | ... | @@ -891,6 +894,17 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont |
| 891 | return expected_type; | 894 | return expected_type; |
| 892 | } | 895 | } |
| 893 | 896 | ||
| 897 | // implicit non-const to const | ||
| 898 | if (expected_type->id == TypeTableEntryIdPointer && | ||
| 899 | actual_type->id == TypeTableEntryIdPointer && | ||
| 900 | expected_type->data.pointer.is_const && | ||
| 901 | !actual_type->data.pointer.is_const) | ||
| 902 | { | ||
| 903 | return resolve_type_compatibility(g, context, node, | ||
| 904 | expected_type->data.pointer.child_type, | ||
| 905 | actual_type->data.pointer.child_type); | ||
| 906 | } | ||
| 907 | |||
| 894 | add_node_error(g, node, | 908 | add_node_error(g, node, |
| 895 | buf_sprintf("expected type '%s', got '%s'", | 909 | buf_sprintf("expected type '%s', got '%s'", |
| 896 | buf_ptr(&expected_type->name), | 910 | buf_ptr(&expected_type->name), |
| ... | @@ -1013,6 +1027,9 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -1013,6 +1027,9 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1013 | Buf *name = &node->data.field_access_expr.field_name; | 1027 | Buf *name = &node->data.field_access_expr.field_name; |
| 1014 | if (buf_eql_str(name, "len")) { | 1028 | if (buf_eql_str(name, "len")) { |
| 1015 | return_type = g->builtin_types.entry_usize; | 1029 | return_type = g->builtin_types.entry_usize; |
| 1030 | } else if (buf_eql_str(name, "ptr")) { | ||
| 1031 | // TODO determine whether the pointer should be const | ||
| 1032 | return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false); | ||
| 1016 | } else { | 1033 | } else { |
| 1017 | add_node_error(g, node, | 1034 | add_node_error(g, node, |
| 1018 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), | 1035 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), |
| ... | @@ -1160,6 +1177,11 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -1160,6 +1177,11 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 1160 | codegen_num_lit->resolved_type = wanted_type; | 1177 | codegen_num_lit->resolved_type = wanted_type; |
| 1161 | cast_node->op = CastOpNothing; | 1178 | cast_node->op = CastOpNothing; |
| 1162 | return wanted_type; | 1179 | return wanted_type; |
| 1180 | } else if (actual_type->id == TypeTableEntryIdPointer && | ||
| 1181 | wanted_type->id == TypeTableEntryIdPointer) | ||
| 1182 | { | ||
| 1183 | cast_node->op = CastOpPointerReinterpret; | ||
| 1184 | return wanted_type; | ||
| 1163 | } else { | 1185 | } else { |
| 1164 | add_node_error(g, node, | 1186 | add_node_error(g, node, |
| 1165 | buf_sprintf("invalid cast from type '%s' to '%s'", | 1187 | buf_sprintf("invalid cast from type '%s' to '%s'", |
| ... | @@ -1286,6 +1308,9 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -1286,6 +1308,9 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 1286 | } | 1308 | } |
| 1287 | case BinOpTypeAdd: | 1309 | case BinOpTypeAdd: |
| 1288 | case BinOpTypeSub: | 1310 | case BinOpTypeSub: |
| 1311 | case BinOpTypeMult: | ||
| 1312 | case BinOpTypeDiv: | ||
| 1313 | case BinOpTypeMod: | ||
| 1289 | { | 1314 | { |
| 1290 | AstNode *op1 = node->data.bin_op_expr.op1; | 1315 | AstNode *op1 = node->data.bin_op_expr.op1; |
| 1291 | AstNode *op2 = node->data.bin_op_expr.op2; | 1316 | AstNode *op2 = node->data.bin_op_expr.op2; |
| ... | @@ -1294,15 +1319,6 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -1294,15 +1319,6 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 1294 | 1319 | ||
| 1295 | return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type); | 1320 | return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type); |
| 1296 | } | 1321 | } |
| 1297 | case BinOpTypeMult: | ||
| 1298 | case BinOpTypeDiv: | ||
| 1299 | case BinOpTypeMod: | ||
| 1300 | { | ||
| 1301 | // TODO: don't require i32 | ||
| 1302 | analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op1); | ||
| 1303 | analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op2); | ||
| 1304 | return g->builtin_types.entry_i32; | ||
| 1305 | } | ||
| 1306 | case BinOpTypeInvalid: | 1322 | case BinOpTypeInvalid: |
| 1307 | zig_unreachable(); | 1323 | zig_unreachable(); |
| 1308 | } | 1324 | } |
| ... | @@ -1746,6 +1762,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1746,6 +1762,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1746 | return_type = get_array_type(g, g->builtin_types.entry_u8, buf_len(&node->data.string_literal.buf)); | 1762 | return_type = get_array_type(g, g->builtin_types.entry_u8, buf_len(&node->data.string_literal.buf)); |
| 1747 | } | 1763 | } |
| 1748 | break; | 1764 | break; |
| 1765 | case NodeTypeCharLiteral: | ||
| 1766 | return_type = g->builtin_types.entry_u8; | ||
| 1767 | break; | ||
| 1749 | case NodeTypeUnreachable: | 1768 | case NodeTypeUnreachable: |
| 1750 | return_type = g->builtin_types.entry_unreachable; | 1769 | return_type = g->builtin_types.entry_unreachable; |
| 1751 | break; | 1770 | break; |
| ... | @@ -1959,6 +1978,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -1959,6 +1978,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 1959 | case NodeTypeArrayAccessExpr: | 1978 | case NodeTypeArrayAccessExpr: |
| 1960 | case NodeTypeNumberLiteral: | 1979 | case NodeTypeNumberLiteral: |
| 1961 | case NodeTypeStringLiteral: | 1980 | case NodeTypeStringLiteral: |
| 1981 | case NodeTypeCharLiteral: | ||
| 1962 | case NodeTypeUnreachable: | 1982 | case NodeTypeUnreachable: |
| 1963 | case NodeTypeVoid: | 1983 | case NodeTypeVoid: |
| 1964 | case NodeTypeBoolLiteral: | 1984 | case NodeTypeBoolLiteral: |
src/analyze.hpp+1| ... | @@ -277,6 +277,7 @@ enum CastOp { | ... | @@ -277,6 +277,7 @@ enum CastOp { |
| 277 | CastOpIntWidenOrShorten, | 277 | CastOpIntWidenOrShorten, |
| 278 | CastOpArrayToString, | 278 | CastOpArrayToString, |
| 279 | CastOpMaybeWrap, | 279 | CastOpMaybeWrap, |
| 280 | CastOpPointerReinterpret, | ||
| 280 | }; | 281 | }; |
| 281 | 282 | ||
| 282 | struct CastNode { | 283 | struct CastNode { |
src/codegen.cpp+4| ... | @@ -390,6 +390,8 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v | ... | @@ -390,6 +390,8 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v |
| 390 | } | 390 | } |
| 391 | case CastOpPtrToInt: | 391 | case CastOpPtrToInt: |
| 392 | return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, ""); | 392 | return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, ""); |
| 393 | case CastOpPointerReinterpret: | ||
| 394 | return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, ""); | ||
| 393 | case CastOpIntWidenOrShorten: | 395 | case CastOpIntWidenOrShorten: |
| 394 | if (actual_type->size_in_bits == wanted_type->size_in_bits) { | 396 | if (actual_type->size_in_bits == wanted_type->size_in_bits) { |
| 395 | return expr_val; | 397 | return expr_val; |
| ... | @@ -1236,6 +1238,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | ... | @@ -1236,6 +1238,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1236 | LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, ""); | 1238 | LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, ""); |
| 1237 | return ptr_val; | 1239 | return ptr_val; |
| 1238 | } | 1240 | } |
| 1241 | case NodeTypeCharLiteral: | ||
| 1242 | return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false); | ||
| 1239 | case NodeTypeSymbol: | 1243 | case NodeTypeSymbol: |
| 1240 | { | 1244 | { |
| 1241 | VariableTableEntry *variable = find_variable( | 1245 | VariableTableEntry *variable = find_variable( |
src/parser.cpp+66-2| ... | @@ -102,6 +102,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -102,6 +102,8 @@ const char *node_type_str(NodeType node_type) { |
| 102 | return "NumberLiteral"; | 102 | return "NumberLiteral"; |
| 103 | case NodeTypeStringLiteral: | 103 | case NodeTypeStringLiteral: |
| 104 | return "StringLiteral"; | 104 | return "StringLiteral"; |
| 105 | case NodeTypeCharLiteral: | ||
| 106 | return "CharLiteral"; | ||
| 105 | case NodeTypeUnreachable: | 107 | case NodeTypeUnreachable: |
| 106 | return "Unreachable"; | 108 | return "Unreachable"; |
| 107 | case NodeTypeSymbol: | 109 | case NodeTypeSymbol: |
| ... | @@ -313,6 +315,11 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -313,6 +315,11 @@ void ast_print(AstNode *node, int indent) { |
| 313 | buf_ptr(&node->data.string_literal.buf)); | 315 | buf_ptr(&node->data.string_literal.buf)); |
| 314 | break; | 316 | break; |
| 315 | } | 317 | } |
| 318 | case NodeTypeCharLiteral: | ||
| 319 | { | ||
| 320 | fprintf(stderr, "%s '%c'\n", node_type_str(node->type), node->data.char_literal.value); | ||
| 321 | break; | ||
| 322 | } | ||
| 316 | case NodeTypeUnreachable: | 323 | case NodeTypeUnreachable: |
| 317 | fprintf(stderr, "Unreachable\n"); | 324 | fprintf(stderr, "Unreachable\n"); |
| 318 | break; | 325 | break; |
| ... | @@ -575,6 +582,55 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) { | ... | @@ -575,6 +582,55 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) { |
| 575 | } | 582 | } |
| 576 | } | 583 | } |
| 577 | 584 | ||
| 585 | static uint8_t parse_char_literal(ParseContext *pc, Token *token) { | ||
| 586 | // skip the single quotes at beginning and end | ||
| 587 | // convert escape sequences | ||
| 588 | bool escape = false; | ||
| 589 | int return_count = 0; | ||
| 590 | uint8_t return_value; | ||
| 591 | for (int i = token->start_pos + 1; i < token->end_pos - 1; i += 1) { | ||
| 592 | uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i); | ||
| 593 | if (escape) { | ||
| 594 | switch (c) { | ||
| 595 | case '\\': | ||
| 596 | return_value = '\\'; | ||
| 597 | return_count += 1; | ||
| 598 | break; | ||
| 599 | case 'r': | ||
| 600 | return_value = '\r'; | ||
| 601 | return_count += 1; | ||
| 602 | break; | ||
| 603 | case 'n': | ||
| 604 | return_value = '\n'; | ||
| 605 | return_count += 1; | ||
| 606 | break; | ||
| 607 | case 't': | ||
| 608 | return_value = '\t'; | ||
| 609 | return_count += 1; | ||
| 610 | break; | ||
| 611 | case '\'': | ||
| 612 | return_value = '\''; | ||
| 613 | return_count += 1; | ||
| 614 | break; | ||
| 615 | default: | ||
| 616 | ast_error(pc, token, "invalid escape character"); | ||
| 617 | } | ||
| 618 | escape = false; | ||
| 619 | } else if (c == '\\') { | ||
| 620 | escape = true; | ||
| 621 | } else { | ||
| 622 | return_value = c; | ||
| 623 | return_count += 1; | ||
| 624 | } | ||
| 625 | } | ||
| 626 | if (return_count == 0) { | ||
| 627 | ast_error(pc, token, "character literal too short"); | ||
| 628 | } else if (return_count > 1) { | ||
| 629 | ast_error(pc, token, "character literal too long"); | ||
| 630 | } | ||
| 631 | return return_count; | ||
| 632 | } | ||
| 633 | |||
| 578 | static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str, | 634 | static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str, |
| 579 | ZigList<SrcPos> *offset_map) | 635 | ZigList<SrcPos> *offset_map) |
| 580 | { | 636 | { |
| ... | @@ -620,6 +676,9 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool | ... | @@ -620,6 +676,9 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool |
| 620 | buf_append_char(buf, '"'); | 676 | buf_append_char(buf, '"'); |
| 621 | if (offset_map) offset_map->append(pos); | 677 | if (offset_map) offset_map->append(pos); |
| 622 | break; | 678 | break; |
| 679 | default: | ||
| 680 | ast_error(pc, token, "invalid escape character"); | ||
| 681 | break; | ||
| 623 | } | 682 | } |
| 624 | escape = false; | 683 | escape = false; |
| 625 | } else if (c == '\\') { | 684 | } else if (c == '\\') { |
| ... | @@ -1136,7 +1195,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) { | ... | @@ -1136,7 +1195,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) { |
| 1136 | } | 1195 | } |
| 1137 | 1196 | ||
| 1138 | /* | 1197 | /* |
| 1139 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | 1198 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression |
| 1140 | */ | 1199 | */ |
| 1141 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1200 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1142 | Token *token = &pc->tokens->at(*token_index); | 1201 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -1151,6 +1210,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1151,6 +1210,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1151 | parse_string_literal(pc, token, &node->data.string_literal.buf, &node->data.string_literal.c, nullptr); | 1210 | parse_string_literal(pc, token, &node->data.string_literal.buf, &node->data.string_literal.c, nullptr); |
| 1152 | *token_index += 1; | 1211 | *token_index += 1; |
| 1153 | return node; | 1212 | return node; |
| 1213 | } else if (token->id == TokenIdCharLiteral) { | ||
| 1214 | AstNode *node = ast_create_node(pc, NodeTypeCharLiteral, token); | ||
| 1215 | node->data.char_literal.value = parse_char_literal(pc, token); | ||
| 1216 | *token_index += 1; | ||
| 1217 | return node; | ||
| 1154 | } else if (token->id == TokenIdKeywordUnreachable) { | 1218 | } else if (token->id == TokenIdKeywordUnreachable) { |
| 1155 | AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token); | 1219 | AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token); |
| 1156 | *token_index += 1; | 1220 | *token_index += 1; |
| ... | @@ -1733,7 +1797,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m | ... | @@ -1733,7 +1797,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m |
| 1733 | } | 1797 | } |
| 1734 | 1798 | ||
| 1735 | /* | 1799 | /* |
| 1736 | VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | 1800 | VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) |
| 1737 | */ | 1801 | */ |
| 1738 | static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1802 | static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1739 | Token *var_or_const_tok = &pc->tokens->at(*token_index); | 1803 | Token *var_or_const_tok = &pc->tokens->at(*token_index); |
src/parser.hpp+6| ... | @@ -35,6 +35,7 @@ enum NodeType { | ... | @@ -35,6 +35,7 @@ enum NodeType { |
| 35 | NodeTypeCastExpr, | 35 | NodeTypeCastExpr, |
| 36 | NodeTypeNumberLiteral, | 36 | NodeTypeNumberLiteral, |
| 37 | NodeTypeStringLiteral, | 37 | NodeTypeStringLiteral, |
| 38 | NodeTypeCharLiteral, | ||
| 38 | NodeTypeUnreachable, | 39 | NodeTypeUnreachable, |
| 39 | NodeTypeSymbol, | 40 | NodeTypeSymbol, |
| 40 | NodeTypePrefixOpExpr, | 41 | NodeTypePrefixOpExpr, |
| ... | @@ -289,6 +290,10 @@ struct AstNodeStringLiteral { | ... | @@ -289,6 +290,10 @@ struct AstNodeStringLiteral { |
| 289 | bool c; | 290 | bool c; |
| 290 | }; | 291 | }; |
| 291 | 292 | ||
| 293 | struct AstNodeCharLiteral { | ||
| 294 | uint8_t value; | ||
| 295 | }; | ||
| 296 | |||
| 292 | enum NumLit { | 297 | enum NumLit { |
| 293 | NumLitF32, | 298 | NumLitF32, |
| 294 | NumLitF64, | 299 | NumLitF64, |
| ... | @@ -359,6 +364,7 @@ struct AstNode { | ... | @@ -359,6 +364,7 @@ struct AstNode { |
| 359 | AstNodeStructDecl struct_decl; | 364 | AstNodeStructDecl struct_decl; |
| 360 | AstNodeStructField struct_field; | 365 | AstNodeStructField struct_field; |
| 361 | AstNodeStringLiteral string_literal; | 366 | AstNodeStringLiteral string_literal; |
| 367 | AstNodeCharLiteral char_literal; | ||
| 362 | AstNodeNumberLiteral number_literal; | 368 | AstNodeNumberLiteral number_literal; |
| 363 | AstNodeStructValueExpr struct_val_expr; | 369 | AstNodeStructValueExpr struct_val_expr; |
| 364 | AstNodeStructValueField struct_val_field; | 370 | AstNodeStructValueField struct_val_field; |
src/tokenizer.cpp+19| ... | @@ -103,6 +103,7 @@ enum TokenizeState { | ... | @@ -103,6 +103,7 @@ enum TokenizeState { |
| 103 | TokenizeStateFloatExponentUnsigned, // "123.456e", "123e", "0x123p" | 103 | TokenizeStateFloatExponentUnsigned, // "123.456e", "123e", "0x123p" |
| 104 | TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" | 104 | TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" |
| 105 | TokenizeStateString, | 105 | TokenizeStateString, |
| 106 | TokenizeStateCharLiteral, | ||
| 106 | TokenizeStateSawStar, | 107 | TokenizeStateSawStar, |
| 107 | TokenizeStateSawSlash, | 108 | TokenizeStateSawSlash, |
| 108 | TokenizeStateSawPercent, | 109 | TokenizeStateSawPercent, |
| ... | @@ -307,6 +308,10 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -307,6 +308,10 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 307 | begin_token(&t, TokenIdStringLiteral); | 308 | begin_token(&t, TokenIdStringLiteral); |
| 308 | t.state = TokenizeStateString; | 309 | t.state = TokenizeStateString; |
| 309 | break; | 310 | break; |
| 311 | case '\'': | ||
| 312 | begin_token(&t, TokenIdCharLiteral); | ||
| 313 | t.state = TokenizeStateCharLiteral; | ||
| 314 | break; | ||
| 310 | case '(': | 315 | case '(': |
| 311 | begin_token(&t, TokenIdLParen); | 316 | begin_token(&t, TokenIdLParen); |
| 312 | end_token(&t); | 317 | end_token(&t); |
| ... | @@ -773,6 +778,16 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -773,6 +778,16 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 773 | break; | 778 | break; |
| 774 | } | 779 | } |
| 775 | break; | 780 | break; |
| 781 | case TokenizeStateCharLiteral: | ||
| 782 | switch (c) { | ||
| 783 | case '\'': | ||
| 784 | end_token(&t); | ||
| 785 | t.state = TokenizeStateStart; | ||
| 786 | break; | ||
| 787 | default: | ||
| 788 | break; | ||
| 789 | } | ||
| 790 | break; | ||
| 776 | case TokenizeStateZero: | 791 | case TokenizeStateZero: |
| 777 | switch (c) { | 792 | switch (c) { |
| 778 | case 'b': | 793 | case 'b': |
| ... | @@ -912,6 +927,9 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -912,6 +927,9 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 912 | case TokenizeStateString: | 927 | case TokenizeStateString: |
| 913 | tokenize_error(&t, "unterminated string"); | 928 | tokenize_error(&t, "unterminated string"); |
| 914 | break; | 929 | break; |
| 930 | case TokenizeStateCharLiteral: | ||
| 931 | tokenize_error(&t, "unterminated character literal"); | ||
| 932 | break; | ||
| 915 | case TokenizeStateSymbol: | 933 | case TokenizeStateSymbol: |
| 916 | case TokenizeStateSymbolFirst: | 934 | case TokenizeStateSymbolFirst: |
| 917 | case TokenizeStateZero: | 935 | case TokenizeStateZero: |
| ... | @@ -993,6 +1011,7 @@ static const char * token_name(Token *token) { | ... | @@ -993,6 +1011,7 @@ static const char * token_name(Token *token) { |
| 993 | case TokenIdLBracket: return "LBracket"; | 1011 | case TokenIdLBracket: return "LBracket"; |
| 994 | case TokenIdRBracket: return "RBracket"; | 1012 | case TokenIdRBracket: return "RBracket"; |
| 995 | case TokenIdStringLiteral: return "StringLiteral"; | 1013 | case TokenIdStringLiteral: return "StringLiteral"; |
| 1014 | case TokenIdCharLiteral: return "CharLiteral"; | ||
| 996 | case TokenIdSemicolon: return "Semicolon"; | 1015 | case TokenIdSemicolon: return "Semicolon"; |
| 997 | case TokenIdNumberLiteral: return "NumberLiteral"; | 1016 | case TokenIdNumberLiteral: return "NumberLiteral"; |
| 998 | case TokenIdPlus: return "Plus"; | 1017 | case TokenIdPlus: return "Plus"; |
src/tokenizer.hpp+1| ... | @@ -44,6 +44,7 @@ enum TokenId { | ... | @@ -44,6 +44,7 @@ enum TokenId { |
| 44 | TokenIdLBracket, | 44 | TokenIdLBracket, |
| 45 | TokenIdRBracket, | 45 | TokenIdRBracket, |
| 46 | TokenIdStringLiteral, | 46 | TokenIdStringLiteral, |
| 47 | TokenIdCharLiteral, | ||
| 47 | TokenIdSemicolon, | 48 | TokenIdSemicolon, |
| 48 | TokenIdNumberLiteral, | 49 | TokenIdNumberLiteral, |
| 49 | TokenIdPlus, | 50 | TokenIdPlus, |
std/errno.zig created+146| ... | @@ -0,0 +1,146 @@ | ||
| 1 | pub const EPERM = 1; // Operation not permitted | ||
| 2 | pub const ENOENT = 2; // No such file or directory | ||
| 3 | pub const ESRCH = 3; // No such process | ||
| 4 | pub const EINTR = 4; // Interrupted system call | ||
| 5 | pub const EIO = 5; // I/O error | ||
| 6 | pub const ENXIO = 6; // No such device or address | ||
| 7 | pub const E2BIG = 7; // Arg list too long | ||
| 8 | pub const ENOEXEC = 8; // Exec format error | ||
| 9 | pub const EBADF = 9; // Bad file number | ||
| 10 | pub const ECHILD = 10; // No child processes | ||
| 11 | pub const EAGAIN = 11; // Try again | ||
| 12 | pub const ENOMEM = 12; // Out of memory | ||
| 13 | pub const EACCES = 13; // Permission denied | ||
| 14 | pub const EFAULT = 14; // Bad address | ||
| 15 | pub const ENOTBLK = 15; // Block device required | ||
| 16 | pub const EBUSY = 16; // Device or resource busy | ||
| 17 | pub const EEXIST = 17; // File exists | ||
| 18 | pub const EXDEV = 18; // Cross-device link | ||
| 19 | pub const ENODEV = 19; // No such device | ||
| 20 | pub const ENOTDIR = 20; // Not a directory | ||
| 21 | pub const EISDIR = 21; // Is a directory | ||
| 22 | pub const EINVAL = 22; // Invalid argument | ||
| 23 | pub const ENFILE = 23; // File table overflow | ||
| 24 | pub const EMFILE = 24; // Too many open files | ||
| 25 | pub const ENOTTY = 25; // Not a typewriter | ||
| 26 | pub const ETXTBSY = 26; // Text file busy | ||
| 27 | pub const EFBIG = 27; // File too large | ||
| 28 | pub const ENOSPC = 28; // No space left on device | ||
| 29 | pub const ESPIPE = 29; // Illegal seek | ||
| 30 | pub const EROFS = 30; // Read-only file system | ||
| 31 | pub const EMLINK = 31; // Too many links | ||
| 32 | pub const EPIPE = 32; // Broken pipe | ||
| 33 | pub const EDOM = 33; // Math argument out of domain of func | ||
| 34 | pub const ERANGE = 34; // Math result not representable | ||
| 35 | pub const EDEADLK = 35; // Resource deadlock would occur | ||
| 36 | pub const ENAMETOOLONG = 36; // File name too long | ||
| 37 | pub const ENOLCK = 37; // No record locks available | ||
| 38 | pub const ENOSYS = 38; // Function not implemented | ||
| 39 | pub const ENOTEMPTY = 39; // Directory not empty | ||
| 40 | pub const ELOOP = 40; // Too many symbolic links encountered | ||
| 41 | pub const EWOULDBLOCK = EAGAIN; // Operation would block | ||
| 42 | pub const ENOMSG = 42; // No message of desired type | ||
| 43 | pub const EIDRM = 43; // Identifier removed | ||
| 44 | pub const ECHRNG = 44; // Channel number out of range | ||
| 45 | pub const EL2NSYNC = 45; // Level 2 not synchronized | ||
| 46 | pub const EL3HLT = 46; // Level 3 halted | ||
| 47 | pub const EL3RST = 47; // Level 3 reset | ||
| 48 | pub const ELNRNG = 48; // Link number out of range | ||
| 49 | pub const EUNATCH = 49; // Protocol driver not attached | ||
| 50 | pub const ENOCSI = 50; // No CSI structure available | ||
| 51 | pub const EL2HLT = 51; // Level 2 halted | ||
| 52 | pub const EBADE = 52; // Invalid exchange | ||
| 53 | pub const EBADR = 53; // Invalid request descriptor | ||
| 54 | pub const EXFULL = 54; // Exchange full | ||
| 55 | pub const ENOANO = 55; // No anode | ||
| 56 | pub const EBADRQC = 56; // Invalid request code | ||
| 57 | pub const EBADSLT = 57; // Invalid slot | ||
| 58 | |||
| 59 | pub const EBFONT = 59; // Bad font file format | ||
| 60 | pub const ENOSTR = 60; // Device not a stream | ||
| 61 | pub const ENODATA = 61; // No data available | ||
| 62 | pub const ETIME = 62; // Timer expired | ||
| 63 | pub const ENOSR = 63; // Out of streams resources | ||
| 64 | pub const ENONET = 64; // Machine is not on the network | ||
| 65 | pub const ENOPKG = 65; // Package not installed | ||
| 66 | pub const EREMOTE = 66; // Object is remote | ||
| 67 | pub const ENOLINK = 67; // Link has been severed | ||
| 68 | pub const EADV = 68; // Advertise error | ||
| 69 | pub const ESRMNT = 69; // Srmount error | ||
| 70 | pub const ECOMM = 70; // Communication error on send | ||
| 71 | pub const EPROTO = 71; // Protocol error | ||
| 72 | pub const EMULTIHOP = 72; // Multihop attempted | ||
| 73 | pub const EDOTDOT = 73; // RFS specific error | ||
| 74 | pub const EBADMSG = 74; // Not a data message | ||
| 75 | pub const EOVERFLOW = 75; // Value too large for defined data type | ||
| 76 | pub const ENOTUNIQ = 76; // Name not unique on network | ||
| 77 | pub const EBADFD = 77; // File descriptor in bad state | ||
| 78 | pub const EREMCHG = 78; // Remote address changed | ||
| 79 | pub const ELIBACC = 79; // Can not access a needed shared library | ||
| 80 | pub const ELIBBAD = 80; // Accessing a corrupted shared library | ||
| 81 | pub const ELIBSCN = 81; // .lib section in a.out corrupted | ||
| 82 | pub const ELIBMAX = 82; // Attempting to link in too many shared libraries | ||
| 83 | pub const ELIBEXEC = 83; // Cannot exec a shared library directly | ||
| 84 | pub const EILSEQ = 84; // Illegal byte sequence | ||
| 85 | pub const ERESTART = 85; // Interrupted system call should be restarted | ||
| 86 | pub const ESTRPIPE = 86; // Streams pipe error | ||
| 87 | pub const EUSERS = 87; // Too many users | ||
| 88 | pub const ENOTSOCK = 88; // Socket operation on non-socket | ||
| 89 | pub const EDESTADDRREQ = 89; // Destination address required | ||
| 90 | pub const EMSGSIZE = 90; // Message too long | ||
| 91 | pub const EPROTOTYPE = 91; // Protocol wrong type for socket | ||
| 92 | pub const ENOPROTOOPT = 92; // Protocol not available | ||
| 93 | pub const EPROTONOSUPPORT = 93; // Protocol not supported | ||
| 94 | pub const ESOCKTNOSUPPORT = 94; // Socket type not supported | ||
| 95 | pub const EOPNOTSUPP = 95; // Operation not supported on transport endpoint | ||
| 96 | pub const EPFNOSUPPORT = 96; // Protocol family not supported | ||
| 97 | pub const EAFNOSUPPORT = 97; // Address family not supported by protocol | ||
| 98 | pub const EADDRINUSE = 98; // Address already in use | ||
| 99 | pub const EADDRNOTAVAIL = 99; // Cannot assign requested address | ||
| 100 | pub const ENETDOWN = 100; // Network is down | ||
| 101 | pub const ENETUNREACH = 101; // Network is unreachable | ||
| 102 | pub const ENETRESET = 102; // Network dropped connection because of reset | ||
| 103 | pub const ECONNABORTED = 103; // Software caused connection abort | ||
| 104 | pub const ECONNRESET = 104; // Connection reset by peer | ||
| 105 | pub const ENOBUFS = 105; // No buffer space available | ||
| 106 | pub const EISCONN = 106; // Transport endpoint is already connected | ||
| 107 | pub const ENOTCONN = 107; // Transport endpoint is not connected | ||
| 108 | pub const ESHUTDOWN = 108; // Cannot send after transport endpoint shutdown | ||
| 109 | pub const ETOOMANYREFS = 109; // Too many references: cannot splice | ||
| 110 | pub const ETIMEDOUT = 110; // Connection timed out | ||
| 111 | pub const ECONNREFUSED = 111; // Connection refused | ||
| 112 | pub const EHOSTDOWN = 112; // Host is down | ||
| 113 | pub const EHOSTUNREACH = 113; // No route to host | ||
| 114 | pub const EALREADY = 114; // Operation already in progress | ||
| 115 | pub const EINPROGRESS = 115; // Operation now in progress | ||
| 116 | pub const ESTALE = 116; // Stale NFS file handle | ||
| 117 | pub const EUCLEAN = 117; // Structure needs cleaning | ||
| 118 | pub const ENOTNAM = 118; // Not a XENIX named type file | ||
| 119 | pub const ENAVAIL = 119; // No XENIX semaphores available | ||
| 120 | pub const EISNAM = 120; // Is a named type file | ||
| 121 | pub const EREMOTEIO = 121; // Remote I/O error | ||
| 122 | pub const EDQUOT = 122; // Quota exceeded | ||
| 123 | |||
| 124 | pub const ENOMEDIUM = 123; // No medium found | ||
| 125 | pub const EMEDIUMTYPE = 124; // Wrong medium type | ||
| 126 | |||
| 127 | // nameserver query return codes | ||
| 128 | pub const ENSROK = 0; // DNS server returned answer with no data | ||
| 129 | pub const ENSRNODATA = 160; // DNS server returned answer with no data | ||
| 130 | pub const ENSRFORMERR = 161; // DNS server claims query was misformatted | ||
| 131 | pub const ENSRSERVFAIL = 162; // DNS server returned general failure | ||
| 132 | pub const ENSRNOTFOUND = 163; // Domain name not found | ||
| 133 | pub const ENSRNOTIMP = 164; // DNS server does not implement requested operation | ||
| 134 | pub const ENSRREFUSED = 165; // DNS server refused query | ||
| 135 | pub const ENSRBADQUERY = 166; // Misformatted DNS query | ||
| 136 | pub const ENSRBADNAME = 167; // Misformatted domain name | ||
| 137 | pub const ENSRBADFAMILY = 168; // Unsupported address family | ||
| 138 | pub const ENSRBADRESP = 169; // Misformatted DNS reply | ||
| 139 | pub const ENSRCONNREFUSED = 170; // Could not contact DNS servers | ||
| 140 | pub const ENSRTIMEOUT = 171; // Timeout while contacting DNS servers | ||
| 141 | pub const ENSROF = 172; // End of file | ||
| 142 | pub const ENSRFILE = 173; // Error reading file | ||
| 143 | pub const ENSRNOMEM = 174; // Out of memory | ||
| 144 | pub const ENSRDESTRUCTION = 175; // Application terminated lookup | ||
| 145 | pub const ENSRQUERYDOMAINTOOLONG = 176; // Domain name is too long | ||
| 146 | pub const ENSRCNAMELOOP = 177; // Domain name is too long | ||
std/std.zig+66-3| ... | @@ -1,6 +1,9 @@ | ... | @@ -1,6 +1,9 @@ |
| 1 | const SYS_write : isize = 1; | 1 | const SYS_write : isize = 1; |
| 2 | const SYS_exit : isize = 60; | 2 | const SYS_exit : isize = 60; |
| 3 | const SYS_getrandom : isize = 278; | ||
| 4 | |||
| 3 | const stdout_fileno : isize = 1; | 5 | const stdout_fileno : isize = 1; |
| 6 | const stderr_fileno : isize = 2; | ||
| 4 | 7 | ||
| 5 | fn syscall1(number: isize, arg1: isize) -> isize { | 8 | fn syscall1(number: isize, arg1: isize) -> isize { |
| 6 | asm volatile ("syscall" | 9 | asm volatile ("syscall" |
| ... | @@ -16,6 +19,12 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { | ... | @@ -16,6 +19,12 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 16 | : "rcx", "r11") | 19 | : "rcx", "r11") |
| 17 | } | 20 | } |
| 18 | 21 | ||
| 22 | /* | ||
| 23 | pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize { | ||
| 24 | return syscall3(SYS_getrandom, buf as isize, count as isize, flags as isize); | ||
| 25 | } | ||
| 26 | */ | ||
| 27 | |||
| 19 | pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { | 28 | pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { |
| 20 | return syscall3(SYS_write, fd, buf as isize, count as isize); | 29 | return syscall3(SYS_write, fd, buf as isize, count as isize); |
| 21 | } | 30 | } |
| ... | @@ -25,8 +34,62 @@ pub fn exit(status: i32) -> unreachable { | ... | @@ -25,8 +34,62 @@ pub fn exit(status: i32) -> unreachable { |
| 25 | unreachable; | 34 | unreachable; |
| 26 | } | 35 | } |
| 27 | 36 | ||
| 37 | /* | ||
| 38 | fn digit_to_char(digit: u64) -> u8 { '0' + (digit as u8) } | ||
| 39 | |||
| 40 | const max_u64_base10_digits: usize = 20; | ||
| 41 | |||
| 42 | fn buf_print_u64(out_buf: &u8, x: u64) -> usize { | ||
| 43 | // TODO use max_u64_base10_digits instead of hardcoding 20 | ||
| 44 | var buf: [u8; 20]; | ||
| 45 | var a = x; | ||
| 46 | var index = max_u64_base10_digits; | ||
| 47 | |||
| 48 | while (true) { | ||
| 49 | const digit = a % 10; | ||
| 50 | index -= 1; | ||
| 51 | buf[index] = digit_to_char(digit); | ||
| 52 | a /= 10; | ||
| 53 | if (a == 0) | ||
| 54 | break; | ||
| 55 | } | ||
| 56 | |||
| 57 | const len = max_u64_base10_digits - index; | ||
| 58 | |||
| 59 | // TODO memcpy intrinsic | ||
| 60 | var i: usize = 0; | ||
| 61 | while (i < len) { | ||
| 62 | out_buf[i] = buf[index + i]; | ||
| 63 | i += 1; | ||
| 64 | } | ||
| 65 | |||
| 66 | return len; | ||
| 67 | } | ||
| 68 | |||
| 69 | // TODO handle buffering and flushing (mutex protected) | ||
| 70 | // TODO error handling | ||
| 71 | pub fn print_u64(x: u64) -> isize { | ||
| 72 | // TODO use max_u64_base10_digits instead of hardcoding 20 | ||
| 73 | var buf: [u8; 20]; | ||
| 74 | const len = buf_print_u64(buf.ptr, x); | ||
| 75 | return write(stdout_fileno, buf.ptr, len); | ||
| 76 | } | ||
| 77 | */ | ||
| 78 | |||
| 79 | |||
| 80 | // TODO error handling | ||
| 81 | // TODO handle buffering and flushing (mutex protected) | ||
| 82 | pub fn print_str(str: string) -> isize { fprint_str(stdout_fileno, str) } | ||
| 83 | |||
| 84 | // TODO error handling | ||
| 85 | // TODO handle buffering and flushing (mutex protected) | ||
| 86 | pub fn fprint_str(fd: isize, str: string) -> isize { | ||
| 87 | return write(fd, str.ptr, str.len); | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 28 | // TODO error handling | 91 | // TODO error handling |
| 29 | // TODO handle buffering and flushing | 92 | pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize { |
| 30 | pub fn print_str(str : string) -> isize { | 93 | return getrandom(buf, count, 0); |
| 31 | return write(stdout_fileno, str.ptr, str.len); | ||
| 32 | } | 94 | } |
| 95 | */ |