authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-20 18:18:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-20 18:18:50-07:00
log5e212db29cf9e2c06aba363736ffb965e631aa2d
tree2ec22f86549bca4cceb423bb3b66aa796754951f
parent82d1b51b1d34a0c1b21ec2aaae70051379b37f43

parsing error value decls and error value literals

and return with '?' or '%' prefix

10 files changed, 548 insertions(+), 88 deletions(-)

doc/langref.md+23-10
......@@ -5,9 +5,11 @@
55```
66Root : many(TopLevelDecl) "EOF"
77
8TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration
8TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
99
10VariableDeclaration : option(FnVisibleMod) ("var" | "const") "symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
10ErrorValueDecl : option(FnVisibleMod) "%." "Symbol"
11
12VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
1113
1214ContainerDecl : many(Directive) option(FnVisibleMod) ("struct" | "enum") "Symbol" "{" many(StructMember) "}"
1315
......@@ -77,7 +79,7 @@ ForExpression : "for" "(" "Symbol" "," Expression option("," "Symbol") ")" Expre
7779
7880BoolOrExpression : BoolAndExpression "||" BoolOrExpression | BoolAndExpression
7981
80ReturnExpression : "return" option(Expression)
82ReturnExpression : option("%" | "?") "return" option(Expression)
8183
8284IfExpression : IfVarExpression | IfBoolExpression
8385
......@@ -133,7 +135,7 @@ StructLiteralField : "." "Symbol" "=" Expression
133135
134136PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?"
135137
136PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression
138PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol")
137139
138140ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression
139141
......@@ -148,7 +150,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue"
148150
149151```
150152x() x[] x.y
151!x -x ~x *x &x ?x
153!x -x ~x *x &x ?x %x
152154x{}
153155* / %
154156+ -
......@@ -199,12 +201,20 @@ c_ulonglong unsigned long long for ABI compatibility with C
199201### Boolean Type
200202The boolean type has the name `bool` and represents either true or false.
201203
202### Function Types
204### Function Type
203205TODO
204206
205### Array Types
206TODO
207Also, are there slices?
207### Fixed-Size Array Type
208
209Example: The string `"aoeu"` has type `[4]u8`.
210
211The size is known at compile time and is part of the type.
212
213### Slice Type
214
215A slice can be obtained with the slicing syntax: `array[start...end]`
216
217Example: `"aoeu"[0...2]` has type `[]u8`.
208218
209219### Struct Types
210220TODO
......@@ -213,10 +223,13 @@ TODO
213223TODO
214224
215225### Unreachable Type
226
216227The unreachable type has the name `unreachable`. TODO explanation
217228
218229### Void Type
219The void type has the name `void`. TODO explanation
230
231The void type has the name `void`. void types are zero bits and are omitted
232from codegen.
220233
221234
222235## Expressions
example/cat/main.zig+17-17
......@@ -3,50 +3,50 @@ export executable "cat";
33import "std.zig";
44
55// Things to do to make this work:
6// * isize instead of usize for things
76// * var args printing
8// * update std API
9// * !void type
7// * %void type
108// * defer
11// * !return
12// * !! operator
13// * make main return !void
14// * how to reference error values (!void).Invalid ? !Invalid ?
15// * ~ is bool not, not !
9// * %return
10// * %% operator
11// * make main return %void
12// * how to reference error values %.Invalid
1613// * cast err type to string
14// * update std API
15
16pub %.Invalid;
1717
18pub fn main(args: [][]u8) !void => {
18pub fn main(args: [][]u8) %void => {
1919 const exe = args[0];
2020 var catted_anything = false;
2121 for (arg, args[1...]) {
2222 if (arg == "-") {
2323 catted_anything = true;
24 !return cat_stream(stdin);
24 %return cat_stream(stdin);
2525 } else if (arg[0] == '-') {
2626 return usage(exe);
2727 } else {
2828 var is: InputStream;
29 is.open(arg, OpenReadOnly) !! (err) => {
29 is.open(arg, OpenReadOnly) %% (err) => {
3030 stderr.print("Unable to open file: {}", ([]u8])(err));
3131 return err;
3232 }
3333 defer is.close();
3434
3535 catted_anything = true;
36 !return cat_stream(is);
36 %return cat_stream(is);
3737 }
3838 }
39 if (~catted_anything) {
40 !return cat_stream(stdin)
39 if (!catted_anything) {
40 %return cat_stream(stdin)
4141 }
4242}
4343
44fn usage(exe: []u8) !void => {
44fn usage(exe: []u8) %void => {
4545 stderr.print("Usage: {} [FILE]...\n", exe);
46 return !Invalid;
46 return %.Invalid;
4747}
4848
49fn cat_stream(is: InputStream) !void => {
49fn cat_stream(is: InputStream) %void => {
5050 var buf: [1024 * 4]u8;
5151
5252 while (true) {
example/hello_world/hello.zig+1
......@@ -3,6 +3,7 @@ export executable "hello";
33import "std.zig";
44
55pub fn main(args: [][]u8) i32 => {
6 //stderr.print_str("Hello, world!\n");
67 print_str("Hello, world!\n");
78 return 0;
89}
src/all_types.hpp+35
......@@ -129,10 +129,12 @@ enum NodeType {
129129 NodeTypeDirective,
130130 NodeTypeReturnExpr,
131131 NodeTypeVariableDeclaration,
132 NodeTypeErrorValueDecl,
132133 NodeTypeBinOpExpr,
133134 NodeTypeNumberLiteral,
134135 NodeTypeStringLiteral,
135136 NodeTypeCharLiteral,
137 NodeTypeErrorLiteral,
136138 NodeTypeSymbol,
137139 NodeTypePrefixOpExpr,
138140 NodeTypeFnCallExpr,
......@@ -222,7 +224,14 @@ struct AstNodeBlock {
222224 Expr resolved_expr;
223225};
224226
227enum ReturnKind {
228 ReturnKindUnconditional,
229 ReturnKindMaybe,
230 ReturnKindError,
231};
232
225233struct AstNodeReturnExpr {
234 ReturnKind kind;
226235 // might be null in case of return void;
227236 AstNode *expr;
228237
......@@ -243,6 +252,14 @@ struct AstNodeVariableDeclaration {
243252 Expr resolved_expr;
244253};
245254
255struct AstNodeErrorValueDecl {
256 VisibMod visib_mod;
257 Buf name;
258
259 // populated by semantic analyzer
260 TopLevelDecl top_level_decl;
261};
262
246263enum BinOpType {
247264 BinOpTypeInvalid,
248265 BinOpTypeAssign,
......@@ -358,6 +375,7 @@ enum PrefixOp {
358375 PrefixOpConstAddressOf,
359376 PrefixOpDereference,
360377 PrefixOpMaybe,
378 PrefixOpError,
361379};
362380
363381struct AstNodePrefixOpExpr {
......@@ -564,6 +582,14 @@ struct AstNodeNumberLiteral {
564582 Expr resolved_expr;
565583};
566584
585struct AstNodeErrorLiteral {
586 Buf symbol;
587
588 // populated by semantic analyzer
589 NumLitCodeGen codegen;
590 Expr resolved_expr;
591};
592
567593struct AstNodeStructValueField {
568594 Buf name;
569595 AstNode *expr;
......@@ -644,6 +670,7 @@ struct AstNode {
644670 AstNodeBlock block;
645671 AstNodeReturnExpr return_expr;
646672 AstNodeVariableDeclaration variable_declaration;
673 AstNodeErrorValueDecl error_value_decl;
647674 AstNodeBinOpExpr bin_op_expr;
648675 AstNodeExternBlock extern_block;
649676 AstNodeDirective directive;
......@@ -668,6 +695,7 @@ struct AstNode {
668695 AstNodeStringLiteral string_literal;
669696 AstNodeCharLiteral char_literal;
670697 AstNodeNumberLiteral number_literal;
698 AstNodeErrorLiteral error_literal;
671699 AstNodeContainerInitExpr container_init_expr;
672700 AstNodeStructValueField struct_val_field;
673701 AstNodeNullLiteral null_literal;
......@@ -738,6 +766,10 @@ struct TypeTableEntryMaybe {
738766 TypeTableEntry *child_type;
739767};
740768
769struct TypeTableEntryError {
770 TypeTableEntry *child_type;
771};
772
741773struct TypeTableEntryEnum {
742774 AstNode *decl_node;
743775 uint32_t field_count;
......@@ -778,6 +810,7 @@ enum TypeTableEntryId {
778810 TypeTableEntryIdStruct,
779811 TypeTableEntryIdNumberLiteral,
780812 TypeTableEntryIdMaybe,
813 TypeTableEntryIdError,
781814 TypeTableEntryIdEnum,
782815 TypeTableEntryIdFn,
783816};
......@@ -799,6 +832,7 @@ struct TypeTableEntry {
799832 TypeTableEntryStruct structure;
800833 TypeTableEntryNumLit num_lit;
801834 TypeTableEntryMaybe maybe;
835 TypeTableEntryError error;
802836 TypeTableEntryEnum enumeration;
803837 TypeTableEntryFn fn;
804838 } data;
......@@ -808,6 +842,7 @@ struct TypeTableEntry {
808842 TypeTableEntry *unknown_size_array_parent[2];
809843 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
810844 TypeTableEntry *maybe_parent;
845 TypeTableEntry *error_parent;
811846};
812847
813848struct ImporterInfo {
src/analyze.cpp+148-24
......@@ -43,7 +43,9 @@ static AstNode *first_executing_node(AstNode *node) {
4343 case NodeTypeDirective:
4444 case NodeTypeReturnExpr:
4545 case NodeTypeVariableDeclaration:
46 case NodeTypeErrorValueDecl:
4647 case NodeTypeNumberLiteral:
48 case NodeTypeErrorLiteral:
4749 case NodeTypeStringLiteral:
4850 case NodeTypeCharLiteral:
4951 case NodeTypeSymbol:
......@@ -104,6 +106,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
104106 case TypeTableEntryIdNumberLiteral:
105107 case TypeTableEntryIdMaybe:
106108 case TypeTableEntryIdFn:
109 case TypeTableEntryIdError:
107110 // nothing to init
108111 break;
109112 case TypeTableEntryIdStruct:
......@@ -215,6 +218,57 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
215218 }
216219}
217220
221static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
222 if (child_type->error_parent) {
223 return child_type->error_parent;
224 } else {
225 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdError);
226 zig_panic("TODO get_error_type");
227 // create a struct with a boolean whether this is the null value
228 assert(child_type->type_ref);
229 LLVMTypeRef elem_types[] = {
230 child_type->type_ref,
231 LLVMInt1Type(),
232 };
233 entry->type_ref = LLVMStructType(elem_types, 2, false);
234 buf_resize(&entry->name, 0);
235 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
236 entry->size_in_bits = child_type->size_in_bits + 8;
237 entry->align_in_bits = child_type->align_in_bits;
238 assert(child_type->di_type);
239
240
241 LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
242 LLVMZigDIFile *di_file = nullptr;
243 unsigned line = 0;
244 entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
245 LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
246 compile_unit_scope, di_file, line);
247
248 LLVMZigDIType *di_element_types[] = {
249 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
250 "val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
251 child_type->di_type),
252 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
253 "maybe", di_file, line, 8, 8, 8, 0,
254 child_type->di_type),
255 };
256 LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
257 compile_unit_scope,
258 buf_ptr(&entry->name),
259 di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
260 nullptr, di_element_types, 2, 0, nullptr, "");
261
262 LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
263 entry->di_type = replacement_di_type;
264
265 entry->data.maybe.child_type = child_type;
266
267 child_type->maybe_parent = entry;
268 return entry;
269 }
270}
271
218272static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size)
219273{
220274 auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);
......@@ -922,6 +976,11 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
922976 g->global_vars.append(var);
923977 break;
924978 }
979 case NodeTypeErrorValueDecl:
980 {
981 zig_panic("TODO resolve_top_level_decl NodeTypeErrorValueDecl");
982 break;
983 }
925984 case NodeTypeUse:
926985 // nothing to do here
927986 break;
......@@ -937,6 +996,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
937996 case NodeTypeArrayAccessExpr:
938997 case NodeTypeSliceExpr:
939998 case NodeTypeNumberLiteral:
999 case NodeTypeErrorLiteral:
9401000 case NodeTypeStringLiteral:
9411001 case NodeTypeCharLiteral:
9421002 case NodeTypeBoolLiteral:
......@@ -1005,6 +1065,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,
10051065 case TypeTableEntryIdEnum:
10061066 case TypeTableEntryIdMetaType:
10071067 case TypeTableEntryIdFn:
1068 case TypeTableEntryIdError:
10081069 return false;
10091070 case TypeTableEntryIdInt:
10101071 if (is_num_lit_unsigned(num_lit)) {
......@@ -2263,6 +2324,12 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
22632324 }
22642325}
22652326
2327static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
2328 BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
2329{
2330 zig_panic("TODO analyze_error_literal_expr");
2331}
2332
22662333static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
22672334 TypeTableEntry *expected_type, AstNode *node)
22682335{
......@@ -3021,7 +3088,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
30213088 if (meta_type->id == TypeTableEntryIdInvalid) {
30223089 return g->builtin_types.entry_invalid;
30233090 } else if (meta_type->id == TypeTableEntryIdUnreachable) {
3024 add_node_error(g, node, buf_create_from_str("maybe unreachable type not allowed"));
3091 add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in maybe type"));
30253092 return g->builtin_types.entry_invalid;
30263093 } else {
30273094 return resolve_expr_const_val_as_type(g, node, get_maybe_type(g, meta_type));
......@@ -3034,6 +3101,31 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
30343101 return get_maybe_type(g, type_entry);
30353102 }
30363103 }
3104 case PrefixOpError:
3105 {
3106 TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
3107
3108 if (type_entry->id == TypeTableEntryIdInvalid) {
3109 return type_entry;
3110 } else if (type_entry->id == TypeTableEntryIdMetaType) {
3111 TypeTableEntry *meta_type = resolve_type(g, expr_node);
3112 if (meta_type->id == TypeTableEntryIdInvalid) {
3113 return meta_type;
3114 } else if (meta_type->id == TypeTableEntryIdUnreachable) {
3115 add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in error type"));
3116 return g->builtin_types.entry_invalid;
3117 } else {
3118 return resolve_expr_const_val_as_type(g, node, get_error_type(g, meta_type));
3119 }
3120 } else if (type_entry->id == TypeTableEntryIdUnreachable) {
3121 add_node_error(g, expr_node, buf_sprintf("unable to wrap unreachable in error type"));
3122 return g->builtin_types.entry_invalid;
3123 } else {
3124 // TODO eval const expr
3125 return get_error_type(g, type_entry);
3126 }
3127
3128 }
30373129 }
30383130 zig_unreachable();
30393131}
......@@ -3099,6 +3191,37 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
30993191 return expected_type;
31003192}
31013193
3194static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3195 TypeTableEntry *expected_type, AstNode *node)
3196{
3197 if (!context->fn_entry) {
3198 add_node_error(g, node, buf_sprintf("return expression outside function definition"));
3199 return g->builtin_types.entry_invalid;
3200 }
3201
3202 if (node->data.return_expr.kind != ReturnKindUnconditional) {
3203 zig_panic("TODO analyze_return_expr conditional");
3204 }
3205
3206 TypeTableEntry *expected_return_type = get_return_type(context);
3207 TypeTableEntry *actual_return_type;
3208 if (node->data.return_expr.expr) {
3209 actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
3210 } else {
3211 actual_return_type = g->builtin_types.entry_void;
3212 }
3213
3214 if (actual_return_type->id == TypeTableEntryIdUnreachable) {
3215 // "return exit(0)" should just be "exit(0)".
3216 add_node_error(g, node, buf_sprintf("returning is unreachable"));
3217 actual_return_type = g->builtin_types.entry_invalid;
3218 }
3219
3220 resolve_type_compatibility(g, context, node, expected_return_type, actual_return_type);
3221
3222 return g->builtin_types.entry_unreachable;
3223}
3224
31023225static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
31033226 TypeTableEntry *expected_type, AstNode *node)
31043227{
......@@ -3140,29 +3263,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
31403263 }
31413264
31423265 case NodeTypeReturnExpr:
3143 {
3144 if (context->fn_entry) {
3145 TypeTableEntry *expected_return_type = get_return_type(context);
3146 TypeTableEntry *actual_return_type;
3147 if (node->data.return_expr.expr) {
3148 actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
3149 } else {
3150 actual_return_type = g->builtin_types.entry_void;
3151 }
3152
3153 if (actual_return_type->id == TypeTableEntryIdUnreachable) {
3154 // "return exit(0)" should just be "exit(0)".
3155 add_node_error(g, node, buf_sprintf("returning is unreachable"));
3156 actual_return_type = g->builtin_types.entry_invalid;
3157 }
3158
3159 resolve_type_compatibility(g, context, node, expected_return_type, actual_return_type);
3160 } else {
3161 add_node_error(g, node, buf_sprintf("return expression outside function definition"));
3162 }
3163 return_type = g->builtin_types.entry_unreachable;
3164 break;
3165 }
3266 return_type = analyze_return_expr(g, import, context, expected_type, node);
3267 break;
31663268 case NodeTypeVariableDeclaration:
31673269 analyze_variable_declaration(g, import, context, expected_type, node);
31683270 return_type = g->builtin_types.entry_void;
......@@ -3236,6 +3338,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
32363338 case NodeTypeNumberLiteral:
32373339 return_type = analyze_number_literal_expr(g, import, context, expected_type, node);
32383340 break;
3341 case NodeTypeErrorLiteral:
3342 return_type = analyze_error_literal_expr(g, import, context, expected_type, node);
3343 break;
32393344 case NodeTypeStringLiteral:
32403345 if (node->data.string_literal.c) {
32413346 return_type = g->builtin_types.entry_c_string_literal;
......@@ -3294,6 +3399,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
32943399 case NodeTypeStructDecl:
32953400 case NodeTypeStructField:
32963401 case NodeTypeStructValueField:
3402 case NodeTypeErrorValueDecl:
32973403 zig_unreachable();
32983404 }
32993405 assert(return_type);
......@@ -3411,6 +3517,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
34113517 case NodeTypeExternBlock:
34123518 case NodeTypeUse:
34133519 case NodeTypeVariableDeclaration:
3520 case NodeTypeErrorValueDecl:
34143521 // already took care of these
34153522 break;
34163523 case NodeTypeDirective:
......@@ -3425,6 +3532,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
34253532 case NodeTypeArrayAccessExpr:
34263533 case NodeTypeSliceExpr:
34273534 case NodeTypeNumberLiteral:
3535 case NodeTypeErrorLiteral:
34283536 case NodeTypeStringLiteral:
34293537 case NodeTypeCharLiteral:
34303538 case NodeTypeBoolLiteral:
......@@ -3457,6 +3565,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
34573565{
34583566 switch (node->type) {
34593567 case NodeTypeNumberLiteral:
3568 case NodeTypeErrorLiteral:
34603569 case NodeTypeStringLiteral:
34613570 case NodeTypeCharLiteral:
34623571 case NodeTypeBoolLiteral:
......@@ -3464,6 +3573,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
34643573 case NodeTypeGoto:
34653574 case NodeTypeBreak:
34663575 case NodeTypeContinue:
3576 case NodeTypeErrorValueDecl:
34673577 // no dependencies on other top level declarations
34683578 break;
34693579 case NodeTypeSymbol:
......@@ -3758,6 +3868,10 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
37583868 case NodeTypeUse:
37593869 // already taken care of
37603870 break;
3871 case NodeTypeErrorValueDecl:
3872 // error value declarations do not depend on other top level decls
3873 resolve_top_level_decl(g, import, node);
3874 break;
37613875 case NodeTypeDirective:
37623876 case NodeTypeParamDecl:
37633877 case NodeTypeFnDecl:
......@@ -3769,6 +3883,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
37693883 case NodeTypeArrayAccessExpr:
37703884 case NodeTypeSliceExpr:
37713885 case NodeTypeNumberLiteral:
3886 case NodeTypeErrorLiteral:
37723887 case NodeTypeStringLiteral:
37733888 case NodeTypeCharLiteral:
37743889 case NodeTypeBoolLiteral:
......@@ -3966,6 +4081,8 @@ Expr *get_resolved_expr(AstNode *node) {
39664081 return &node->data.container_init_expr.resolved_expr;
39674082 case NodeTypeNumberLiteral:
39684083 return &node->data.number_literal.resolved_expr;
4084 case NodeTypeErrorLiteral:
4085 return &node->data.error_literal.resolved_expr;
39694086 case NodeTypeStringLiteral:
39704087 return &node->data.string_literal.resolved_expr;
39714088 case NodeTypeBlock:
......@@ -4006,6 +4123,7 @@ Expr *get_resolved_expr(AstNode *node) {
40064123 case NodeTypeStructDecl:
40074124 case NodeTypeStructField:
40084125 case NodeTypeStructValueField:
4126 case NodeTypeErrorValueDecl:
40094127 zig_unreachable();
40104128 }
40114129 zig_unreachable();
......@@ -4015,6 +4133,8 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
40154133 switch (node->type) {
40164134 case NodeTypeNumberLiteral:
40174135 return &node->data.number_literal.codegen;
4136 case NodeTypeErrorLiteral:
4137 return &node->data.error_literal.codegen;
40184138 case NodeTypeFnCallExpr:
40194139 return &node->data.fn_call_expr.resolved_num_lit;
40204140 case NodeTypeReturnExpr:
......@@ -4056,6 +4176,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
40564176 case NodeTypeStructField:
40574177 case NodeTypeStructValueField:
40584178 case NodeTypeArrayType:
4179 case NodeTypeErrorValueDecl:
40594180 zig_unreachable();
40604181 }
40614182 zig_unreachable();
......@@ -4069,7 +4190,10 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
40694190 return &node->data.fn_proto.top_level_decl;
40704191 case NodeTypeStructDecl:
40714192 return &node->data.struct_decl.top_level_decl;
4193 case NodeTypeErrorValueDecl:
4194 return &node->data.error_value_decl.top_level_decl;
40724195 case NodeTypeNumberLiteral:
4196 case NodeTypeErrorLiteral:
40734197 case NodeTypeReturnExpr:
40744198 case NodeTypeBinOpExpr:
40754199 case NodeTypePrefixOpExpr:
src/codegen.cpp+13
......@@ -829,6 +829,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
829829 {
830830 zig_panic("TODO codegen PrefixOpMaybe");
831831 }
832 case PrefixOpError:
833 {
834 zig_panic("TODO codegen PrefixOpError");
835 }
832836 }
833837 zig_unreachable();
834838}
......@@ -1937,6 +1941,12 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
19371941 return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
19381942}
19391943
1944static LLVMValueRef gen_error_literal(CodeGen *g, AstNode *node) {
1945 assert(node->type == NodeTypeErrorLiteral);
1946
1947 zig_panic("TODO gen_error_literal");
1948}
1949
19401950static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
19411951 assert(node->type == NodeTypeSymbol);
19421952 VariableTableEntry *variable = node->data.symbol_expr.variable;
......@@ -2070,6 +2080,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
20702080 return gen_asm_expr(g, node);
20712081 case NodeTypeNumberLiteral:
20722082 return gen_number_literal(g, node);
2083 case NodeTypeErrorLiteral:
2084 return gen_error_literal(g, node);
20732085 case NodeTypeStringLiteral:
20742086 {
20752087 Buf *str = &node->data.string_literal.buf;
......@@ -2125,6 +2137,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
21252137 case NodeTypeArrayType:
21262138 case NodeTypeSwitchProng:
21272139 case NodeTypeSwitchRange:
2140 case NodeTypeErrorValueDecl:
21282141 zig_unreachable();
21292142 }
21302143 zig_unreachable();
src/parser.cpp+154-21
......@@ -63,6 +63,16 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
6363 case PrefixOpConstAddressOf: return "&const";
6464 case PrefixOpDereference: return "*";
6565 case PrefixOpMaybe: return "?";
66 case PrefixOpError: return "%";
67 }
68 zig_unreachable();
69}
70
71static const char *return_prefix_str(ReturnKind kind) {
72 switch (kind) {
73 case ReturnKindError: return "%";
74 case ReturnKindMaybe: return "?";
75 case ReturnKindUnconditional: return "";
6676 }
6777 zig_unreachable();
6878}
......@@ -99,8 +109,12 @@ const char *node_type_str(NodeType node_type) {
99109 return "ReturnExpr";
100110 case NodeTypeVariableDeclaration:
101111 return "VariableDeclaration";
112 case NodeTypeErrorValueDecl:
113 return "ErrorValueDecl";
102114 case NodeTypeNumberLiteral:
103115 return "NumberLiteral";
116 case NodeTypeErrorLiteral:
117 return "ErrorLiteral";
104118 case NodeTypeStringLiteral:
105119 return "StringLiteral";
106120 case NodeTypeCharLiteral:
......@@ -214,10 +228,13 @@ void ast_print(AstNode *node, int indent) {
214228 break;
215229 }
216230 case NodeTypeReturnExpr:
217 fprintf(stderr, "%s\n", node_type_str(node->type));
218 if (node->data.return_expr.expr)
219 ast_print(node->data.return_expr.expr, indent + 2);
220 break;
231 {
232 const char *prefix_str = return_prefix_str(node->data.return_expr.kind);
233 fprintf(stderr, "%s%s\n", prefix_str, node_type_str(node->type));
234 if (node->data.return_expr.expr)
235 ast_print(node->data.return_expr.expr, indent + 2);
236 break;
237 }
221238 case NodeTypeVariableDeclaration:
222239 {
223240 Buf *name_buf = &node->data.variable_declaration.symbol;
......@@ -228,6 +245,12 @@ void ast_print(AstNode *node, int indent) {
228245 ast_print(node->data.variable_declaration.expr, indent + 2);
229246 break;
230247 }
248 case NodeTypeErrorValueDecl:
249 {
250 Buf *name_buf = &node->data.error_value_decl.name;
251 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
252 break;
253 }
231254 case NodeTypeExternBlock:
232255 {
233256 fprintf(stderr, "%s\n", node_type_str(node->type));
......@@ -288,6 +311,11 @@ void ast_print(AstNode *node, int indent) {
288311 }
289312 break;
290313 }
314 case NodeTypeErrorLiteral:
315 {
316 fprintf(stderr, "%s '%s'", node_type_str(node->type), buf_ptr(&node->data.error_literal.symbol));
317 break;
318 }
291319 case NodeTypeStringLiteral:
292320 {
293321 const char *c = node->data.string_literal.c ? "c" : "";
......@@ -1345,7 +1373,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
13451373}
13461374
13471375/*
1348PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression
1376PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol")
13491377KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue)
13501378*/
13511379static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
......@@ -1415,6 +1443,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
14151443
14161444 ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);
14171445 return node;
1446 } else if (token->id == TokenIdPercentDot) {
1447 *token_index += 1;
1448 Token *symbol_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
1449 AstNode *node = ast_create_node(pc, NodeTypeErrorLiteral, token);
1450 ast_buf_from_token(pc, symbol_tok, &node->data.error_literal.symbol);
1451 return node;
14181452 }
14191453
14201454 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
......@@ -1612,6 +1646,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
16121646 case TokenIdAmpersand: return PrefixOpAddressOf;
16131647 case TokenIdStar: return PrefixOpDereference;
16141648 case TokenIdMaybe: return PrefixOpMaybe;
1649 case TokenIdPercent: return PrefixOpError;
16151650 case TokenIdBoolAnd: return PrefixOpAddressOf;
16161651 default: return PrefixOpInvalid;
16171652 }
......@@ -2031,20 +2066,46 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
20312066}
20322067
20332068/*
2034ReturnExpression : token(Return) option(Expression)
2069ReturnExpression : option("%" | "?") "return" option(Expression)
20352070*/
20362071static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool mandatory) {
2037 Token *return_tok = &pc->tokens->at(*token_index);
2038 if (return_tok->id == TokenIdKeywordReturn) {
2072 Token *token = &pc->tokens->at(*token_index);
2073
2074 ReturnKind kind;
2075
2076 if (token->id == TokenIdPercent) {
2077 Token *next_token = &pc->tokens->at(*token_index + 1);
2078 if (next_token->id == TokenIdKeywordReturn) {
2079 kind = ReturnKindError;
2080 *token_index += 2;
2081 } else if (mandatory) {
2082 ast_invalid_token_error(pc, token);
2083 } else {
2084 return nullptr;
2085 }
2086 } else if (token->id == TokenIdMaybe) {
2087 Token *next_token = &pc->tokens->at(*token_index + 1);
2088 if (next_token->id == TokenIdKeywordReturn) {
2089 kind = ReturnKindMaybe;
2090 *token_index += 2;
2091 } else if (mandatory) {
2092 ast_invalid_token_error(pc, token);
2093 } else {
2094 return nullptr;
2095 }
2096 } else if (token->id == TokenIdKeywordReturn) {
2097 kind = ReturnKindUnconditional;
20392098 *token_index += 1;
2040 AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, return_tok);
2041 node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
2042 return node;
20432099 } else if (mandatory) {
2044 ast_invalid_token_error(pc, return_tok);
2100 ast_invalid_token_error(pc, token);
20452101 } else {
20462102 return nullptr;
20472103 }
2104
2105 AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, token);
2106 node->data.return_expr.kind = kind;
2107 node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
2108 return node;
20482109}
20492110
20502111/*
......@@ -2054,27 +2115,46 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
20542115 Token *first_token = &pc->tokens->at(*token_index);
20552116
20562117 VisibMod visib_mod;
2118 bool is_const;
20572119
20582120 if (first_token->id == TokenIdKeywordPub) {
2059 *token_index += 1;
2060 visib_mod = VisibModPub;
2121 Token *next_token = &pc->tokens->at(*token_index + 1);
2122 if (next_token->id == TokenIdKeywordVar ||
2123 next_token->id == TokenIdKeywordConst)
2124 {
2125 visib_mod = VisibModPub;
2126 is_const = (next_token->id == TokenIdKeywordConst);
2127 *token_index += 2;
2128 } else if (mandatory) {
2129 ast_invalid_token_error(pc, next_token);
2130 } else {
2131 return nullptr;
2132 }
20612133 } else if (first_token->id == TokenIdKeywordExport) {
2062 *token_index += 1;
2063 visib_mod = VisibModExport;
2134 Token *next_token = &pc->tokens->at(*token_index + 1);
2135 if (next_token->id == TokenIdKeywordVar ||
2136 next_token->id == TokenIdKeywordConst)
2137 {
2138 visib_mod = VisibModExport;
2139 is_const = (next_token->id == TokenIdKeywordConst);
2140 *token_index += 2;
2141 } else if (mandatory) {
2142 ast_invalid_token_error(pc, next_token);
2143 } else {
2144 return nullptr;
2145 }
20642146 } else if (first_token->id == TokenIdKeywordVar ||
20652147 first_token->id == TokenIdKeywordConst)
20662148 {
20672149 visib_mod = VisibModPrivate;
2150 is_const = (first_token->id == TokenIdKeywordConst);
2151 *token_index += 1;
20682152 } else if (mandatory) {
20692153 ast_invalid_token_error(pc, first_token);
20702154 } else {
20712155 return nullptr;
20722156 }
20732157
2074 Token *var_or_const_tok = &pc->tokens->at(*token_index);
2075 bool is_const = (var_or_const_tok->id == TokenIdKeywordConst);
2076 *token_index += 1;
2077
20782158 AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, first_token);
20792159
20802160 node->data.variable_declaration.is_const = is_const;
......@@ -2836,7 +2916,54 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
28362916}
28372917
28382918/*
2839TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration | EnumDecl
2919ErrorValueDecl : option(FnVisibleMod) "%." "Symbol"
2920*/
2921static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, bool mandatory) {
2922 Token *first_token = &pc->tokens->at(*token_index);
2923
2924 VisibMod visib_mod;
2925
2926 if (first_token->id == TokenIdKeywordPub) {
2927 Token *next_token = &pc->tokens->at(*token_index + 1);
2928 if (next_token->id == TokenIdPercentDot) {
2929 visib_mod = VisibModPub;
2930 *token_index += 2;
2931 } else if (mandatory) {
2932 ast_invalid_token_error(pc, next_token);
2933 } else {
2934 return nullptr;
2935 }
2936 } else if (first_token->id == TokenIdKeywordExport) {
2937 Token *next_token = &pc->tokens->at(*token_index + 1);
2938 if (next_token->id == TokenIdPercentDot) {
2939 visib_mod = VisibModExport;
2940 *token_index += 2;
2941 } else if (mandatory) {
2942 ast_invalid_token_error(pc, next_token);
2943 } else {
2944 return nullptr;
2945 }
2946 } else if (first_token->id == TokenIdPercentDot) {
2947 visib_mod = VisibModPrivate;
2948 *token_index += 1;
2949 } else if (mandatory) {
2950 ast_invalid_token_error(pc, first_token);
2951 } else {
2952 return nullptr;
2953 }
2954
2955 Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
2956 ast_eat_token(pc, token_index, TokenIdSemicolon);
2957
2958 AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
2959 node->data.error_value_decl.visib_mod = visib_mod;
2960 ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name);
2961
2962 return node;
2963}
2964
2965/*
2966TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
28402967*/
28412968static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
28422969 for (;;) {
......@@ -2887,6 +3014,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
28873014 continue;
28883015 }
28893016
3017 AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index, false);
3018 if (error_value_node) {
3019 top_level_decls->append(error_value_node);
3020 continue;
3021 }
3022
28903023 return;
28913024 }
28923025 zig_unreachable();
src/tokenizer.cpp+6
......@@ -584,6 +584,11 @@ void tokenize(Buf *buf, Tokenization *out) {
584584 end_token(&t);
585585 t.state = TokenizeStateStart;
586586 break;
587 case '.':
588 t.cur_tok->id = TokenIdPercentDot;
589 end_token(&t);
590 t.state = TokenizeStateStart;
591 break;
587592 default:
588593 t.pos -= 1;
589594 end_token(&t);
......@@ -1092,6 +1097,7 @@ const char * token_name(TokenId id) {
10921097 case TokenIdDoubleQuestion: return "??";
10931098 case TokenIdMaybeAssign: return "?=";
10941099 case TokenIdAtSign: return "@";
1100 case TokenIdPercentDot: return "%.";
10951101 }
10961102 return "(invalid token)";
10971103}
src/tokenizer.hpp+1
......@@ -91,6 +91,7 @@ enum TokenId {
9191 TokenIdDoubleQuestion,
9292 TokenIdMaybeAssign,
9393 TokenIdAtSign,
94 TokenIdPercentDot,
9495};
9596
9697struct Token {
std/std.zig+150-16
......@@ -1,43 +1,177 @@
11import "syscall.zig";
2//import "errno.zig";
23
34pub const stdin_fileno : isize = 0;
45pub const stdout_fileno : isize = 1;
56pub const stderr_fileno : isize = 2;
67
7// TODO error handling
8pub fn os_get_random_bytes(buf: []u8) isize => {
9 getrandom(buf.ptr, buf.len, 0)
8/*
9pub var stdin = InStream {
10 .fd = stdin_fileno,
11};
12
13pub var stdout = OutStream {
14 .fd = stdout_fileno,
15 .buffer = uninitialized,
16 .index = 0,
17 .buffered = true,
18};
19
20pub var stderr = OutStream {
21 .fd = stderr_fileno,
22 .buffer = uninitialized,
23 .index = 0,
24 .buffered = false,
25};
26
27pub %.Unexpected;
28pub %.DiskQuota;
29pub %.FileTooBig;
30pub %.SigInterrupt;
31pub %.Io;
32pub %.NoSpaceLeft;
33pub %.BadPerm;
34pub %.PipeFail;
35*/
36
37const buffer_size: u16 = 4 * 1024;
38const max_u64_base10_digits: isize = 20;
39
40/*
41pub struct OutStream {
42 fd: isize,
43 buffer: [buffer_size]u8,
44 index: @typeof(buffer_size),
45 buffered: bool,
46
47 pub fn print_str(os: &OutStream, str: []const u8) %isize => {
48 var src_bytes_left = str.len;
49 var src_index: @typeof(str.len) = 0;
50 const dest_space_left = os.buffer.len - index;
51
52 while (src_bytes_left > 0) {
53 const copy_amt = min_isize(dest_space_left, src_bytes_left);
54 @memcpy(&buffer[os.index], &str[src_index], copy_amt);
55 os.index += copy_amt;
56 if (os.index == os.buffer.len) {
57 %return os.flush();
58 }
59 src_bytes_left -= copy_amt;
60 }
61 if (!os.buffered) {
62 %return os.flush();
63 }
64 return str.len;
65 }
66
67 pub fn print_u64(os: &OutStream, x: u64) %isize => {
68 if (os.index + max_u64_base10_digits >= os.buffer.len) {
69 %return os.flush();
70 }
71 const amt_printed = buf_print_u64(buf[os.index...], x);
72 os.index += amt_printed;
73
74 if (!os.buffered) {
75 %return os.flush();
76 }
77
78 return amt_printed;
79 }
80
81
82 pub fn print_i64(os: &OutStream, x: i64) %isize => {
83 if (os.index + max_u64_base10_digits >= os.buffer.len) {
84 %return os.flush();
85 }
86 const amt_printed = buf_print_i64(buf[os.index...], x);
87 os.index += amt_printed;
88
89 if (!os.buffered) {
90 %return os.flush();
91 }
92
93 return amt_printed;
94 }
95
96
97 pub fn flush(os: &OutStream) %void => {
98 const amt_to_write = os.index;
99 os.index = 0;
100 switch (write(fd, os.buffer.ptr, amt_to_write)) {
101 EINVAL => unreachable{},
102 EDQUOT => %.DiskQuota,
103 EFBIG => %.FileTooBig,
104 EINTR => %.SigInterrupt,
105 EIO => %.Io,
106 ENOSPC => %.NoSpaceLeft,
107 EPERM => %.BadPerm,
108 EPIPE => %.PipeFail,
109 else => %.Unexpected,
110 }
111 }
112}
113
114pub struct InStream {
115 fd: isize,
116
117 pub fn readline(buf: []u8) %isize => {
118 const amt_read = read(stdin_fileno, buf.ptr, buf.len);
119 if (amt_read < 0) {
120 switch (-amt_read) {
121 EINVAL => unreachable{},
122 EFAULT => unreachable{},
123 EBADF => %.BadFd,
124 EINTR => %.SigInterrupt,
125 EIO => %.Io,
126 else => %.Unexpected,
127 }
128 }
129 return amt_read;
130 }
131
132}
133
134pub fn os_get_random_bytes(buf: []u8) %void => {
135 switch (getrandom(buf.ptr, buf.len, 0)) {
136 EINVAL => unreachable{},
137 EFAULT => unreachable{},
138 EINTR => %.SigInterrupt,
139 else => %.Unexpected,
140 }
10141}
142*/
143
11144
12// TODO error handling
13// TODO handle buffering and flushing (mutex protected)
145// TODO remove this
14146pub fn print_str(str: []const u8) isize => {
15147 fprint_str(stdout_fileno, str)
16148}
17149
18// TODO error handling
19// TODO handle buffering and flushing (mutex protected)
150// TODO remove this
20151pub fn fprint_str(fd: isize, str: []const u8) isize => {
21152 write(fd, str.ptr, str.len)
22153}
23154
24// TODO handle buffering and flushing (mutex protected)
25// TODO error handling
155// TODO remove this
156pub fn os_get_random_bytes(buf: []u8) isize => {
157 getrandom(buf.ptr, buf.len, 0)
158}
159
160// TODO remove this
26161pub fn print_u64(x: u64) isize => {
27162 var buf: [max_u64_base10_digits]u8;
28163 const len = buf_print_u64(buf, x);
29164 return write(stdout_fileno, buf.ptr, len);
30165}
31166
32// TODO handle buffering and flushing (mutex protected)
33// TODO error handling
167// TODO remove this
34168pub fn print_i64(x: i64) isize => {
35169 var buf: [max_u64_base10_digits]u8;
36170 const len = buf_print_i64(buf, x);
37171 return write(stdout_fileno, buf.ptr, len);
38172}
39173
40// TODO error handling
174// TODO remove this
41175pub fn readline(buf: []u8, out_len: &isize) bool => {
42176 const amt_read = read(stdin_fileno, buf.ptr, buf.len);
43177 if (amt_read < 0) {
......@@ -47,7 +181,8 @@ pub fn readline(buf: []u8, out_len: &isize) bool => {
47181 return false;
48182}
49183
50// TODO return ?u64 when we support returning struct byval
184
185// TODO return %u64 when we support errors
51186pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
52187 var x : u64 = 0;
53188
......@@ -74,6 +209,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
74209}
75210
76211fn char_to_digit(c: u8) u8 => {
212 // TODO use switch with range
77213 if ('0' <= c && c <= '9') {
78214 c - '0'
79215 } else if ('A' <= c && c <= 'Z') {
......@@ -85,8 +221,6 @@ fn char_to_digit(c: u8) u8 => {
85221 }
86222}
87223
88const max_u64_base10_digits: isize = 20;
89
90224fn buf_print_i64(out_buf: []u8, x: i64) isize => {
91225 if (x < 0) {
92226 out_buf[0] = '-';
......@@ -112,7 +246,7 @@ fn buf_print_u64(out_buf: []u8, x: u64) isize => {
112246
113247 const len = buf.len - index;
114248
115 @memcpy(out_buf.ptr, &buf[index], len);
249 @memcpy(&out_buf[0], &buf[index], len);
116250
117251 return len;
118252}