authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-24 01:58:20-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-24 02:02:48-05:00
log4b3f18de3c5746b2ecfd6183351913de0909a83b
treee3d0d56fcd8c00d994a13c4d69d60f0ab28fe389
parent32d8686da80d282e8cd6d84a0e5c331d269a1f69

printf var args proof of concept

See #167 Need to troubleshoot when we send 2 slices to printf. It goes into an infinite loop. This commit introduces 4 builtin functions: * `@isInteger` * `@isFloat` * `@canImplictCast` * `@typeName`

9 files changed, 412 insertions(+), 38 deletions(-)

doc/langref.md+37-22
......@@ -370,10 +370,10 @@ TODO
370370
371371## Built-in Functions
372372
373Built-in functions are prefixed with `@`. Remember that the `inline` keyword on
373Built-in functions are prefixed with `@`. Remember that the `comptime` keyword on
374374a parameter means that the parameter must be known at compile time.
375375
376### @alloca(inline T: type, count: usize) -> []T
376### @alloca(comptime T: type, count: usize) -> []T
377377
378378Allocates memory in the stack frame of the caller. This temporary space is
379379automatically freed when the function that called alloca returns to its caller,
......@@ -391,13 +391,13 @@ The allocated memory contents are undefined.
391391This function returns a compile-time constant, which is the type of the
392392expression passed as an argument. The expression is *not evaluated*.
393393
394### @sizeOf(inline T: type) -> (number literal)
394### @sizeOf(comptime T: type) -> (number literal)
395395
396396This function returns the number of bytes it takes to store T in memory.
397397
398398The result is a target-specific compile time constant.
399399
400### @alignOf(inline T: type) -> (number literal)
400### @alignOf(comptime T: type) -> (number literal)
401401
402402This function returns the number of bytes that this type should be aligned to
403403for the current target.
......@@ -414,10 +414,10 @@ false otherwise.
414414
415415```
416416Function Operation
417@addWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a + b
418@subWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a - b
419@mulWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a * b
420@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b
417@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool *x = a + b
418@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool *x = a - b
419@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool *x = a * b
420@shlWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool *x = a << b
421421```
422422
423423### @memset(dest: &u8, c: u8, byte_count: usize)
......@@ -475,27 +475,27 @@ aggressive optimizations.
475475
476476This function is only valid within function scope.
477477
478### @maxValue(inline T: type) -> (number literal)
478### @maxValue(comptime T: type) -> (number literal)
479479
480480This function returns the maximum integer value of the integer type T.
481481
482482The result is a compile time constant. For some types such as `c_long`, the
483483result is marked as depending on a compile variable.
484484
485### @minValue(inline T: type) -> (number literal)
485### @minValue(comptime T: type) -> (number literal)
486486
487487This function returns the minimum integer value of the integer type T.
488488
489489The result is a compile time constant. For some types such as `c_long`, the
490490result is marked as depending on a compile variable.
491491
492### @memberCount(inline T: type) -> (number literal)
492### @memberCount(comptime T: type) -> (number literal)
493493
494494This function returns the number of enum values in an enum type.
495495
496496The result is a compile time constant.
497497
498### @import(inline path: []u8) -> (namespace)
498### @import(comptime path: []u8) -> (namespace)
499499
500500This function finds a zig file corresponding to `path` and imports all the
501501public top level declarations into the resulting namespace.
......@@ -516,25 +516,25 @@ appending to a temporary buffer which is then parsed as C code.
516516
517517This function is only valid at top level scope.
518518
519### @cInclude(inline path: []u8)
519### @cInclude(comptime path: []u8)
520520
521521This function can only occur inside `@c_import`.
522522
523523This appends `#include <$path>\n` to the `c_import` temporary buffer.
524524
525### @cDefine(inline name: []u8, value)
525### @cDefine(comptime name: []u8, value)
526526
527527This function can only occur inside `@c_import`.
528528
529529This appends `#define $name $value` to the `c_import` temporary buffer.
530530
531### @cUndef(inline name: []u8)
531### @cUndef(comptime name: []u8)
532532
533533This function can only occur inside `@c_import`.
534534
535535This appends `#undef $name` to the `c_import` temporary buffer.
536536
537### @compileVar(inline name: []u8) -> (varying type)
537### @compileVar(comptime name: []u8) -> (varying type)
538538
539539This function returns a compile-time variable. There are built in compile
540540variables:
......@@ -584,10 +584,14 @@ error OutOfMem;
584584
585585Then the string representation is "OutOfMem".
586586
587If there are no calls to `@err_name` in an entire application, then no error
587If there are no calls to `@errorName` in an entire application, then no error
588588name table will be generated.
589589
590### @embedFile(inline path: []u8) -> [X]u8
590### @typeName(T: type) -> []u8
591
592This function returns the string representation of a type.
593
594### @embedFile(comptime path: []u8) -> [X]u8
591595
592596This function returns a compile time constant fixed-size array with length
593597equal to the byte count of the file given by `path`. The contents of the array
......@@ -610,7 +614,7 @@ The caller guarantees that this operation will have no remainder.
610614In debug mode, a remainder causes a panic. In release mode, a remainder is
611615undefined behavior.
612616
613### @truncate(inline T: type, integer) -> T
617### @truncate(comptime T: type, integer) -> T
614618
615619This function truncates bits from an integer type, resulting in a smaller
616620integer type.
......@@ -631,14 +635,14 @@ const b: u8 = @truncate(u8, a);
631635// b is now 0xcd
632636```
633637
634### @compileError(inline msg: []u8)
638### @compileError(comptime msg: []u8)
635639
636640This function, when semantically analyzed, causes a compile error with the message `msg`.
637641
638642There are several ways that code avoids being semantically checked, such as using `if`
639or `switch` with compile time constants, and inline functions.
643or `switch` with compile time constants, and comptime functions.
640644
641### @intType(inline is_signed: bool, inline bit_count: u8) -> type
645### @intType(comptime is_signed: bool, comptime bit_count: u8) -> type
642646
643647This function returns an integer type with the given signness and bit count.
644648
......@@ -646,3 +650,14 @@ This function returns an integer type with the given signness and bit count.
646650
647651Makes the target function a test function.
648652
653### @isInteger(comptime T: type) -> bool
654
655Returns whether a given type is an integer.
656
657### @isFloat(comptime T: type) -> bool
658
659Returns whether a given type is a float.
660
661### @canImplicitCast(comptime T: type, value) -> bool
662
663Returns whether a value can be implicitly casted to a given type.
example/cat/main.zig-2
......@@ -2,8 +2,6 @@ const std = @import("std");
22const io = std.io;
33const str = std.str;
44
5// TODO var args printing
6
75pub fn main(args: [][]u8) -> %void {
86 const exe = args[0];
97 var catted_anything = false;
src/all_types.hpp+30
......@@ -978,6 +978,9 @@ struct TypeTableEntry {
978978 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
979979 TypeTableEntry *maybe_parent;
980980 TypeTableEntry *error_parent;
981 // If we generate a constant name value for this type, we memoize it here.
982 // The type of this is array
983 ConstExprValue *cached_const_name_val;
981984};
982985
983986struct PackageTableEntry {
......@@ -1086,6 +1089,10 @@ enum BuiltinFnId {
10861089 BuiltinFnIdSetFnVisible,
10871090 BuiltinFnIdSetDebugSafety,
10881091 BuiltinFnIdAlloca,
1092 BuiltinFnIdTypeName,
1093 BuiltinFnIdIsInteger,
1094 BuiltinFnIdIsFloat,
1095 BuiltinFnIdCanImplicitCast,
10891096};
10901097
10911098struct BuiltinFnEntry {
......@@ -1505,6 +1512,9 @@ enum IrInstructionId {
15051512 IrInstructionIdPtrToInt,
15061513 IrInstructionIdIntToEnum,
15071514 IrInstructionIdCheckSwitchProngs,
1515 IrInstructionIdTestType,
1516 IrInstructionIdTypeName,
1517 IrInstructionIdCanImplicitCast,
15081518};
15091519
15101520struct IrInstruction {
......@@ -2188,6 +2198,26 @@ struct IrInstructionCheckSwitchProngs {
21882198 size_t range_count;
21892199};
21902200
2201struct IrInstructionTestType {
2202 IrInstruction base;
2203
2204 IrInstruction *type_value;
2205 TypeTableEntryId type_id;
2206};
2207
2208struct IrInstructionTypeName {
2209 IrInstruction base;
2210
2211 IrInstruction *type_value;
2212};
2213
2214struct IrInstructionCanImplicitCast {
2215 IrInstruction base;
2216
2217 IrInstruction *type_value;
2218 IrInstruction *target_value;
2219};
2220
21912221enum LValPurpose {
21922222 LValPurposeNone,
21932223 LValPurposeAssign,
src/codegen.cpp+7
......@@ -2279,6 +2279,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
22792279 case IrInstructionIdTestComptime:
22802280 case IrInstructionIdGeneratedCode:
22812281 case IrInstructionIdCheckSwitchProngs:
2282 case IrInstructionIdTestType:
2283 case IrInstructionIdTypeName:
2284 case IrInstructionIdCanImplicitCast:
22822285 zig_unreachable();
22832286 case IrInstructionIdReturn:
22842287 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
......@@ -3652,6 +3655,10 @@ static void define_builtin_fns(CodeGen *g) {
36523655 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);
36533656 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
36543657 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
3658 create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
3659 create_builtin_fn(g, BuiltinFnIdIsInteger, "isInteger", 1);
3660 create_builtin_fn(g, BuiltinFnIdIsFloat, "isFloat", 1);
3661 create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
36553662 create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
36563663 create_builtin_fn(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);
36573664 create_builtin_fn(g, BuiltinFnIdFence, "fence", 1);
src/ir.cpp+186-1
......@@ -495,6 +495,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckSwitchProng
495495 return IrInstructionIdCheckSwitchProngs;
496496}
497497
498static constexpr IrInstructionId ir_instruction_id(IrInstructionTestType *) {
499 return IrInstructionIdTestType;
500}
501
502static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeName *) {
503 return IrInstructionIdTypeName;
504}
505
506static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast *) {
507 return IrInstructionIdCanImplicitCast;
508}
509
498510template<typename T>
499511static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
500512 T *special_instruction = allocate<T>(1);
......@@ -2001,6 +2013,45 @@ static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope,
20012013 return &instruction->base;
20022014}
20032015
2016static IrInstruction *ir_build_test_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
2017 IrInstruction *type_value, TypeTableEntryId type_id)
2018{
2019 IrInstructionTestType *instruction = ir_build_instruction<IrInstructionTestType>(
2020 irb, scope, source_node);
2021 instruction->type_value = type_value;
2022 instruction->type_id = type_id;
2023
2024 ir_ref_instruction(type_value, irb->current_basic_block);
2025
2026 return &instruction->base;
2027}
2028
2029static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
2030 IrInstruction *type_value)
2031{
2032 IrInstructionTypeName *instruction = ir_build_instruction<IrInstructionTypeName>(
2033 irb, scope, source_node);
2034 instruction->type_value = type_value;
2035
2036 ir_ref_instruction(type_value, irb->current_basic_block);
2037
2038 return &instruction->base;
2039}
2040
2041static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
2042 IrInstruction *type_value, IrInstruction *target_value)
2043{
2044 IrInstructionCanImplicitCast *instruction = ir_build_instruction<IrInstructionCanImplicitCast>(
2045 irb, scope, source_node);
2046 instruction->type_value = type_value;
2047 instruction->target_value = target_value;
2048
2049 ir_ref_instruction(type_value, irb->current_basic_block);
2050 ir_ref_instruction(target_value, irb->current_basic_block);
2051
2052 return &instruction->base;
2053}
2054
20042055static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
20052056 return nullptr;
20062057}
......@@ -2605,6 +2656,28 @@ static IrInstruction *ir_instruction_checkswitchprongs_get_dep(IrInstructionChec
26052656 return nullptr;
26062657}
26072658
2659static IrInstruction *ir_instruction_testtype_get_dep(IrInstructionTestType *instruction, size_t index) {
2660 switch (index) {
2661 case 0: return instruction->type_value;
2662 default: return nullptr;
2663 }
2664}
2665
2666static IrInstruction *ir_instruction_typename_get_dep(IrInstructionTypeName *instruction, size_t index) {
2667 switch (index) {
2668 case 0: return instruction->type_value;
2669 default: return nullptr;
2670 }
2671}
2672
2673static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImplicitCast *instruction, size_t index) {
2674 switch (index) {
2675 case 0: return instruction->type_value;
2676 case 1: return instruction->target_value;
2677 default: return nullptr;
2678 }
2679}
2680
26082681static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
26092682 switch (instruction->id) {
26102683 case IrInstructionIdInvalid:
......@@ -2777,6 +2850,12 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
27772850 return ir_instruction_inttoenum_get_dep((IrInstructionIntToEnum *) instruction, index);
27782851 case IrInstructionIdCheckSwitchProngs:
27792852 return ir_instruction_checkswitchprongs_get_dep((IrInstructionCheckSwitchProngs *) instruction, index);
2853 case IrInstructionIdTestType:
2854 return ir_instruction_testtype_get_dep((IrInstructionTestType *) instruction, index);
2855 case IrInstructionIdTypeName:
2856 return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index);
2857 case IrInstructionIdCanImplicitCast:
2858 return ir_instruction_canimplicitcast_get_dep((IrInstructionCanImplicitCast *) instruction, index);
27802859 }
27812860 zig_unreachable();
27822861}
......@@ -3594,6 +3673,18 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
35943673 return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
35953674}
35963675
3676static IrInstruction *ir_gen_test_type(IrBuilder *irb, Scope *scope, AstNode *node, TypeTableEntryId type_id) {
3677 assert(node->type == NodeTypeFnCallExpr);
3678
3679 AstNode *type_node = node->data.fn_call_expr.params.at(0);
3680
3681 IrInstruction *type_value = ir_gen_node(irb, type_node, scope);
3682 if (type_value == irb->codegen->invalid_instruction)
3683 return irb->codegen->invalid_instruction;
3684
3685 return ir_build_test_type(irb, scope, node, type_value, type_id);
3686}
3687
35973688static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {
35983689 assert(node->type == NodeTypeFnCallExpr);
35993690
......@@ -3995,6 +4086,33 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39954086 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul);
39964087 case BuiltinFnIdShlWithOverflow:
39974088 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl);
4089 case BuiltinFnIdTypeName:
4090 {
4091 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4092 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4093 if (arg0_value == irb->codegen->invalid_instruction)
4094 return arg0_value;
4095
4096 return ir_build_type_name(irb, scope, node, arg0_value);
4097 }
4098 case BuiltinFnIdIsInteger:
4099 return ir_gen_test_type(irb, scope, node, TypeTableEntryIdInt);
4100 case BuiltinFnIdIsFloat:
4101 return ir_gen_test_type(irb, scope, node, TypeTableEntryIdFloat);
4102 case BuiltinFnIdCanImplicitCast:
4103 {
4104 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4105 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4106 if (arg0_value == irb->codegen->invalid_instruction)
4107 return arg0_value;
4108
4109 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4110 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4111 if (arg1_value == irb->codegen->invalid_instruction)
4112 return arg1_value;
4113
4114 return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value);
4115 }
39984116 }
39994117 zig_unreachable();
40004118}
......@@ -8942,7 +9060,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
89429060 case TypeTableEntryIdEnumTag:
89439061 case TypeTableEntryIdArgTuple:
89449062 {
8945 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false);
9063 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, true);
89469064 // TODO depends_on_compile_var should be set based on whether the type of the expression
89479065 // depends_on_compile_var. but we currently don't have a thing to tell us if the type of
89489066 // something depends on a compile var
......@@ -9622,6 +9740,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
96229740 pointee_val = nullptr;
96239741 }
96249742 TypeTableEntry *canon_target_type = get_underlying_type(target_type);
9743 ensure_complete_type(ira->codegen, target_type);
9744
96259745 switch (canon_target_type->id) {
96269746 case TypeTableEntryIdInvalid:
96279747 case TypeTableEntryIdVar:
......@@ -10260,6 +10380,24 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
1026010380 return str_type;
1026110381}
1026210382
10383static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {
10384 IrInstruction *type_value = instruction->type_value->other;
10385 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
10386 if (type_entry->id == TypeTableEntryIdInvalid)
10387 return ira->codegen->builtin_types.entry_invalid;
10388
10389 TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
10390 if (!type_entry->cached_const_name_val) {
10391 ConstExprValue *array_val = create_const_str_lit(ira->codegen, &type_entry->name);
10392 type_entry->cached_const_name_val = create_const_slice(ira->codegen,
10393 array_val, 0, buf_len(&type_entry->name), true);
10394 }
10395 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
10396 type_value->value.depends_on_compile_var);
10397 *out_val = *type_entry->cached_const_name_val;
10398 return str_type;
10399}
10400
1026310401static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
1026410402 AstNode *node = instruction->base.source_node;
1026510403 assert(node->type == NodeTypeFnCallExpr);
......@@ -11370,6 +11508,44 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
1137011508 return ira->codegen->builtin_types.entry_void;
1137111509}
1137211510
11511static TypeTableEntry *ir_analyze_instruction_test_type(IrAnalyze *ira, IrInstructionTestType *instruction) {
11512 IrInstruction *type_value = instruction->type_value->other;
11513 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
11514 if (type_entry->id == TypeTableEntryIdInvalid)
11515 return ira->codegen->builtin_types.entry_invalid;
11516
11517 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, type_value->value.depends_on_compile_var);
11518 out_val->data.x_bool = (type_entry->id == instruction->type_id);
11519 return ira->codegen->builtin_types.entry_bool;
11520}
11521
11522static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
11523 IrInstructionCanImplicitCast *instruction)
11524{
11525 IrInstruction *type_value = instruction->type_value->other;
11526 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
11527 if (type_entry->id == TypeTableEntryIdInvalid)
11528 return ira->codegen->builtin_types.entry_invalid;
11529
11530 IrInstruction *target_value = instruction->target_value->other;
11531 if (target_value->value.type->id == TypeTableEntryIdInvalid)
11532 return ira->codegen->builtin_types.entry_invalid;
11533
11534 ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, type_entry, target_value->value.type,
11535 target_value);
11536
11537 if (result == ImplicitCastMatchResultReportedError) {
11538 zig_panic("TODO refactor implicit cast tester to return bool without reporting errors");
11539 }
11540
11541 // TODO in order to known depends_on_compile_var we have to known if the type of the target
11542 // depends on a compile var
11543 bool depends_on_compile_var = true;
11544 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
11545 out_val->data.x_bool = (result == ImplicitCastMatchResultYes);
11546 return ira->codegen->builtin_types.entry_bool;
11547}
11548
1137311549static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1137411550 switch (instruction->id) {
1137511551 case IrInstructionIdInvalid:
......@@ -11471,6 +11647,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1147111647 return ir_analyze_instruction_compile_err(ira, (IrInstructionCompileErr *)instruction);
1147211648 case IrInstructionIdErrName:
1147311649 return ir_analyze_instruction_err_name(ira, (IrInstructionErrName *)instruction);
11650 case IrInstructionIdTypeName:
11651 return ir_analyze_instruction_type_name(ira, (IrInstructionTypeName *)instruction);
1147411652 case IrInstructionIdCImport:
1147511653 return ir_analyze_instruction_c_import(ira, (IrInstructionCImport *)instruction);
1147611654 case IrInstructionIdCInclude:
......@@ -11525,6 +11703,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1152511703 return ir_analyze_instruction_test_comptime(ira, (IrInstructionTestComptime *)instruction);
1152611704 case IrInstructionIdCheckSwitchProngs:
1152711705 return ir_analyze_instruction_check_switch_prongs(ira, (IrInstructionCheckSwitchProngs *)instruction);
11706 case IrInstructionIdTestType:
11707 return ir_analyze_instruction_test_type(ira, (IrInstructionTestType *)instruction);
11708 case IrInstructionIdCanImplicitCast:
11709 return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction);
1152811710 case IrInstructionIdMaybeWrap:
1152911711 case IrInstructionIdErrWrapCode:
1153011712 case IrInstructionIdErrWrapPayload:
......@@ -11691,6 +11873,9 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1169111873 case IrInstructionIdPtrToInt:
1169211874 case IrInstructionIdIntToPtr:
1169311875 case IrInstructionIdIntToEnum:
11876 case IrInstructionIdTestType:
11877 case IrInstructionIdTypeName:
11878 case IrInstructionIdCanImplicitCast:
1169411879 return false;
1169511880 case IrInstructionIdAsm:
1169611881 {
src/ir_print.cpp+29
......@@ -807,6 +807,26 @@ static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchP
807807 fprintf(irp->f, ")");
808808}
809809
810static void ir_print_test_type(IrPrint *irp, IrInstructionTestType *instruction) {
811 fprintf(irp->f, "@testType(");
812 ir_print_other_instruction(irp, instruction->type_value);
813 fprintf(irp->f, ")");
814}
815
816static void ir_print_type_name(IrPrint *irp, IrInstructionTypeName *instruction) {
817 fprintf(irp->f, "@typeName(");
818 ir_print_other_instruction(irp, instruction->type_value);
819 fprintf(irp->f, ")");
820}
821
822static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCast *instruction) {
823 fprintf(irp->f, "@canImplicitCast(");
824 ir_print_other_instruction(irp, instruction->type_value);
825 fprintf(irp->f, ",");
826 ir_print_other_instruction(irp, instruction->target_value);
827 fprintf(irp->f, ")");
828}
829
810830static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
811831 ir_print_prefix(irp, instruction);
812832 switch (instruction->id) {
......@@ -1064,6 +1084,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10641084 case IrInstructionIdCheckSwitchProngs:
10651085 ir_print_check_switch_prongs(irp, (IrInstructionCheckSwitchProngs *)instruction);
10661086 break;
1087 case IrInstructionIdTestType:
1088 ir_print_test_type(irp, (IrInstructionTestType *)instruction);
1089 break;
1090 case IrInstructionIdTypeName:
1091 ir_print_type_name(irp, (IrInstructionTypeName *)instruction);
1092 break;
1093 case IrInstructionIdCanImplicitCast:
1094 ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
1095 break;
10671096 }
10681097 fprintf(irp->f, "\n");
10691098}
std/debug.zig+1-4
......@@ -50,10 +50,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
5050 const compile_unit = findCompileUnit(st, return_address) ?? return error.MissingDebugInfo;
5151 const name = %return compile_unit.die.getAttrString(st, DW.AT_name);
5252
53 %return out_stream.printInt(usize, return_address);
54 %return out_stream.printf(" -> ");
55 %return out_stream.printf(name);
56 %return out_stream.printf("\n");
53 %return out_stream.printf("{} -> {}\n", return_address, name);
5754 maybe_fp = *(&const ?&const u8)(fp);
5855 }
5956 },
std/io.zig+73-9
......@@ -80,7 +80,7 @@ pub const OutStream = struct {
8080 self.index += 1;
8181 }
8282
83 pub fn write(self: &OutStream, bytes: []const u8) -> %usize {
83 pub fn write(self: &OutStream, bytes: []const u8) -> %void {
8484 var src_bytes_left = bytes.len;
8585 var src_index: usize = 0;
8686 const dest_space_left = self.buffer.len - self.index;
......@@ -94,25 +94,89 @@ pub const OutStream = struct {
9494 }
9595 src_bytes_left -= copy_amt;
9696 }
97 return bytes.len;
9897 }
9998
100 /// Prints a byte buffer, flushes the buffer, then returns the number of
101 /// bytes printed. The "f" is for "flush".
102 pub fn printf(self: &OutStream, str: []const u8) -> %usize {
103 const byte_count = %return self.write(str);
99 const State = enum { // TODO put inside printf function and make sure the name and debug info is correct
100 Start,
101 OpenBrace,
102 CloseBrace,
103 };
104
105 /// Calls print and then flushes the buffer.
106 pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> %void {
107 comptime var start_index: usize = 0;
108 comptime var state = State.Start;
109 comptime var next_arg: usize = 0;
110 inline for (format) |c, i| {
111 switch (state) {
112 State.Start => switch (c) {
113 '{' => {
114 if (start_index < i) %return self.write(format[start_index...i]);
115 state = State.OpenBrace;
116 },
117 '}' => {
118 if (start_index < i) %return self.write(format[start_index...i]);
119 state = State.CloseBrace;
120 },
121 else => {},
122 },
123 State.OpenBrace => switch (c) {
124 '{' => {
125 state = State.Start;
126 start_index = i;
127 },
128 '}' => {
129 %return self.printValue(args[next_arg]);
130 next_arg += 1;
131 state = State.Start;
132 start_index = i + 1;
133 },
134 else => @compileError("Unknown format character: " ++ c),
135 },
136 State.CloseBrace => switch (c) {
137 '}' => {
138 state = State.Start;
139 start_index = i;
140 },
141 else => @compileError("Single '}' encountered in format string"),
142 },
143 }
144 }
145 comptime {
146 if (args.len != next_arg) {
147 @compileError("Unused arguments");
148 }
149 if (state != State.Start) {
150 @compileError("Incomplete format string: " ++ format);
151 }
152 }
153 inline if (start_index < format.len) {
154 %return self.write(format[start_index...format.len]);
155 }
104156 %return self.flush();
105 return byte_count;
106157 }
107158
108 pub fn printInt(self: &OutStream, comptime T: type, x: T) -> %usize {
159 pub fn printValue(self: &OutStream, value: var) -> %void {
160 const T = @typeOf(value);
161 if (@isInteger(T)) {
162 return self.printInt(T, value);
163 } else if (@isFloat(T)) {
164 return self.printFloat(T, value);
165 } else if (@canImplicitCast([]const u8, value)) {
166 const casted_value = ([]const u8)(value);
167 return self.write(casted_value);
168 } else {
169 @compileError("Unable to print type '" ++ @typeName(T) ++ "'");
170 }
171 }
172
173 pub fn printInt(self: &OutStream, comptime T: type, x: T) -> %void {
109174 // TODO replace max_u64_base10_digits with math.log10(math.pow(2, @sizeOf(T)))
110175 if (self.index + max_u64_base10_digits >= self.buffer.len) {
111176 %return self.flush();
112177 }
113178 const amt_printed = bufPrintInt(T, self.buffer[self.index...], x);
114179 self.index += amt_printed;
115 return amt_printed;
116180 }
117181
118182 pub fn flush(self: &OutStream) -> %void {
test/cases/misc.zig+49
......@@ -517,3 +517,52 @@ fn testArray2DConstDoublePtr(ptr: &const f32) {
517517 assert(ptr[0] == 1.0);
518518 assert(ptr[1] == 2.0);
519519}
520
521fn isInteger() {
522 @setFnTest(this);
523
524 comptime {
525 assert(@isInteger(i8));
526 assert(@isInteger(u8));
527 assert(@isInteger(i64));
528 assert(@isInteger(u64));
529 assert(!@isInteger(f32));
530 assert(!@isInteger(f64));
531 assert(!@isInteger(bool));
532 assert(!@isInteger(&i32));
533 }
534}
535
536fn isFloat() {
537 @setFnTest(this);
538
539 comptime {
540 assert(!@isFloat(i8));
541 assert(!@isFloat(u8));
542 assert(!@isFloat(i64));
543 assert(!@isFloat(u64));
544 assert(@isFloat(f32));
545 assert(@isFloat(f64));
546 assert(!@isFloat(bool));
547 assert(!@isFloat(&f32));
548 }
549}
550
551fn canImplicitCast() {
552 @setFnTest(this);
553
554 comptime {
555 assert(@canImplicitCast(i64, i32(3)));
556 assert(!@canImplicitCast(i32, f32(1.234)));
557 assert(@canImplicitCast([]const u8, "aoeu"));
558 }
559}
560
561fn typeName() {
562 @setFnTest(this);
563
564 comptime {
565 assert(str.eql(@typeName(i64), "i64"));
566 assert(str.eql(@typeName(&usize), "&usize"));
567 }
568}