diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr index ea51484396e9..9e887a10532b 100644 --- a/src/compiler/crystal/codegen/codegen.cr +++ b/src/compiler/crystal/codegen/codegen.cr @@ -424,10 +424,10 @@ module Crystal @last = int64(node.value.to_u64) when :i128 # TODO: implement String#to_i128 and use it - @last = int128(node.value.to_i64) + @last = int128(node.value.to_i128) when :u128 # TODO: implement String#to_u128 and use it - @last = int128(node.value.to_u64) + @last = int128(node.value.to_u128) when :f32 @last = llvm_context.float.const_float(node.value) when :f64 diff --git a/src/compiler/crystal/codegen/llvm_builder_helper.cr b/src/compiler/crystal/codegen/llvm_builder_helper.cr index 9136ead94247..1218214d2b46 100644 --- a/src/compiler/crystal/codegen/llvm_builder_helper.cr +++ b/src/compiler/crystal/codegen/llvm_builder_helper.cr @@ -21,7 +21,7 @@ module Crystal end def int128(n) - llvm_context.int128.const_int(n) + llvm_context.int128.const_int_of_string(n.to_s) end def int(n) diff --git a/src/compiler/crystal/syntax/lexer.cr b/src/compiler/crystal/syntax/lexer.cr index bc1ca2c9014c..0060bb460595 100644 --- a/src/compiler/crystal/syntax/lexer.cr +++ b/src/compiler/crystal/syntax/lexer.cr @@ -1557,7 +1557,7 @@ module Crystal def scan_hex_number(start, negative = false) next_char - num = 0_u64 + num = 0_u128 while true char = next_char if char == '_' @@ -1576,7 +1576,7 @@ module Crystal def finish_scan_prefixed_number(num, negative, start) if negative - string_value = (num.to_i64 * -1).to_s + string_value = (num.to_i128 * -1).to_s else string_value = num.to_s end diff --git a/src/int.cr b/src/int.cr index 00454ab97774..b1c80c10feea 100644 --- a/src/int.cr +++ b/src/int.cr @@ -779,7 +779,7 @@ end struct UInt128 # TODO: eventually update to literals once UInt128 bit support is finished - MIN = new 0 + MIN = 0_u128 MAX = ~MIN # Returns an `UInt128` by invoking `to_u128` on *value*. diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr index 7c6fc5c333ef..4609066e234a 100644 --- a/src/llvm/lib_llvm.cr +++ b/src/llvm/lib_llvm.cr @@ -134,6 +134,7 @@ lib LibLLVM fun build_zext = LLVMBuildZExt(builder : BuilderRef, val : ValueRef, dest_ty : TypeRef, name : UInt8*) : ValueRef fun const_array = LLVMConstArray(element_type : TypeRef, constant_vals : ValueRef*, length : UInt32) : ValueRef fun const_int = LLVMConstInt(int_type : TypeRef, value : UInt64, sign_extend : Int32) : ValueRef + fun const_int_of_string = LLVMConstIntOfString(int_type : TypeRef, value : UInt8*, radix : UInt8) : ValueRef fun const_null = LLVMConstNull(ty : TypeRef) : ValueRef fun const_pointer_null = LLVMConstPointerNull(ty : TypeRef) : ValueRef fun const_real = LLVMConstReal(real_ty : TypeRef, n : Float64) : ValueRef diff --git a/src/llvm/type.cr b/src/llvm/type.cr index 01926eca8845..ad11b17c94be 100644 --- a/src/llvm/type.cr +++ b/src/llvm/type.cr @@ -129,6 +129,10 @@ struct LLVM::Type Value.new LibLLVM.const_int(self, value, 0) end + def const_int_of_string(string) : Value + Value.new LibLLVM.const_int_of_string(self, string, 10) + end + def const_float(value : Float32) : Value Value.new LibLLVM.const_real(self, value) end diff --git a/src/string.cr b/src/string.cr index 5f2f4b3b1486..ff38eac59566 100644 --- a/src/string.cr +++ b/src/string.cr @@ -462,6 +462,38 @@ class String gen_to_ u64 end + ### to_i128/to_u128 + + # Same as `#to_i` but returns an `Int128`. + def to_i128(base : Int = 10, whitespace = true, underscore = false, prefix = false, strict = true) : Int128 + to_i128(base, whitespace, underscore, prefix, strict) { raise ArgumentError.new("Invalid Int128: #{self}") } + end + + # Same as `#to_i` but returns an `Int128` or `nil`. + def to_i128?(base : Int = 10, whitespace = true, underscore = false, prefix = false, strict = true) : Int128? + to_i128(base, whitespace, underscore, prefix, strict) { nil } + end + + # Same as `#to_i` but returns an `Int128` or the block's value. + def to_i128(base : Int = 10, whitespace = true, underscore = false, prefix = false, strict = true, &block) + gen_to_ i128, ((1<<127)-1).to_u128, (1<<127).to_u128 + end + + # Same as `#to_i` but returns an `UInt128`. + def to_u128(base : Int = 10, whitespace = true, underscore = false, prefix = false, strict = true) : UInt128 + to_u128(base, whitespace, underscore, prefix, strict) { raise ArgumentError.new("Invalid UInt128: #{self}") } + end + + # Same as `#to_i` but returns an `UInt128` or `nil`. + def to_u128?(base : Int = 10, whitespace = true, underscore = false, prefix = false, strict = true) : UInt128? + to_u128(base, whitespace, underscore, prefix, strict) { nil } + end + + # Same as `#to_i` but returns an `UInt128` or the block's value. + def to_u128(base : Int = 10, whitespace = true, underscore = false, prefix = false, strict = true, &block) + gen_to_ u128 + end + # :nodoc: CHAR_TO_DIGIT = begin table = StaticArray(Int8, 256).new(-1_i8) @@ -485,13 +517,13 @@ class String end # :nodoc: - record ToU64Info, - value : UInt64, + record ToU128Info, + value : UInt128, negative : Bool, invalid : Bool private macro gen_to_(method, max_positive = nil, max_negative = nil) - info = to_u64_info(base, whitespace, underscore, prefix, strict) + info = to_u128_info(base, whitespace, underscore, prefix, strict) return yield if info.invalid if info.negative @@ -509,7 +541,7 @@ class String end end - private def to_u64_info(base, whitespace, underscore, prefix, strict) + private def to_u128_info(base, whitespace, underscore, prefix, strict) raise ArgumentError.new("Invalid base #{base}") unless 2 <= base <= 36 || base == 62 ptr = to_unsafe @@ -523,7 +555,7 @@ class String negative = false found_digit = false - mul_overflow = ~0_u64 / base + mul_overflow = ~0_u128 / base # Check + and - case ptr.value.unsafe_chr @@ -555,7 +587,7 @@ class String end end - value = 0_u64 + value = 0_u128 last_is_underscore = true invalid = false @@ -608,7 +640,7 @@ class String invalid = true end - ToU64Info.new value, negative, invalid + ToU128Info.new value, negative, invalid end # Returns the result of interpreting characters in this string as a floating point number (`Float64`).