From d9ea7d65f2ff86d846ebea91c330822550fda293 Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Sun, 19 Dec 2021 14:39:49 +0800 Subject: [PATCH] Use enums instead of symbols for primitive number kinds --- spec/compiler/lexer/lexer_spec.cr | 10 +- src/compiler/crystal/codegen/ast.cr | 25 - src/compiler/crystal/codegen/call.cr | 4 +- src/compiler/crystal/codegen/codegen.cr | 26 +- src/compiler/crystal/codegen/const.cr | 2 +- .../crystal/codegen/llvm_builder_helper.cr | 4 +- src/compiler/crystal/codegen/primitives.cr | 6 +- src/compiler/crystal/interpreter/c.cr | 22 +- src/compiler/crystal/interpreter/compiler.cr | 26 +- .../crystal/interpreter/primitives.cr | 634 +++++++++--------- src/compiler/crystal/interpreter/value.cr | 48 +- src/compiler/crystal/macros/methods.cr | 20 +- src/compiler/crystal/program.cr | 27 +- src/compiler/crystal/semantic/ast.cr | 17 +- src/compiler/crystal/semantic/call.cr | 6 +- .../crystal/semantic/math_interpreter.cr | 18 +- .../crystal/semantic/top_level_visitor.cr | 2 +- src/compiler/crystal/syntax/ast.cr | 108 ++- src/compiler/crystal/syntax/lexer.cr | 62 +- src/compiler/crystal/syntax/parser.cr | 2 +- src/compiler/crystal/syntax/to_s.cr | 4 +- src/compiler/crystal/syntax/token.cr | 4 +- src/compiler/crystal/types.cr | 30 +- 23 files changed, 565 insertions(+), 542 deletions(-) diff --git a/spec/compiler/lexer/lexer_spec.cr b/spec/compiler/lexer/lexer_spec.cr index e6bd87e35d2e..42ab6b5a79b6 100644 --- a/spec/compiler/lexer/lexer_spec.cr +++ b/spec/compiler/lexer/lexer_spec.cr @@ -20,7 +20,7 @@ private def it_lexes(string, type, value) end end -private def it_lexes(string, type, value, number_kind) +private def it_lexes(string, type, value, number_kind : NumberKind) it "lexes #{string.inspect}" do lexer = Lexer.new string token = lexer.next_token @@ -72,11 +72,11 @@ private def it_lexes_f64(values) values.each { |value| it_lexes_number :f64, value } end -private def it_lexes_number(number_kind, value : Array) +private def it_lexes_number(number_kind : NumberKind, value : Array) it_lexes value[0], :NUMBER, value[1], number_kind end -private def it_lexes_number(number_kind, value : String) +private def it_lexes_number(number_kind : NumberKind, value : String) it_lexes value, :NUMBER, value, number_kind end @@ -567,11 +567,11 @@ describe "Lexer" do it "lexes float then zero (bug)" do lexer = Lexer.new "2.5 0" - lexer.next_token.number_kind.should eq(:f64) + lexer.next_token.number_kind.should eq(NumberKind::F64) lexer.next_token.type.should eq(:SPACE) token = lexer.next_token token.type.should eq(:NUMBER) - token.number_kind.should eq(:i32) + token.number_kind.should eq(NumberKind::I32) end it "lexes symbol with quote" do diff --git a/src/compiler/crystal/codegen/ast.cr b/src/compiler/crystal/codegen/ast.cr index 014e1a9d1289..c36f55c30987 100644 --- a/src/compiler/crystal/codegen/ast.cr +++ b/src/compiler/crystal/codegen/ast.cr @@ -5,31 +5,6 @@ module Crystal def no_returns? type?.try &.no_return? end - - def zero? - false - end - - def false? - false - end - end - - class BoolLiteral - def false? - !value - end - end - - class NumberLiteral - def zero? - case :kind - when :f32, :f64 - value == "0.0" - else - value == "0" - end - end end class Def diff --git a/src/compiler/crystal/codegen/call.cr b/src/compiler/crystal/codegen/call.cr index ac7f937d6485..69e7a4ca0277 100644 --- a/src/compiler/crystal/codegen/call.cr +++ b/src/compiler/crystal/codegen/call.cr @@ -229,10 +229,10 @@ class Crystal::CodeGenVisitor # If we are passing variadic arguments there are some special rules if i >= target_def_args_size arg_type = arg.type.remove_indirection - if arg_type.is_a?(FloatType) && arg_type.kind == :f32 + if arg_type.is_a?(FloatType) && arg_type.kind.bytesize < 64 # Floats must be passed as doubles (there are no float varargs) call_arg = extend_float @program.float64, call_arg - elsif arg_type.is_a?(IntegerType) && arg_type.kind.in?(:i8, :u8, :i16, :u16) + elsif arg_type.is_a?(IntegerType) && arg_type.kind.bytesize < 32 # Integer with a size less that `int` must be converted to `int` call_arg = extend_int arg_type, @program.int32, call_arg end diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr index c5ebc460ef96..bf5bfbe1511d 100644 --- a/src/compiler/crystal/codegen/codegen.cr +++ b/src/compiler/crystal/codegen/codegen.cr @@ -458,32 +458,30 @@ module Crystal def visit(node : NumberLiteral) case node.kind - when :i8 + in .i8? @last = int8(node.value.to_i8) - when :u8 + in .u8? @last = int8(node.value.to_u8) - when :i16 + in .i16? @last = int16(node.value.to_i16) - when :u16 + in .u16? @last = int16(node.value.to_u16) - when :i32 + in .i32? @last = int32(node.value.to_i32) - when :u32 + in .u32? @last = int32(node.value.to_u32) - when :i64 + in .i64? @last = int64(node.value.to_i64) - when :u64 + in .u64? @last = int64(node.value.to_u64) - when :i128 + in .i128? @last = int128(node.value.to_i128) - when :u128 + in .u128? @last = int128(node.value.to_u128) - when :f32 + in .f32? @last = float32(node.value) - when :f64 + in .f64? @last = float64(node.value) - else - node.raise "Bug: unhandled number kind: #{node.kind}" end end diff --git a/src/compiler/crystal/codegen/const.cr b/src/compiler/crystal/codegen/const.cr index 83c4a934e4e7..9a97afd87dcd 100644 --- a/src/compiler/crystal/codegen/const.cr +++ b/src/compiler/crystal/codegen/const.cr @@ -49,7 +49,7 @@ class Crystal::CodeGenVisitor # TODO: there's an LLVM bug that prevents us from having internal globals of type i128 or u128: # https://bugs.llvm.org/show_bug.cgi?id=42932 # so we just use global. - if @single_module && !(type.is_a?(IntegerType) && (type.kind == :i128 || type.kind == :u128)) + if @single_module && !(type.is_a?(IntegerType) && (type.kind.i128? || type.kind.u128?)) global.linkage = LLVM::Linkage::Internal if @single_module end diff --git a/src/compiler/crystal/codegen/llvm_builder_helper.cr b/src/compiler/crystal/codegen/llvm_builder_helper.cr index f62fdcee7da1..687b60d33b10 100644 --- a/src/compiler/crystal/codegen/llvm_builder_helper.cr +++ b/src/compiler/crystal/codegen/llvm_builder_helper.cr @@ -42,9 +42,9 @@ module Crystal def float(value, type) case type.kind - when :f32 + when .f32? float32(value.to_f32) - when :f64 + when .f64? float64(value.to_f64) else raise "Unsupported float type" diff --git a/src/compiler/crystal/codegen/primitives.cr b/src/compiler/crystal/codegen/primitives.cr index cae276f36e1f..c8722385f9e2 100644 --- a/src/compiler/crystal/codegen/primitives.cr +++ b/src/compiler/crystal/codegen/primitives.cr @@ -260,7 +260,7 @@ class Crystal::CodeGenVisitor end private def codegen_out_of_range(target_type : IntegerType, arg_type : FloatType, arg) - if arg_type.kind == :f32 && target_type.kind == :u128 + if arg_type.kind.f32? && target_type.kind.u128? # since Float32::MAX < UInt128::MAX # the range checking is replaced by a positive check only builder.fcmp(LLVM::RealPredicate::OLT, arg, llvm_type(arg_type).const_float(0)) @@ -275,7 +275,7 @@ class Crystal::CodeGenVisitor end private def codegen_out_of_range(target_type : FloatType, arg_type : IntegerType, arg) - if arg_type.kind == :u128 && target_type.kind == :f32 + if arg_type.kind.u128? && target_type.kind.f32? # since Float32::MAX < UInt128::MAX # the value will be outside of the float range if # arg > Float32::MAX @@ -636,7 +636,7 @@ class Crystal::CodeGenVisitor def codegen_convert(from_type : IntegerType, to_type : FloatType, arg, *, checked : Bool) if checked - if from_type.kind == :u128 && to_type.kind == :f32 + if from_type.kind.u128? && to_type.kind.f32? overflow = codegen_out_of_range(to_type, from_type, arg) codegen_raise_overflow_cond(overflow) end diff --git a/src/compiler/crystal/interpreter/c.cr b/src/compiler/crystal/interpreter/c.cr index 7b469371e0b1..7055b1123bfe 100644 --- a/src/compiler/crystal/interpreter/c.cr +++ b/src/compiler/crystal/interpreter/c.cr @@ -27,16 +27,14 @@ module Crystal class IntegerType def ffi_type : FFI::Type case kind - when :i8 then FFI::Type.sint8 - when :u8 then FFI::Type.uint8 - when :i16 then FFI::Type.sint16 - when :u16 then FFI::Type.uint16 - when :i32 then FFI::Type.sint32 - when :u32 then FFI::Type.uint32 - when :i64 then FFI::Type.sint64 - when :u64 then FFI::Type.uint64 - when :f32 then FFI::Type.float - when :f64 then FFI::Type.double + when .i8? then FFI::Type.sint8 + when .u8? then FFI::Type.uint8 + when .i16? then FFI::Type.sint16 + when .u16? then FFI::Type.uint16 + when .i32? then FFI::Type.sint32 + when .u32? then FFI::Type.uint32 + when .i64? then FFI::Type.sint64 + when .u64? then FFI::Type.uint64 else raise "BUG: missing ffi_type for #{self} (#{self.class})" end @@ -46,8 +44,8 @@ module Crystal class FloatType def ffi_type : FFI::Type case kind - when :f32 then FFI::Type.float - when :f64 then FFI::Type.double + when .f32? then FFI::Type.float + when .f64? then FFI::Type.double else raise "BUG: missing ffi_type for #{self} (#{self.class})" end diff --git a/src/compiler/crystal/interpreter/compiler.cr b/src/compiler/crystal/interpreter/compiler.cr index ccb103a8cae4..17610f61108c 100644 --- a/src/compiler/crystal/interpreter/compiler.cr +++ b/src/compiler/crystal/interpreter/compiler.cr @@ -317,34 +317,32 @@ class Crystal::Repl::Compiler < Crystal::Visitor private def compile_number(node, kind, value) case kind - when :i8 + in .i8? put_i8 value.to_i8, node: node - when :u8 + in .u8? put_u8 value.to_u8, node: node - when :i16 + in .i16? put_i16 value.to_i16, node: node - when :u16 + in .u16? put_u16 value.to_u16, node: node - when :i32 + in .i32? put_i32 value.to_i32, node: node - when :u32 + in .u32? put_u32 value.to_u32, node: node - when :i64 + in .i64? put_i64 value.to_i64, node: node - when :u64 + in .u64? put_u64 value.to_u64, node: node - when :i128 + in .i128? # TODO: implement String#to_i128 and use it put_i128 value.to_i64.to_i128!, node: node - when :u128 + in .u128? # TODO: implement String#to_i128 and use it put_u128 value.to_u64.to_u128!, node: node - when :f32 + in .f32? put_i32 value.to_f32.unsafe_as(Int32), node: node - when :f64 + in .f64? put_i64 value.to_f64.unsafe_as(Int64), node: node - else - node.raise "BUG: missing interpret for NumberLiteral with kind #{kind}" end end diff --git a/src/compiler/crystal/interpreter/primitives.cr b/src/compiler/crystal/interpreter/primitives.cr index 7c80e2796b3d..b4994d74eb6a 100644 --- a/src/compiler/crystal/interpreter/primitives.cr +++ b/src/compiler/crystal/interpreter/primitives.cr @@ -589,155 +589,154 @@ class Crystal::Repl::Compiler node.raise "BUG: missing handling of convert from #{from_type} to #{to_type}" end - private def primitive_convert(node : ASTNode, from_kind : Symbol, to_kind : Symbol, checked : Bool) + private def primitive_convert(node : ASTNode, from_kind : NumberKind, to_kind : NumberKind, checked : Bool) # Most of these are nop because we align the stack to 64 bits, # so numbers are already converted to 64 bits case {from_kind, to_kind} - when {:i8, :i8} then nop - when {:i8, :i16} then sign_extend(7, node: node) - when {:i8, :i32} then sign_extend(7, node: node) - when {:i8, :i64} then sign_extend(7, node: node) - when {:i8, :i128} then sign_extend(15, node: node) - when {:i8, :u8} then checked ? (sign_extend(7, node: node); i64_to_u8(node: node)) : nop - when {:i8, :u16} then sign_extend(7, node: node); checked ? i64_to_u16(node: node) : nop - when {:i8, :u32} then sign_extend(7, node: node); checked ? i64_to_u32(node: node) : nop - when {:i8, :u64} then sign_extend(7, node: node); checked ? i64_to_u64(node: node) : nop - when {:i8, :u128} then sign_extend(15, node: node); checked ? i128_to_u128(node: node) : nop - when {:i8, :f32} then sign_extend(7, node: node); i64_to_f32(node: node) - when {:i8, :f64} then sign_extend(7, node: node); i64_to_f64(node: node) - when {:u8, :i8} then zero_extend(7, node: node); checked ? u64_to_i8(node: node) : nop - when {:u8, :i16} then zero_extend(7, node: node) - when {:u8, :i32} then zero_extend(7, node: node) - when {:u8, :i64} then zero_extend(7, node: node) - when {:u8, :i128} then zero_extend(15, node: node) - when {:u8, :u8} then nop - when {:u8, :u16} then zero_extend(7, node: node) - when {:u8, :u32} then zero_extend(7, node: node) - when {:u8, :u64} then zero_extend(7, node: node) - when {:u8, :u128} then zero_extend(15, node: node) - when {:u8, :f32} then zero_extend(7, node: node); u64_to_f32(node: node) - when {:u8, :f64} then zero_extend(7, node: node); u64_to_f64(node: node) - when {:i16, :i8} then checked ? (sign_extend(6, node: node); i64_to_i8(node: node)) : nop - when {:i16, :i16} then nop - when {:i16, :i32} then sign_extend(6, node: node) - when {:i16, :i64} then sign_extend(6, node: node) - when {:i16, :i128} then sign_extend(14, node: node) - when {:i16, :u8} then checked ? (sign_extend(6, node: node); i64_to_u8(node: node)) : nop - when {:i16, :u16} then checked ? (sign_extend(6, node: node); i64_to_u16(node: node)) : nop - when {:i16, :u32} then sign_extend(6, node: node); checked ? i64_to_u32(node: node) : nop - when {:i16, :u64} then sign_extend(6, node: node); checked ? i64_to_u64(node: node) : nop - when {:i16, :u128} then sign_extend(14, node: node); checked ? i128_to_u128(node: node) : nop - when {:i16, :f32} then sign_extend(6, node: node); i64_to_f32(node: node) - when {:i16, :f64} then sign_extend(6, node: node); i64_to_f64(node: node) - when {:u16, :i8} then checked ? (zero_extend(6, node: node); u64_to_i8(node: node)) : nop - when {:u16, :i16} then checked ? (zero_extend(6, node: node); u64_to_i16(node: node)) : nop - when {:u16, :i32} then zero_extend(6, node: node) - when {:u16, :i64} then zero_extend(6, node: node) - when {:u16, :i128} then zero_extend(14, node: node) - when {:u16, :u8} then nop - when {:u16, :u16} then nop - when {:u16, :u32} then zero_extend(6, node: node) - when {:u16, :u64} then zero_extend(6, node: node) - when {:u16, :u128} then zero_extend(14, node: node) - when {:u16, :f32} then zero_extend(6, node: node); u64_to_f32(node: node) - when {:u16, :f64} then zero_extend(6, node: node); u64_to_f64(node: node) - when {:i32, :i8} then checked ? (sign_extend(4, node: node); i64_to_i8(node: node)) : nop - when {:i32, :i16} then checked ? (sign_extend(4, node: node); i64_to_i16(node: node)) : nop - when {:i32, :i32} then nop - when {:i32, :i64} then sign_extend(4, node: node) - when {:i32, :i128} then sign_extend(12, node: node) - when {:i32, :u8} then checked ? (sign_extend(4, node: node); i64_to_u8(node: node)) : nop - when {:i32, :u16} then checked ? (sign_extend(4, node: node); i64_to_u16(node: node)) : nop - when {:i32, :u32} then checked ? (sign_extend(4, node: node); i64_to_u32(node: node)) : nop - when {:i32, :u64} then checked ? (sign_extend(4, node: node); i64_to_u64(node: node)) : sign_extend(4, node: node) - when {:i32, :u128} then checked ? (sign_extend(12, node: node); i128_to_u128(node: node)) : sign_extend(12, node: node) - when {:i32, :f32} then sign_extend(4, node: node); i64_to_f32(node: node) - when {:i32, :f64} then sign_extend(4, node: node); i64_to_f64(node: node) - when {:u32, :i8} then checked ? (zero_extend(4, node: node); u64_to_i8(node: node)) : nop - when {:u32, :i16} then checked ? (zero_extend(4, node: node); u64_to_i16(node: node)) : nop - when {:u32, :i32} then checked ? (zero_extend(4, node: node); u64_to_i32(node: node)) : nop - when {:u32, :i64} then zero_extend(4, node: node) - when {:u32, :i128} then zero_extend(12, node: node) - when {:u32, :u8} then checked ? (zero_extend(4, node: node); u64_to_u8(node: node)) : nop - when {:u32, :u16} then checked ? (zero_extend(4, node: node); u64_to_u16(node: node)) : nop - when {:u32, :u32} then nop - when {:u32, :u64} then zero_extend(4, node: node) - when {:u32, :u128} then zero_extend(12, node: node) - when {:u32, :f32} then zero_extend(4, node: node); u64_to_f32(node: node) - when {:u32, :f64} then zero_extend(4, node: node); u64_to_f64(node: node) - when {:i64, :i8} then checked ? i64_to_i8(node: node) : nop - when {:i64, :i16} then checked ? i64_to_i16(node: node) : nop - when {:i64, :i32} then checked ? i64_to_i32(node: node) : nop - when {:i64, :i64} then nop - when {:i64, :i128} then sign_extend(8, node: node) - when {:i64, :u8} then checked ? i64_to_u8(node: node) : nop - when {:i64, :u16} then checked ? i64_to_u16(node: node) : nop - when {:i64, :u32} then checked ? i64_to_u32(node: node) : nop - when {:i64, :u64} then checked ? i64_to_u64(node: node) : nop - when {:i64, :u128} then checked ? (sign_extend(8, node: node); i128_to_u128(node: node)) : sign_extend(8, node: node) - when {:i64, :f32} then i64_to_f32(node: node) - when {:i64, :f64} then i64_to_f64(node: node) - when {:u64, :i8} then checked ? u64_to_i8(node: node) : nop - when {:u64, :i16} then checked ? u64_to_i16(node: node) : nop - when {:u64, :i32} then checked ? u64_to_i32(node: node) : nop - when {:u64, :i64} then checked ? u64_to_i64(node: node) : nop - when {:u64, :i128} then zero_extend(8, node: node) - when {:u64, :u8} then checked ? u64_to_u8(node: node) : nop - when {:u64, :u16} then checked ? u64_to_u16(node: node) : nop - when {:u64, :u32} then checked ? u64_to_u32(node: node) : nop - when {:u64, :u64} then nop - when {:u64, :u128} then zero_extend(8, node: node) - when {:u64, :f32} then u64_to_f32(node: node) - when {:u64, :f64} then u64_to_f64(node: node) - when {:i128, :i8} then checked ? i128_to_i8(node: node) : pop(8, node: node) - when {:i128, :i16} then checked ? i128_to_i16(node: node) : pop(8, node: node) - when {:i128, :i32} then checked ? i128_to_i32(node: node) : pop(8, node: node) - when {:i128, :i64} then checked ? i128_to_i64(node: node) : pop(8, node: node) - when {:i128, :i128} then nop - when {:i128, :u8} then checked ? i128_to_u8(node: node) : pop(8, node: node) - when {:i128, :u16} then checked ? i128_to_u16(node: node) : pop(8, node: node) - when {:i128, :u32} then checked ? i128_to_u32(node: node) : pop(8, node: node) - when {:i128, :u64} then checked ? i128_to_u64(node: node) : pop(8, node: node) - when {:i128, :u128} then checked ? i128_to_u128(node: node) : nop - when {:i128, :f32} then i128_to_f32(node: node) - when {:i128, :f64} then i128_to_f64(node: node) - when {:u128, :i8} then checked ? u128_to_i8(node: node) : pop(8, node: node) - when {:u128, :i16} then checked ? u128_to_i16(node: node) : pop(8, node: node) - when {:u128, :i32} then checked ? u128_to_i32(node: node) : pop(8, node: node) - when {:u128, :i64} then checked ? u128_to_i64(node: node) : pop(8, node: node) - when {:u128, :i128} then checked ? u128_to_i128(node: node) : nop - when {:u128, :u8} then checked ? u128_to_u8(node: node) : pop(8, node: node) - when {:u128, :u16} then checked ? u128_to_u16(node: node) : pop(8, node: node) - when {:u128, :u32} then checked ? u128_to_u32(node: node) : pop(8, node: node) - when {:u128, :u64} then checked ? u128_to_u64(node: node) : pop(8, node: node) - when {:u128, :u128} then nop - when {:u128, :f32} then u128_to_f32(node: node) - when {:u128, :f64} then u128_to_f64(node: node) - when {:f32, :i8} then f32_to_f64(node: node); checked ? f64_to_i8(node: node) : f64_to_i64_bang(node: node) - when {:f32, :i16} then f32_to_f64(node: node); checked ? f64_to_i16(node: node) : f64_to_i64_bang(node: node) - when {:f32, :i32} then f32_to_f64(node: node); checked ? f64_to_i32(node: node) : f64_to_i64_bang(node: node) - when {:f32, :i64} then f32_to_f64(node: node); checked ? f64_to_i64(node: node) : f64_to_i64_bang(node: node) - when {:f32, :i128} then f32_to_f64(node: node); checked ? f64_to_i128(node: node) : f64_to_i128_bang(node: node) - when {:f32, :u8} then f32_to_f64(node: node); checked ? f64_to_u8(node: node) : f64_to_i64_bang(node: node) - when {:f32, :u16} then f32_to_f64(node: node); checked ? f64_to_u16(node: node) : f64_to_i64_bang(node: node) - when {:f32, :u32} then f32_to_f64(node: node); checked ? f64_to_u32(node: node) : f64_to_i64_bang(node: node) - when {:f32, :u64} then f32_to_f64(node: node); checked ? f64_to_u64(node: node) : f64_to_i64_bang(node: node) - when {:f32, :u128} then f32_to_f64(node: node); checked ? f64_to_u128(node: node) : f64_to_i128_bang(node: node) - when {:f32, :f32} then nop - when {:f32, :f64} then f32_to_f64(node: node) - when {:f64, :i8} then checked ? f64_to_i8(node: node) : f64_to_i64_bang(node: node) - when {:f64, :i16} then checked ? f64_to_i16(node: node) : f64_to_i64_bang(node: node) - when {:f64, :i32} then checked ? f64_to_i32(node: node) : f64_to_i64_bang(node: node) - when {:f64, :i64} then checked ? f64_to_i64(node: node) : f64_to_i64_bang(node: node) - when {:f64, :i128} then checked ? f64_to_i128(node: node) : f64_to_i128_bang(node: node) - when {:f64, :u8} then checked ? f64_to_u8(node: node) : f64_to_i64_bang(node: node) - when {:f64, :u16} then checked ? f64_to_u16(node: node) : f64_to_i64_bang(node: node) - when {:f64, :u32} then checked ? f64_to_u32(node: node) : f64_to_i64_bang(node: node) - when {:f64, :u64} then checked ? f64_to_u64(node: node) : f64_to_i64_bang(node: node) - when {:f64, :u128} then checked ? f64_to_u128(node: node) : f64_to_i128_bang(node: node) - when {:f64, :f32} then checked ? f64_to_f32(node: node) : f64_to_f32_bang(node: node) - when {:f64, :f64} then nop - else node.raise "BUG: missing handling of unchecked_convert for #{from_kind} - #{to_kind}" + in {.i8?, .i8?} then nop + in {.i8?, .i16?} then sign_extend(7, node: node) + in {.i8?, .i32?} then sign_extend(7, node: node) + in {.i8?, .i64?} then sign_extend(7, node: node) + in {.i8?, .i128?} then sign_extend(15, node: node) + in {.i8?, .u8?} then checked ? (sign_extend(7, node: node); i64_to_u8(node: node)) : nop + in {.i8?, .u16?} then sign_extend(7, node: node); checked ? i64_to_u16(node: node) : nop + in {.i8?, .u32?} then sign_extend(7, node: node); checked ? i64_to_u32(node: node) : nop + in {.i8?, .u64?} then sign_extend(7, node: node); checked ? i64_to_u64(node: node) : nop + in {.i8?, .u128?} then sign_extend(15, node: node); checked ? i128_to_u128(node: node) : nop + in {.i8?, .f32?} then sign_extend(7, node: node); i64_to_f32(node: node) + in {.i8?, .f64?} then sign_extend(7, node: node); i64_to_f64(node: node) + in {.u8?, .i8?} then zero_extend(7, node: node); checked ? u64_to_i8(node: node) : nop + in {.u8?, .i16?} then zero_extend(7, node: node) + in {.u8?, .i32?} then zero_extend(7, node: node) + in {.u8?, .i64?} then zero_extend(7, node: node) + in {.u8?, .i128?} then zero_extend(15, node: node) + in {.u8?, .u8?} then nop + in {.u8?, .u16?} then zero_extend(7, node: node) + in {.u8?, .u32?} then zero_extend(7, node: node) + in {.u8?, .u64?} then zero_extend(7, node: node) + in {.u8?, .u128?} then zero_extend(15, node: node) + in {.u8?, .f32?} then zero_extend(7, node: node); u64_to_f32(node: node) + in {.u8?, .f64?} then zero_extend(7, node: node); u64_to_f64(node: node) + in {.i16?, .i8?} then checked ? (sign_extend(6, node: node); i64_to_i8(node: node)) : nop + in {.i16?, .i16?} then nop + in {.i16?, .i32?} then sign_extend(6, node: node) + in {.i16?, .i64?} then sign_extend(6, node: node) + in {.i16?, .i128?} then sign_extend(14, node: node) + in {.i16?, .u8?} then checked ? (sign_extend(6, node: node); i64_to_u8(node: node)) : nop + in {.i16?, .u16?} then checked ? (sign_extend(6, node: node); i64_to_u16(node: node)) : nop + in {.i16?, .u32?} then sign_extend(6, node: node); checked ? i64_to_u32(node: node) : nop + in {.i16?, .u64?} then sign_extend(6, node: node); checked ? i64_to_u64(node: node) : nop + in {.i16?, .u128?} then sign_extend(14, node: node); checked ? i128_to_u128(node: node) : nop + in {.i16?, .f32?} then sign_extend(6, node: node); i64_to_f32(node: node) + in {.i16?, .f64?} then sign_extend(6, node: node); i64_to_f64(node: node) + in {.u16?, .i8?} then checked ? (zero_extend(6, node: node); u64_to_i8(node: node)) : nop + in {.u16?, .i16?} then checked ? (zero_extend(6, node: node); u64_to_i16(node: node)) : nop + in {.u16?, .i32?} then zero_extend(6, node: node) + in {.u16?, .i64?} then zero_extend(6, node: node) + in {.u16?, .i128?} then zero_extend(14, node: node) + in {.u16?, .u8?} then nop + in {.u16?, .u16?} then nop + in {.u16?, .u32?} then zero_extend(6, node: node) + in {.u16?, .u64?} then zero_extend(6, node: node) + in {.u16?, .u128?} then zero_extend(14, node: node) + in {.u16?, .f32?} then zero_extend(6, node: node); u64_to_f32(node: node) + in {.u16?, .f64?} then zero_extend(6, node: node); u64_to_f64(node: node) + in {.i32?, .i8?} then checked ? (sign_extend(4, node: node); i64_to_i8(node: node)) : nop + in {.i32?, .i16?} then checked ? (sign_extend(4, node: node); i64_to_i16(node: node)) : nop + in {.i32?, .i32?} then nop + in {.i32?, .i64?} then sign_extend(4, node: node) + in {.i32?, .i128?} then sign_extend(12, node: node) + in {.i32?, .u8?} then checked ? (sign_extend(4, node: node); i64_to_u8(node: node)) : nop + in {.i32?, .u16?} then checked ? (sign_extend(4, node: node); i64_to_u16(node: node)) : nop + in {.i32?, .u32?} then checked ? (sign_extend(4, node: node); i64_to_u32(node: node)) : nop + in {.i32?, .u64?} then checked ? (sign_extend(4, node: node); i64_to_u64(node: node)) : sign_extend(4, node: node) + in {.i32?, .u128?} then checked ? (sign_extend(12, node: node); i128_to_u128(node: node)) : sign_extend(12, node: node) + in {.i32?, .f32?} then sign_extend(4, node: node); i64_to_f32(node: node) + in {.i32?, .f64?} then sign_extend(4, node: node); i64_to_f64(node: node) + in {.u32?, .i8?} then checked ? (zero_extend(4, node: node); u64_to_i8(node: node)) : nop + in {.u32?, .i16?} then checked ? (zero_extend(4, node: node); u64_to_i16(node: node)) : nop + in {.u32?, .i32?} then checked ? (zero_extend(4, node: node); u64_to_i32(node: node)) : nop + in {.u32?, .i64?} then zero_extend(4, node: node) + in {.u32?, .i128?} then zero_extend(12, node: node) + in {.u32?, .u8?} then checked ? (zero_extend(4, node: node); u64_to_u8(node: node)) : nop + in {.u32?, .u16?} then checked ? (zero_extend(4, node: node); u64_to_u16(node: node)) : nop + in {.u32?, .u32?} then nop + in {.u32?, .u64?} then zero_extend(4, node: node) + in {.u32?, .u128?} then zero_extend(12, node: node) + in {.u32?, .f32?} then zero_extend(4, node: node); u64_to_f32(node: node) + in {.u32?, .f64?} then zero_extend(4, node: node); u64_to_f64(node: node) + in {.i64?, .i8?} then checked ? i64_to_i8(node: node) : nop + in {.i64?, .i16?} then checked ? i64_to_i16(node: node) : nop + in {.i64?, .i32?} then checked ? i64_to_i32(node: node) : nop + in {.i64?, .i64?} then nop + in {.i64?, .i128?} then sign_extend(8, node: node) + in {.i64?, .u8?} then checked ? i64_to_u8(node: node) : nop + in {.i64?, .u16?} then checked ? i64_to_u16(node: node) : nop + in {.i64?, .u32?} then checked ? i64_to_u32(node: node) : nop + in {.i64?, .u64?} then checked ? i64_to_u64(node: node) : nop + in {.i64?, .u128?} then checked ? (sign_extend(8, node: node); i128_to_u128(node: node)) : sign_extend(8, node: node) + in {.i64?, .f32?} then i64_to_f32(node: node) + in {.i64?, .f64?} then i64_to_f64(node: node) + in {.u64?, .i8?} then checked ? u64_to_i8(node: node) : nop + in {.u64?, .i16?} then checked ? u64_to_i16(node: node) : nop + in {.u64?, .i32?} then checked ? u64_to_i32(node: node) : nop + in {.u64?, .i64?} then checked ? u64_to_i64(node: node) : nop + in {.u64?, .i128?} then zero_extend(8, node: node) + in {.u64?, .u8?} then checked ? u64_to_u8(node: node) : nop + in {.u64?, .u16?} then checked ? u64_to_u16(node: node) : nop + in {.u64?, .u32?} then checked ? u64_to_u32(node: node) : nop + in {.u64?, .u64?} then nop + in {.u64?, .u128?} then zero_extend(8, node: node) + in {.u64?, .f32?} then u64_to_f32(node: node) + in {.u64?, .f64?} then u64_to_f64(node: node) + in {.i128?, .i8?} then checked ? i128_to_i8(node: node) : pop(8, node: node) + in {.i128?, .i16?} then checked ? i128_to_i16(node: node) : pop(8, node: node) + in {.i128?, .i32?} then checked ? i128_to_i32(node: node) : pop(8, node: node) + in {.i128?, .i64?} then checked ? i128_to_i64(node: node) : pop(8, node: node) + in {.i128?, .i128?} then nop + in {.i128?, .u8?} then checked ? i128_to_u8(node: node) : pop(8, node: node) + in {.i128?, .u16?} then checked ? i128_to_u16(node: node) : pop(8, node: node) + in {.i128?, .u32?} then checked ? i128_to_u32(node: node) : pop(8, node: node) + in {.i128?, .u64?} then checked ? i128_to_u64(node: node) : pop(8, node: node) + in {.i128?, .u128?} then checked ? i128_to_u128(node: node) : nop + in {.i128?, .f32?} then i128_to_f32(node: node) + in {.i128?, .f64?} then i128_to_f64(node: node) + in {.u128?, .i8?} then checked ? u128_to_i8(node: node) : pop(8, node: node) + in {.u128?, .i16?} then checked ? u128_to_i16(node: node) : pop(8, node: node) + in {.u128?, .i32?} then checked ? u128_to_i32(node: node) : pop(8, node: node) + in {.u128?, .i64?} then checked ? u128_to_i64(node: node) : pop(8, node: node) + in {.u128?, .i128?} then checked ? u128_to_i128(node: node) : nop + in {.u128?, .u8?} then checked ? u128_to_u8(node: node) : pop(8, node: node) + in {.u128?, .u16?} then checked ? u128_to_u16(node: node) : pop(8, node: node) + in {.u128?, .u32?} then checked ? u128_to_u32(node: node) : pop(8, node: node) + in {.u128?, .u64?} then checked ? u128_to_u64(node: node) : pop(8, node: node) + in {.u128?, .u128?} then nop + in {.u128?, .f32?} then u128_to_f32(node: node) + in {.u128?, .f64?} then u128_to_f64(node: node) + in {.f32?, .i8?} then f32_to_f64(node: node); checked ? f64_to_i8(node: node) : f64_to_i64_bang(node: node) + in {.f32?, .i16?} then f32_to_f64(node: node); checked ? f64_to_i16(node: node) : f64_to_i64_bang(node: node) + in {.f32?, .i32?} then f32_to_f64(node: node); checked ? f64_to_i32(node: node) : f64_to_i64_bang(node: node) + in {.f32?, .i64?} then f32_to_f64(node: node); checked ? f64_to_i64(node: node) : f64_to_i64_bang(node: node) + in {.f32?, .i128?} then f32_to_f64(node: node); checked ? f64_to_i128(node: node) : f64_to_i128_bang(node: node) + in {.f32?, .u8?} then f32_to_f64(node: node); checked ? f64_to_u8(node: node) : f64_to_i64_bang(node: node) + in {.f32?, .u16?} then f32_to_f64(node: node); checked ? f64_to_u16(node: node) : f64_to_i64_bang(node: node) + in {.f32?, .u32?} then f32_to_f64(node: node); checked ? f64_to_u32(node: node) : f64_to_i64_bang(node: node) + in {.f32?, .u64?} then f32_to_f64(node: node); checked ? f64_to_u64(node: node) : f64_to_i64_bang(node: node) + in {.f32?, .u128?} then f32_to_f64(node: node); checked ? f64_to_u128(node: node) : f64_to_i128_bang(node: node) + in {.f32?, .f32?} then nop + in {.f32?, .f64?} then f32_to_f64(node: node) + in {.f64?, .i8?} then checked ? f64_to_i8(node: node) : f64_to_i64_bang(node: node) + in {.f64?, .i16?} then checked ? f64_to_i16(node: node) : f64_to_i64_bang(node: node) + in {.f64?, .i32?} then checked ? f64_to_i32(node: node) : f64_to_i64_bang(node: node) + in {.f64?, .i64?} then checked ? f64_to_i64(node: node) : f64_to_i64_bang(node: node) + in {.f64?, .i128?} then checked ? f64_to_i128(node: node) : f64_to_i128_bang(node: node) + in {.f64?, .u8?} then checked ? f64_to_u8(node: node) : f64_to_i64_bang(node: node) + in {.f64?, .u16?} then checked ? f64_to_u16(node: node) : f64_to_i64_bang(node: node) + in {.f64?, .u32?} then checked ? f64_to_u32(node: node) : f64_to_i64_bang(node: node) + in {.f64?, .u64?} then checked ? f64_to_u64(node: node) : f64_to_i64_bang(node: node) + in {.f64?, .u128?} then checked ? f64_to_u128(node: node) : f64_to_i128_bang(node: node) + in {.f64?, .f32?} then checked ? f64_to_f32(node: node) : f64_to_f32_bang(node: node) + in {.f64?, .f64?} then nop end end @@ -772,118 +771,120 @@ class Crystal::Repl::Compiler private def primitive_binary_op_math(left_type : IntegerType, right_type : IntegerType, left_node : ASTNode?, right_node : ASTNode, node : ASTNode, op : String) kind = extend_int(left_type, right_type, left_node, right_node, node) - case kind - when :mixed_64 - if left_type.rank > right_type.rank - # It's UInt64 op X where X is a signed integer - left_node ? left_node.accept(self) : put_self(node: node) - right_node.accept self + if kind.is_a?(MixedNumberKind) + case kind + in .mixed64? + if left_type.rank > right_type.rank + # It's UInt64 op X where X is a signed integer + left_node ? left_node.accept(self) : put_self(node: node) + right_node.accept self + + # TODO: do we need to check for overflow here? + primitive_convert(node, right_type.kind, :i64, checked: false) + + case node.name + when "+" then add_u64_i64(node: node) + when "&+" then add_wrap_i64(node: node) + when "-" then sub_u64_i64(node: node) + when "&-" then sub_wrap_i64(node: node) + when "*" then mul_u64_i64(node: node) + when "&*" then mul_wrap_i64(node: node) + when "^" then xor_i64(node: node) + when "|" then or_i64(node: node) + when "&" then and_i64(node: node) + when "unsafe_shl" then unsafe_shl_i64(node: node) + when "unsafe_shr" then unsafe_shr_u64_i64(node: node) + when "unsafe_div" then unsafe_div_u64_i64(node: node) + when "unsafe_mod" then unsafe_mod_u64_i64(node: node) + else + node.raise "BUG: missing handling of binary #{op} with types #{left_type} and #{right_type}" + end - # TODO: do we need to check for overflow here? - primitive_convert(node, right_type.kind, :i64, checked: false) - - case node.name - when "+" then add_u64_i64(node: node) - when "&+" then add_wrap_i64(node: node) - when "-" then sub_u64_i64(node: node) - when "&-" then sub_wrap_i64(node: node) - when "*" then mul_u64_i64(node: node) - when "&*" then mul_wrap_i64(node: node) - when "^" then xor_i64(node: node) - when "|" then or_i64(node: node) - when "&" then and_i64(node: node) - when "unsafe_shl" then unsafe_shl_i64(node: node) - when "unsafe_shr" then unsafe_shr_u64_i64(node: node) - when "unsafe_div" then unsafe_div_u64_i64(node: node) - when "unsafe_mod" then unsafe_mod_u64_i64(node: node) + kind = NumberKind::U64 else - node.raise "BUG: missing handling of binary #{op} with types #{left_type} and #{right_type}" - end - - kind = :u64 - else - # It's X op UInt64 where X is a signed integer - left_node ? left_node.accept(self) : put_self(node: node) - - # TODO: do we need to check for overflow here? - primitive_convert(node, left_type.kind, :i64, checked: false) - right_node.accept self + # It's X op UInt64 where X is a signed integer + left_node ? left_node.accept(self) : put_self(node: node) + + # TODO: do we need to check for overflow here? + primitive_convert(node, left_type.kind, :i64, checked: false) + right_node.accept self + + case node.name + when "+" then add_i64_u64(node: node) + when "&+" then add_wrap_i64(node: node) + when "-" then sub_i64_u64(node: node) + when "&-" then sub_wrap_i64(node: node) + when "*" then mul_i64_u64(node: node) + when "&*" then mul_wrap_i64(node: node) + when "^" then xor_i64(node: node) + when "|" then or_i64(node: node) + when "&" then and_i64(node: node) + when "unsafe_shl" then unsafe_shl_i64(node: node) + when "unsafe_shr" then unsafe_shr_i64_u64(node: node) + when "unsafe_div" then unsafe_div_i64_u64(node: node) + when "unsafe_mod" then unsafe_mod_i64_u64(node: node) + else + node.raise "BUG: missing handling of binary #{op} with types #{left_type} and #{right_type}" + end - case node.name - when "+" then add_i64_u64(node: node) - when "&+" then add_wrap_i64(node: node) - when "-" then sub_i64_u64(node: node) - when "&-" then sub_wrap_i64(node: node) - when "*" then mul_i64_u64(node: node) - when "&*" then mul_wrap_i64(node: node) - when "^" then xor_i64(node: node) - when "|" then or_i64(node: node) - when "&" then and_i64(node: node) - when "unsafe_shl" then unsafe_shl_i64(node: node) - when "unsafe_shr" then unsafe_shr_i64_u64(node: node) - when "unsafe_div" then unsafe_div_i64_u64(node: node) - when "unsafe_mod" then unsafe_mod_i64_u64(node: node) - else - node.raise "BUG: missing handling of binary #{op} with types #{left_type} and #{right_type}" + kind = NumberKind::I64 end + in .mixed128? + if left_type.rank > right_type.rank + # It's UInt128 op X where X is a signed integer + left_node ? left_node.accept(self) : put_self(node: node) + right_node.accept self + + # TODO: do we need to check for overflow here? + primitive_convert(node, right_type.kind, :i128, checked: false) + + case node.name + when "+" then add_u128_i128(node: node) + when "&+" then add_wrap_i128(node: node) + when "-" then sub_u128_i128(node: node) + when "&-" then sub_wrap_i128(node: node) + when "*" then mul_u128_i128(node: node) + when "&*" then mul_wrap_i128(node: node) + when "^" then xor_i128(node: node) + when "|" then or_i128(node: node) + when "&" then and_i128(node: node) + when "unsafe_shl" then unsafe_shl_i128(node: node) + when "unsafe_shr" then unsafe_shr_u128_i128(node: node) + when "unsafe_div" then unsafe_div_u128_i128(node: node) + when "unsafe_mod" then unsafe_mod_u128_i128(node: node) + else + node.raise "BUG: missing handling of binary #{op} with types #{left_type} and #{right_type}" + end - kind = :i64 - end - when :mixed_128 - if left_type.rank > right_type.rank - # It's UInt128 op X where X is a signed integer - left_node ? left_node.accept(self) : put_self(node: node) - right_node.accept self - - # TODO: do we need to check for overflow here? - primitive_convert(node, right_type.kind, :i128, checked: false) - - case node.name - when "+" then add_u128_i128(node: node) - when "&+" then add_wrap_i128(node: node) - when "-" then sub_u128_i128(node: node) - when "&-" then sub_wrap_i128(node: node) - when "*" then mul_u128_i128(node: node) - when "&*" then mul_wrap_i128(node: node) - when "^" then xor_i128(node: node) - when "|" then or_i128(node: node) - when "&" then and_i128(node: node) - when "unsafe_shl" then unsafe_shl_i128(node: node) - when "unsafe_shr" then unsafe_shr_u128_i128(node: node) - when "unsafe_div" then unsafe_div_u128_i128(node: node) - when "unsafe_mod" then unsafe_mod_u128_i128(node: node) + kind = NumberKind::U128 else - node.raise "BUG: missing handling of binary #{op} with types #{left_type} and #{right_type}" - end - - kind = :u128 - else - # It's X op UInt128 where X is a signed integer - left_node ? left_node.accept(self) : put_self(node: node) - - # TODO: do we need to check for overflow here? - primitive_convert(node, left_type.kind, :i128, checked: false) - right_node.accept self + # It's X op UInt128 where X is a signed integer + left_node ? left_node.accept(self) : put_self(node: node) + + # TODO: do we need to check for overflow here? + primitive_convert(node, left_type.kind, :i128, checked: false) + right_node.accept self + + case node.name + when "+" then add_i128_u128(node: node) + when "&+" then add_wrap_i128(node: node) + when "-" then sub_i128_u128(node: node) + when "&-" then sub_wrap_i128(node: node) + when "*" then mul_i128_u128(node: node) + when "&*" then mul_wrap_i128(node: node) + when "^" then xor_i128(node: node) + when "|" then or_i128(node: node) + when "&" then and_i128(node: node) + when "unsafe_shl" then unsafe_shl_i128(node: node) + when "unsafe_shr" then unsafe_shr_i128_u128(node: node) + when "unsafe_div" then unsafe_div_i128_u128(node: node) + when "unsafe_mod" then unsafe_mod_i128_u128(node: node) + else + node.raise "BUG: missing handling of binary #{op} with types #{left_type} and #{right_type}" + end - case node.name - when "+" then add_i128_u128(node: node) - when "&+" then add_wrap_i128(node: node) - when "-" then sub_i128_u128(node: node) - when "&-" then sub_wrap_i128(node: node) - when "*" then mul_i128_u128(node: node) - when "&*" then mul_wrap_i128(node: node) - when "^" then xor_i128(node: node) - when "|" then or_i128(node: node) - when "&" then and_i128(node: node) - when "unsafe_shl" then unsafe_shl_i128(node: node) - when "unsafe_shr" then unsafe_shr_i128_u128(node: node) - when "unsafe_div" then unsafe_div_i128_u128(node: node) - when "unsafe_mod" then unsafe_mod_i128_u128(node: node) - else - node.raise "BUG: missing handling of binary #{op} with types #{left_type} and #{right_type}" + kind = NumberKind::I128 end - - kind = :i128 end else # Go on @@ -940,9 +941,9 @@ class Crystal::Repl::Compiler end end - private def primitive_binary_op_math(node : ASTNode, kind : Symbol, op : String) + private def primitive_binary_op_math(node : ASTNode, kind : NumberKind, op : String) case kind - when :i32 + when .i32? case op when "+" then add_i32(node: node) when "&+" then add_wrap_i32(node: node) @@ -960,7 +961,7 @@ class Crystal::Repl::Compiler else node.raise "BUG: missing handling of binary #{op} with kind #{kind}" end - when :u32 + when .u32? case op when "+" then add_u32(node: node) when "&+" then add_wrap_i32(node: node) @@ -978,7 +979,7 @@ class Crystal::Repl::Compiler else node.raise "BUG: missing handling of binary #{op} with kind #{kind}" end - when :i64 + when .i64? case op when "+" then add_i64(node: node) when "&+" then add_wrap_i64(node: node) @@ -996,7 +997,7 @@ class Crystal::Repl::Compiler else node.raise "BUG: missing handling of binary #{op} with kind #{kind}" end - when :u64 + when .u64? case op when "+" then add_u64(node: node) when "&+" then add_wrap_i64(node: node) @@ -1014,7 +1015,7 @@ class Crystal::Repl::Compiler else node.raise "BUG: missing handling of binary #{op} with kind #{kind}" end - when :i128 + when .i128? case op when "+" then add_i128(node: node) when "&+" then add_wrap_i128(node: node) @@ -1032,7 +1033,7 @@ class Crystal::Repl::Compiler else node.raise "BUG: missing handling of binary #{op} with kind #{kind}" end - when :u128 + when .u128? case op when "+" then add_u128(node: node) when "&+" then add_wrap_i128(node: node) @@ -1050,7 +1051,7 @@ class Crystal::Repl::Compiler else node.raise "BUG: missing handling of binary #{op} with kind #{kind}" end - when :f32 + when .f32? # TODO: not tested case op when "+" then add_f32(node: node) @@ -1059,7 +1060,7 @@ class Crystal::Repl::Compiler else node.raise "BUG: missing handling of binary #{op} with kind #{kind}" end - when :f64 + when .f64? case op when "+" then add_f64(node: node) when "-" then sub_f64(node: node) @@ -1112,61 +1113,63 @@ class Crystal::Repl::Compiler private def primitive_binary_op_cmp(left_type : IntegerType, right_type : IntegerType, left_node : ASTNode, right_node : ASTNode, node : ASTNode, op : String) kind = extend_int(left_type, right_type, left_node, right_node, node) - case kind - when :mixed_64 - if left_type.rank > right_type.rank - # It's UInt64 == X where X is a signed integer. + if kind.is_a?(MixedNumberKind) + case kind + in .mixed64? + if left_type.rank > right_type.rank + # It's UInt64 == X where X is a signed integer. - # We first extend right to left - left_node.accept self - right_node.accept self + # We first extend right to left + left_node.accept self + right_node.accept self - # TODO: do we need to check for overflow here? - primitive_convert right_node, right_type.kind, :i64, checked: false + # TODO: do we need to check for overflow here? + primitive_convert right_node, right_type.kind, :i64, checked: false - cmp_u64_i64(node: node) - else - # It's X < UInt64 where X is a signed integer - left_node.accept self + cmp_u64_i64(node: node) + else + # It's X < UInt64 where X is a signed integer + left_node.accept self - # TODO: do we need to check for overflow here? - primitive_convert left_node, left_type.kind, :i64, checked: false + # TODO: do we need to check for overflow here? + primitive_convert left_node, left_type.kind, :i64, checked: false - right_node.accept self + right_node.accept self - cmp_i64_u64(node: node) - end - when :mixed_128 - if left_type.rank > right_type.rank - # It's UInt128 == X where X is a signed integer. + cmp_i64_u64(node: node) + end + in .mixed128? + if left_type.rank > right_type.rank + # It's UInt128 == X where X is a signed integer. - # We first extend right to left - left_node.accept self - right_node.accept self + # We first extend right to left + left_node.accept self + right_node.accept self - # TODO: do we need to check for overflow here? - primitive_convert right_node, right_type.kind, :i128, checked: false + # TODO: do we need to check for overflow here? + primitive_convert right_node, right_type.kind, :i128, checked: false - cmp_u128_i128(node: node) - else - # It's X < UInt128 where X is a signed integer - left_node.accept self + cmp_u128_i128(node: node) + else + # It's X < UInt128 where X is a signed integer + left_node.accept self - # TODO: do we need to check for overflow here? - primitive_convert left_node, left_type.kind, :i128, checked: false + # TODO: do we need to check for overflow here? + primitive_convert left_node, left_type.kind, :i128, checked: false - right_node.accept self + right_node.accept self - cmp_i128_u128(node: node) + cmp_i128_u128(node: node) + end end else case kind - when :i32 then cmp_i32(node: node) - when :u32 then cmp_u32(node: node) - when :i64 then cmp_i64(node: node) - when :u64 then cmp_u64(node: node) - when :i128 then cmp_i128(node: node) - when :u128 then cmp_u128(node: node) + when .i32? then cmp_i32(node: node) + when .u32? then cmp_u32(node: node) + when .i64? then cmp_i64(node: node) + when .u64? then cmp_u64(node: node) + when .i128? then cmp_i128(node: node) + when .u128? then cmp_u128(node: node) else node.raise "BUG: missing handling of binary #{op} for #{kind}" end @@ -1202,13 +1205,13 @@ class Crystal::Repl::Compiler primitive_convert(left_node, left_type.kind, right_type.kind, checked: false) right_node.accept self - kind = :f64 + kind = NumberKind::F64 else left_node.accept self right_node.accept self primitive_convert(right_node, right_type.kind, left_type.kind, checked: false) - kind = :f64 + kind = NumberKind::F64 end primitive_binary_op_cmp_float(node, kind, op) @@ -1218,10 +1221,10 @@ class Crystal::Repl::Compiler left_node.raise "BUG: primitive_binary_op_cmp called with #{left_type} #{op} #{right_type}" end - private def primitive_binary_op_cmp_float(node : ASTNode, kind : Symbol, op : String) + private def primitive_binary_op_cmp_float(node : ASTNode, kind : NumberKind, op : String) case kind - when :f32 then cmp_f32(node: node) - when :f64 then cmp_f64(node: node) + when .f32? then cmp_f32(node: node) + when .f64? then cmp_f64(node: node) else node.raise "BUG: missing handling of binary #{op} with kind #{kind}" end @@ -1242,6 +1245,15 @@ class Crystal::Repl::Compiler end end + # interpreter-exclusive integer unions + private enum MixedNumberKind + # Int64 | UInt64 + Mixed64 + + # Int128 | UInt128 + Mixed128 + end + private def extend_int(left_type : IntegerType, right_type : IntegerType, left_node : ASTNode?, right_node : ASTNode, node : ASTNode) # We don't do operations "below" Int32, we always cast the values # to at least Int32. This might be slightly slower, but it allows @@ -1255,7 +1267,7 @@ class Crystal::Repl::Compiler right_node.accept self primitive_convert(right_node, right_type.kind, :i32, checked: false) if right_type.rank < 5 - :i32 + NumberKind::I32 elsif left_type.signed? == right_type.signed? if left_type.rank == right_type.rank left_node ? left_node.accept(self) : put_self(node: node) @@ -1281,9 +1293,9 @@ class Crystal::Repl::Compiler right_node.accept self primitive_convert(right_node, right_type.kind, :i64, checked: false) if right_type.rank < 7 - :i64 + NumberKind::I64 elsif left_type.rank <= 8 && right_type.rank <= 8 - :mixed_64 + MixedNumberKind::Mixed64 elsif left_type.rank <= 9 && right_type.rank <= 9 # If both fit in an Int128 # Convert them to Int128 first, then do the comparison @@ -1293,9 +1305,9 @@ class Crystal::Repl::Compiler right_node.accept self primitive_convert(right_node, right_type.kind, :i128, checked: false) if right_type.rank < 9 - :i128 + NumberKind::I128 else - :mixed_128 + MixedNumberKind::Mixed128 end end @@ -1325,9 +1337,9 @@ class Crystal::Repl::Compiler end case {obj_kind, arg_kind} - when {:f32, :f32} + when {.f32?, .f32?} div_f32(node: node) - when {:f64, :f64} + when {.f64?, .f64?} div_f64(node: node) else node.raise "BUG: missing handling of binary float div with types #{obj_type} and #{arg_type}" diff --git a/src/compiler/crystal/interpreter/value.cr b/src/compiler/crystal/interpreter/value.cr index 02f6881186f4..2b95e146d586 100644 --- a/src/compiler/crystal/interpreter/value.cr +++ b/src/compiler/crystal/interpreter/value.cr @@ -23,34 +23,34 @@ struct Crystal::Repl::Value @pointer.as(Char*).value when IntegerType case type.kind - when :i8 + when .i8? @pointer.as(Int8*).value - when :u8 + when .u8? @pointer.as(UInt8*).value - when :i16 + when .i16? @pointer.as(Int16*).value - when :u16 + when .u16? @pointer.as(UInt16*).value - when :i32 + when .i32? @pointer.as(Int32*).value - when :u32 + when .u32? @pointer.as(UInt32*).value - when :i64 + when .i64? @pointer.as(Int64*).value - when :u64 + when .u64? @pointer.as(UInt64*).value - when :i128 + when .i128? @pointer.as(Int128*).value - when :u128 + when .u128? @pointer.as(UInt128*).value else raise "BUG: missing handling of Repl value for #{type}" end when FloatType case type.kind - when :f32 + when .f32? @pointer.as(Float32*).value - when :f64 + when .f64? @pointer.as(Float64*).value else raise "BUG: missing handling of Repl value for #{type}" @@ -108,34 +108,34 @@ struct Crystal::Repl::Value @pointer.as(Char*).value.inspect(io) when IntegerType case type.kind - when :i8 + when .i8? io << @pointer.as(Int8*).value - when :u8 + when .u8? io << @pointer.as(UInt8*).value - when :i16 + when .i16? io << @pointer.as(Int16*).value - when :u16 + when .u16? io << @pointer.as(UInt16*).value - when :i32 + when .i32? io << @pointer.as(Int32*).value - when :u32 + when .u32? io << @pointer.as(UInt32*).value - when :i64 + when .i64? io << @pointer.as(Int64*).value - when :u64 + when .u64? io << @pointer.as(UInt64*).value - when :i128 + when .i128? io << @pointer.as(Int128*).value - when :u128 + when .u128? io << @pointer.as(UInt128*).value else raise "BUG: missing handling of Repl::Value#to_s(io) for #{type}" end when FloatType case type.kind - when :f32 + when .f32? io << @pointer.as(Float32*).value - when :f64 + when .f64? io << @pointer.as(Float64*).value else raise "BUG: missing handling of Repl::Value#to_s(io) for #{type}" diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr index 95c04ccbc513..b55b020fcc25 100644 --- a/src/compiler/crystal/macros/methods.cr +++ b/src/compiler/crystal/macros/methods.cr @@ -526,16 +526,16 @@ module Crystal def to_number case @kind - when :i8 then @value.to_i8 - when :i16 then @value.to_i16 - when :i32 then @value.to_i32 - when :i64 then @value.to_i64 - when :u8 then @value.to_u8 - when :u16 then @value.to_u16 - when :u32 then @value.to_u32 - when :u64 then @value.to_u64 - when :f32 then @value.to_f32 - when :f64 then @value.to_f64 + when .i8? then @value.to_i8 + when .i16? then @value.to_i16 + when .i32? then @value.to_i32 + when .i64? then @value.to_i64 + when .u8? then @value.to_u8 + when .u16? then @value.to_u16 + when .u32? then @value.to_u32 + when .u64? then @value.to_u64 + when .f32? then @value.to_f32 + when .f64? then @value.to_f64 else raise "Unknown kind: #{@kind}" end diff --git a/src/compiler/crystal/program.cr b/src/compiler/crystal/program.cr index 66a2cd4c5c9d..7fd6f867c29f 100644 --- a/src/compiler/crystal/program.cr +++ b/src/compiler/crystal/program.cr @@ -474,21 +474,20 @@ module Crystal @hash_type.not_nil! end - def type_from_literal_kind(kind) + def type_from_literal_kind(kind : NumberKind) case kind - when :i8 then int8 - when :i16 then int16 - when :i32 then int32 - when :i64 then int64 - when :i128 then int128 - when :u8 then uint8 - when :u16 then uint16 - when :u32 then uint32 - when :u64 then uint64 - when :u128 then uint128 - when :f32 then float32 - when :f64 then float64 - else raise "Invalid node kind: #{kind}" + in .i8? then int8 + in .i16? then int16 + in .i32? then int32 + in .i64? then int64 + in .i128? then int128 + in .u8? then uint8 + in .u16? then uint16 + in .u32? then uint32 + in .u64? then uint64 + in .u128? then uint128 + in .f32? then float32 + in .f64? then float64 end end diff --git a/src/compiler/crystal/semantic/ast.cr b/src/compiler/crystal/semantic/ast.cr index 4ea170e1187f..0d81ef3ec141 100644 --- a/src/compiler/crystal/semantic/ast.cr +++ b/src/compiler/crystal/semantic/ast.cr @@ -40,14 +40,9 @@ module Crystal if number_autocast case self_type = self.type? when IntegerType - case self_type.kind - when :i8, :u8, :i16, :u16, :i32, :u32, :i64, :u64 - true - else - false - end + self_type.kind.bytesize <= 64 when FloatType - self_type.kind == :f32 + self_type.kind.f32? end else false @@ -67,17 +62,17 @@ module Crystal # Float32 mantissa has 23 bits, # Float64 mantissa has 52 bits case self_type.kind - when :i8, :u8, :i16, :u16 + when .i8?, .u8?, .i16?, .u16? # Less than 23 bits, so convertable to Float32 and Float64 without precision loss true - when :i32, :u32 + when .i32?, .u32? # Less than 52 bits, so convertable to Float64 without precision loss - other_type.kind == :f64 + other_type.kind.f64? else false end when {FloatType, FloatType} - self_type.kind == :f32 && other_type.kind == :f64 + self_type.kind.f32? && other_type.kind.f64? else false end diff --git a/src/compiler/crystal/semantic/call.cr b/src/compiler/crystal/semantic/call.cr index 5d6d14cad84a..274e7f4ba662 100644 --- a/src/compiler/crystal/semantic/call.cr +++ b/src/compiler/crystal/semantic/call.cr @@ -496,7 +496,7 @@ class Crystal::Call def tuple_indexer_helper(args, arg_types, owner, instance_type, nilable) arg = args.first - if arg.is_a?(NumberLiteral) && arg.kind == :i32 + if arg.is_a?(NumberLiteral) && arg.kind.i32? index = arg.value.to_i index += instance_type.size if index < 0 in_bounds = (0 <= index < instance_type.size) @@ -509,7 +509,7 @@ class Crystal::Call end elsif arg.is_a?(RangeLiteral) from = arg.from - if from.is_a?(NumberLiteral) && from.kind == :i32 + if from.is_a?(NumberLiteral) && from.kind.i32? from_index = from.value.to_i from_index += instance_type.size if from_index < 0 in_bounds = (0 <= from_index <= instance_type.size) @@ -524,7 +524,7 @@ class Crystal::Call end to = arg.to - if to.is_a?(NumberLiteral) && to.kind == :i32 + if to.is_a?(NumberLiteral) && to.kind.i32? to_index = to.value.to_i to_index += instance_type.size if to_index < 0 to_index = (to_index - (arg.exclusive? ? 1 : 0)).clamp(-1, instance_type.size - 1) diff --git a/src/compiler/crystal/semantic/math_interpreter.cr b/src/compiler/crystal/semantic/math_interpreter.cr index f4501c70fef7..4de9e50080f7 100644 --- a/src/compiler/crystal/semantic/math_interpreter.cr +++ b/src/compiler/crystal/semantic/math_interpreter.cr @@ -8,17 +8,17 @@ struct Crystal::MathInterpreter def interpret(node : NumberLiteral) case node.kind - when :i8, :i16, :i32, :i64, :u8, :u16, :u32, :u64 + when .i8?, .i16?, .i32?, .i64?, .u8?, .u16?, .u32?, .u64? target_kind = @target_type.try(&.kind) || node.kind case target_kind - when :i8 then node.value.to_i8? || node.raise "invalid Int8: #{node.value}" - when :u8 then node.value.to_u8? || node.raise "invalid UInt8: #{node.value}" - when :i16 then node.value.to_i16? || node.raise "invalid Int16: #{node.value}" - when :u16 then node.value.to_u16? || node.raise "invalid UInt16: #{node.value}" - when :i32 then node.value.to_i32? || node.raise "invalid Int32: #{node.value}" - when :u32 then node.value.to_u32? || node.raise "invalid UInt32: #{node.value}" - when :i64 then node.value.to_i64? || node.raise "invalid Int64: #{node.value}" - when :u64 then node.value.to_u64? || node.raise "invalid UInt64: #{node.value}" + when .i8? then node.value.to_i8? || node.raise "invalid Int8: #{node.value}" + when .u8? then node.value.to_u8? || node.raise "invalid UInt8: #{node.value}" + when .i16? then node.value.to_i16? || node.raise "invalid Int16: #{node.value}" + when .u16? then node.value.to_u16? || node.raise "invalid UInt16: #{node.value}" + when .i32? then node.value.to_i32? || node.raise "invalid Int32: #{node.value}" + when .u32? then node.value.to_u32? || node.raise "invalid UInt32: #{node.value}" + when .i64? then node.value.to_i64? || node.raise "invalid Int64: #{node.value}" + when .u64? then node.value.to_u64? || node.raise "invalid UInt64: #{node.value}" else node.raise "enum type must be an integer, not #{target_kind}" end diff --git a/src/compiler/crystal/semantic/top_level_visitor.cr b/src/compiler/crystal/semantic/top_level_visitor.cr index 4d27a6cb1d53..83e7704c572a 100644 --- a/src/compiler/crystal/semantic/top_level_visitor.cr +++ b/src/compiler/crystal/semantic/top_level_visitor.cr @@ -693,7 +693,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor if default_value.is_a?(Crystal::NumberLiteral) enum_base_kind = base_type.kind - if (enum_base_kind == :i32) && (enum_base_kind != default_value.kind) + if (enum_base_kind.i32?) && (enum_base_kind != default_value.kind) default_value.raise "enum value must be an Int32" end end diff --git a/src/compiler/crystal/syntax/ast.cr b/src/compiler/crystal/syntax/ast.cr index 4b01d5c14506..2d830fea1339 100644 --- a/src/compiler/crystal/syntax/ast.cr +++ b/src/compiler/crystal/syntax/ast.cr @@ -230,17 +230,83 @@ module Crystal def_equals_and_hash value end + # The kind of primitive numbers. + enum NumberKind + I8 + I16 + I32 + I64 + I128 + U8 + U16 + U32 + U64 + U128 + F32 + F64 + + def to_s : String + super.downcase + end + + def bytesize + case self + in .i8? then 8 + in .i16? then 16 + in .i32? then 32 + in .i64? then 64 + in .i128? then 128 + in .u8? then 8 + in .u16? then 16 + in .u32? then 32 + in .u64? then 64 + in .u128? then 128 + in .f32? then 32 + in .f64? then 64 + end + end + + def signed_int? + i8? || i16? || i32? || i64? || i128? + end + + def unsigned_int? + u8? || u16? || u32? || u64? || u128? + end + + def float? + f32? || f64? + end + + def self.from_number(number : Number) + case number + when Int8 then I8 + when Int16 then I16 + when Int32 then I32 + when Int64 then I64 + when Int128 then I128 + when UInt8 then U8 + when UInt16 then U16 + when UInt32 then U32 + when UInt64 then U64 + when UInt128 then U128 + when Float32 then F32 + when Float64 then F64 + else raise "Unsupported Number type for NumberLiteral: #{number.class}" + end + end + end + # Any number literal. - # kind stores a symbol indicating which type is it: i32, u16, f32, f64, etc. class NumberLiteral < ASTNode property value : String - property kind : Symbol + property kind : NumberKind - def initialize(@value : String, @kind = :i32) + def initialize(@value : String, @kind : NumberKind = :i32) end def self.new(value : Number) - new(value.to_s, kind_from_number(value)) + new(value.to_s, NumberKind.from_number(value)) end def has_sign? @@ -249,14 +315,14 @@ module Crystal def integer_value case kind - when :i8 then value.to_i8 - when :i16 then value.to_i16 - when :i32 then value.to_i32 - when :i64 then value.to_i64 - when :u8 then value.to_u8 - when :u16 then value.to_u16 - when :u32 then value.to_u32 - when :u64 then value.to_u64 + when .i8? then value.to_i8 + when .i16? then value.to_i16 + when .i32? then value.to_i32 + when .i64? then value.to_i64 + when .u8? then value.to_u8 + when .u16? then value.to_u16 + when .u32? then value.to_u32 + when .u64? then value.to_u64 else raise "Bug: called 'integer_value' for non-integer literal" end @@ -268,24 +334,6 @@ module Crystal def_equals value.to_f64, kind def_hash value, kind - - def self.kind_from_number(number : Number) - case number - when Int8 then :i8 - when Int16 then :i16 - when Int32 then :i32 - when Int64 then :i64 - when Int128 then :i128 - when UInt8 then :u8 - when UInt16 then :u16 - when UInt32 then :u32 - when UInt64 then :u64 - when UInt128 then :u128 - when Float32 then :f32 - when Float64 then :f64 - else raise "Unsupported Number type for NumberLiteral: #{number.class}" - end - end end # A char literal. diff --git a/src/compiler/crystal/syntax/lexer.cr b/src/compiler/crystal/syntax/lexer.cr index bb10d3a5637f..e836d4a9f8c4 100644 --- a/src/compiler/crystal/syntax/lexer.cr +++ b/src/compiler/crystal/syntax/lexer.cr @@ -1566,8 +1566,8 @@ module Crystal end if is_decimal - @token.number_kind = :f64 if suffix_size == 0 - raise("Invalid suffix #{@token.number_kind} for decimal number", @token, (current_pos - start)) unless @token.number_kind.in?(:f32, :f64) + @token.number_kind = NumberKind::F64 if suffix_size == 0 + raise("Invalid suffix #{@token.number_kind} for decimal number", @token, (current_pos - start)) unless @token.number_kind.float? return end @@ -1575,21 +1575,21 @@ module Crystal if suffix_size == 0 raise_value_doesnt_fit_in(negative ? Int64 : UInt64, start, pos_before_suffix) unless @token.value @token.number_kind = case number_size - when 0..9 then :i32 - when 10 then raw_number_string.to_i32? ? :i32 : :i64 - when 11..18 then :i64 + when 0..9 then NumberKind::I32 + when 10 then raw_number_string.to_i32? ? NumberKind::I32 : NumberKind::I64 + when 11..18 then NumberKind::I64 when 19 if raw_number_string.to_i64? - :i64 + NumberKind::I64 elsif negative raise_value_doesnt_fit_in(Int64, start, pos_before_suffix, "i128") else - :u64 + NumberKind::U64 end when 20 raise_value_doesnt_fit_in(Int64, start, pos_before_suffix, "i128") if negative raise_value_doesnt_fit_in(UInt64, start, pos_before_suffix, "i128") unless raw_number_string.to_u64? - :u64 + NumberKind::U64 when 21..38 raise_value_doesnt_fit_in(negative ? Int64 : UInt64, start, pos_before_suffix, "i128") when 39 @@ -1605,50 +1605,50 @@ module Crystal end else case @token.number_kind - when :i8 then gen_check_int_fits_in_size(Int8, :i8, 3, number_size, raw_number_string, start, pos_before_suffix, negative) - when :u8 then gen_check_int_fits_in_size(UInt8, :u8, 3, number_size, raw_number_string, start, pos_before_suffix, negative) - when :i16 then gen_check_int_fits_in_size(Int16, :i16, 5, number_size, raw_number_string, start, pos_before_suffix, negative) - when :u16 then gen_check_int_fits_in_size(UInt16, :u16, 5, number_size, raw_number_string, start, pos_before_suffix, negative) - when :i32 then gen_check_int_fits_in_size(Int32, :i32, 10, number_size, raw_number_string, start, pos_before_suffix, negative) - when :u32 then gen_check_int_fits_in_size(UInt32, :u32, 10, number_size, raw_number_string, start, pos_before_suffix, negative) - when :i64 then gen_check_int_fits_in_size(Int64, :i64, 19, number_size, raw_number_string, start, pos_before_suffix, negative) - when :u64 then gen_check_int_fits_in_size(UInt64, :u64, 20, number_size, raw_number_string, start, pos_before_suffix, negative) - when :i128 then gen_check_int_fits_in_size(Int128, :i128, 39, number_size, raw_number_string, start, pos_before_suffix, negative) - when :u128 then gen_check_int_fits_in_size(UInt128, :u128, 39, number_size, raw_number_string, start, pos_before_suffix, negative) + when .i8? then gen_check_int_fits_in_size(Int8, :i8, 3, number_size, raw_number_string, start, pos_before_suffix, negative) + when .u8? then gen_check_int_fits_in_size(UInt8, :u8, 3, number_size, raw_number_string, start, pos_before_suffix, negative) + when .i16? then gen_check_int_fits_in_size(Int16, :i16, 5, number_size, raw_number_string, start, pos_before_suffix, negative) + when .u16? then gen_check_int_fits_in_size(UInt16, :u16, 5, number_size, raw_number_string, start, pos_before_suffix, negative) + when .i32? then gen_check_int_fits_in_size(Int32, :i32, 10, number_size, raw_number_string, start, pos_before_suffix, negative) + when .u32? then gen_check_int_fits_in_size(UInt32, :u32, 10, number_size, raw_number_string, start, pos_before_suffix, negative) + when .i64? then gen_check_int_fits_in_size(Int64, :i64, 19, number_size, raw_number_string, start, pos_before_suffix, negative) + when .u64? then gen_check_int_fits_in_size(UInt64, :u64, 20, number_size, raw_number_string, start, pos_before_suffix, negative) + when .i128? then gen_check_int_fits_in_size(Int128, :i128, 39, number_size, raw_number_string, start, pos_before_suffix, negative) + when .u128? then gen_check_int_fits_in_size(UInt128, :u128, 39, number_size, raw_number_string, start, pos_before_suffix, negative) end end end - private def consume_number_suffix : Symbol + private def consume_number_suffix : NumberKind case current_char when 'i' case next_char - when '8' then return :i8 + when '8' then return NumberKind::I8 when '1' case next_char - when '2' then return :i128 if next_char == '8' - when '6' then return :i16 + when '2' then return NumberKind::I128 if next_char == '8' + when '6' then return NumberKind::I16 end - when '3' then return :i32 if next_char == '2' - when '6' then return :i64 if next_char == '4' + when '3' then return NumberKind::I32 if next_char == '2' + when '6' then return NumberKind::I64 if next_char == '4' end raise "invalid int suffix" when 'u' case next_char - when '8' then return :u8 + when '8' then return NumberKind::U8 when '1' case next_char - when '2' then return :u128 if next_char == '8' - when '6' then return :u16 + when '2' then return NumberKind::U128 if next_char == '8' + when '6' then return NumberKind::U16 end - when '3' then return :u32 if next_char == '2' - when '6' then return :u64 if next_char == '4' + when '3' then return NumberKind::U32 if next_char == '2' + when '6' then return NumberKind::U64 if next_char == '4' end raise "invalid uint suffix" when 'f' case next_char - when '3' then return :f32 if next_char == '2' - when '6' then return :f64 if next_char == '4' + when '3' then return NumberKind::F32 if next_char == '2' + when '6' then return NumberKind::F64 if next_char == '4' end raise "invalid float suffix" end diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr index 15a7cb52556d..fd9aeb05a32f 100644 --- a/src/compiler/crystal/syntax/parser.cr +++ b/src/compiler/crystal/syntax/parser.cr @@ -5704,7 +5704,7 @@ module Crystal when :INSTANCE_VAR InstanceVar.new(@token.value.to_s) when :NUMBER - raise "expecting an integer offset, not '#{@token}'", @token if @token.number_kind != :i32 + raise "expecting an integer offset, not '#{@token}'", @token if !@token.number_kind.i32? NumberLiteral.new(@token.value.to_s, @token.number_kind) else raise "expecting an instance variable or a integer offset, not '#{@token}'", @token diff --git a/src/compiler/crystal/syntax/to_s.cr b/src/compiler/crystal/syntax/to_s.cr index d08c26434090..9a5cdb751809 100644 --- a/src/compiler/crystal/syntax/to_s.cr +++ b/src/compiler/crystal/syntax/to_s.cr @@ -59,9 +59,9 @@ module Crystal def needs_suffix?(node : NumberLiteral) case node.kind - when :i32 + when .i32? false - when :f64 + when .f64? # If there's no '.' nor 'e', for example in `1_f64`, # we need to include it (#3315) node.value.each_char do |char| diff --git a/src/compiler/crystal/syntax/token.cr b/src/compiler/crystal/syntax/token.cr index ba83014616bc..f919f2f8e734 100644 --- a/src/compiler/crystal/syntax/token.cr +++ b/src/compiler/crystal/syntax/token.cr @@ -4,7 +4,7 @@ module Crystal class Token property type : Symbol property value : Char | String | Symbol | Nil - property number_kind : Symbol + property number_kind : NumberKind property line_number : Int32 property column_number : Int32 property filename : String | VirtualFile | Nil @@ -70,7 +70,7 @@ module Crystal def initialize @type = :EOF - @number_kind = :i32 + @number_kind = NumberKind::I32 @line_number = 0 @column_number = 0 @delimiter_state = DelimiterState.default diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr index 0299aec42338..c35b1693f429 100644 --- a/src/compiler/crystal/types.cr +++ b/src/compiler/crystal/types.cr @@ -1280,9 +1280,9 @@ module Crystal class IntegerType < PrimitiveType getter rank : Int32 - getter kind : Symbol + getter kind : NumberKind - def initialize(program, namespace, name, superclass, bytes, @rank, @kind) + def initialize(program, namespace, name, superclass, bytes, @rank, @kind : NumberKind) super(program, namespace, name, superclass, bytes) end @@ -1304,25 +1304,25 @@ module Crystal def range case kind - when :i8 + when .i8? {Int8::MIN, Int8::MAX} - when :i16 + when .i16? {Int16::MIN, Int16::MAX} - when :i32 + when .i32? {Int32::MIN, Int32::MAX} - when :i64 + when .i64? {Int64::MIN, Int64::MAX} - when :i128 + when .i128? {Int128::MIN, Int128::MAX} - when :u8 + when .u8? {UInt8::MIN, UInt8::MAX} - when :u16 + when .u16? {UInt16::MIN, UInt16::MAX} - when :u32 + when .u32? {UInt32::MIN, UInt32::MAX} - when :u64 + when .u64? {UInt64::MIN, UInt64::MAX} - when :u128 + when .u128? {UInt128::MIN, UInt128::MAX} else raise "Bug: called 'range' for non-integer literal" @@ -1338,14 +1338,14 @@ module Crystal end def kind - @bytes == 4 ? :f32 : :f64 + @bytes == 4 ? NumberKind::F32 : NumberKind::F64 end def range case kind - when :f32 + when .f32? {Float32::MIN, Float32::MAX} - when :f64 + when .f64? {Float64::MIN, Float64::MAX} else raise "Bug: called 'range' for non-float literal"