diff --git a/spec/compiler/codegen/class_spec.cr b/spec/compiler/codegen/class_spec.cr index c6841607a9a6c11618f702bbbbb60c6ae3b24ff3..14b76c7fbbf890e7ac3d16fe656521bb4a9b2173 100755 --- a/spec/compiler/codegen/class_spec.cr +++ b/spec/compiler/codegen/class_spec.cr @@ -34,10 +34,6 @@ describe "Code gen: class" do ").to_i.should eq(42) end - it "codegens byte size of Int32" do - run("Int32.byte_size").to_i.should eq(4) - end - it "codegens recursive type" do run(" class Foo diff --git a/spec/compiler/codegen/sizeof_spec.cr b/spec/compiler/codegen/sizeof_spec.cr new file mode 100644 index 0000000000000000000000000000000000000000..4ce8905390549ea827b2c0c4154382783923d628 --- /dev/null +++ b/spec/compiler/codegen/sizeof_spec.cr @@ -0,0 +1,40 @@ +#!/usr/bin/env bin/crystal --run +require "../../spec_helper" + +describe "Code gen: sizeof" do + it "gets sizeof int" do + run("sizeof(Int32)").to_i.should eq(4) + end + + it "gets sizeof struct" do + run(" + struct Foo + def initialize(@x, @y, @z) + end + end + + Foo.new(1, 2, 3) + + sizeof(Foo) + ").to_i.should eq(12) + end + + it "gets sizeof class" do + run(" + class Foo + def initialize(@x, @y, @z) + end + end + + Foo.new(1, 2, 3) + + sizeof(Foo) + ").to_i.should eq(8) + end + + it "gets sizeof union" do + run(" + sizeof(Int32 | Float64) + ").to_i.should eq(16) + end +end diff --git a/spec/compiler/lexer/lexer_spec.cr b/spec/compiler/lexer/lexer_spec.cr index 6cb3e10e7041585abce45c57ee47f0de743e62af..fa1bbfdae4cf6b0e20fc3c1d2250d87340a8a0c2 100755 --- a/spec/compiler/lexer/lexer_spec.cr +++ b/spec/compiler/lexer/lexer_spec.cr @@ -125,7 +125,7 @@ describe "Lexer" do it_lexes "\t", :SPACE it_lexes "\n", :NEWLINE it_lexes "\n\n\n", :NEWLINE - it_lexes_keywords [:def, :if, :else, :elsif, :end, :true, :false, :class, :module, :include, :extend, :while, :nil, :do, :yield, :return, :unless, :next, :break, :begin, :lib, :fun, :type, :struct, :union, :enum, :macro, :ptr, :out, :require, :case, :when, :then, :of, :abstract, :rescue, :ensure, :is_a?, :alias, :pointerof, :ifdef, :as, :typeof] + it_lexes_keywords [:def, :if, :else, :elsif, :end, :true, :false, :class, :module, :include, :extend, :while, :nil, :do, :yield, :return, :unless, :next, :break, :begin, :lib, :fun, :type, :struct, :union, :enum, :macro, :ptr, :out, :require, :case, :when, :then, :of, :abstract, :rescue, :ensure, :is_a?, :alias, :pointerof, :sizeof, :ifdef, :as, :typeof] it_lexes_idents ["ident", "something", "with_underscores", "with_1", "foo?", "bar!", "foo$123", "foo$bar", "fooBar"] it_lexes_idents ["def?", "if?", "else?", "elsif?", "end?", "true?", "false?", "class?", "while?", "nil?", "do?", "yield?", "return?", "unless?", "next?", "break?", "begin?"] it_lexes_idents ["def!", "if!", "else!", "elsif!", "end!", "true!", "false!", "class!", "while!", "nil!", "do!", "yield!", "return!", "unless!", "next!", "break!", "begin!"] diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr index ea1a4c361309e7b24bf82782c9cbe91bf451392c..df7dd30c15cfbe5c726a894659273358aa1db457 100755 --- a/spec/compiler/parser/parser_spec.cr +++ b/spec/compiler/parser/parser_spec.cr @@ -511,6 +511,8 @@ describe "Parser" do it_parses "a = 1; pointerof(a)", [Assign.new("a".var, 1.int32), PointerOf.new("a".var)] it_parses "pointerof(@a)", PointerOf.new("@a".instance_var) + it_parses "sizeof(X)", SizeOf.new("X".path) + it_parses "foo.is_a?(Const)", IsA.new("foo".call, "Const".path) it_parses "foo.is_a?(Foo | Bar)", IsA.new("foo".call, Union.new(["Foo".path, "Bar".path] of ASTNode)) it_parses "foo.responds_to?(:foo)", RespondsTo.new("foo".call, "foo".symbol) diff --git a/spec/compiler/type_inference/primitives_spec.cr b/spec/compiler/type_inference/primitives_spec.cr index 3d47c457e91c38b7de9fd3eeb16a60f9056f7639..8df36292fca8aa4eb9908bc85d29a8711bc2416f 100755 --- a/spec/compiler/type_inference/primitives_spec.cr +++ b/spec/compiler/type_inference/primitives_spec.cr @@ -49,4 +49,8 @@ describe "Type inference: primitives" do it "types 1 + 2" do assert_type("1 + 2") { int32 } end + + it "types sizeof" do + assert_type("sizeof(Float64)") { int32 } + end end diff --git a/src/compiler/crystal/ast.cr b/src/compiler/crystal/ast.cr index 80ee6c0a4c707d9ddbbd391ca4a043b6cec63999..15625290bc6ee7a49c36210351e50f9837f40a66 100644 --- a/src/compiler/crystal/ast.cr +++ b/src/compiler/crystal/ast.cr @@ -916,6 +916,25 @@ module Crystal end end + class SizeOf < ASTNode + property :exp + + def initialize(@exp) + end + + def accept_children(visitor) + @exp.accept visitor + end + + def ==(other : self) + other.exp == exp + end + + def clone_without_location + SizeOf.new(@exp.clone) + end + end + class IsA < ASTNode property :obj property :const diff --git a/src/compiler/crystal/codegen.cr b/src/compiler/crystal/codegen.cr index acbb22a7f7ae680d239036bc18143216c4e104c7..9319aaa295745cb2e5ef9535f3b40e50f94ed32a 100644 --- a/src/compiler/crystal/codegen.cr +++ b/src/compiler/crystal/codegen.cr @@ -196,8 +196,6 @@ module Crystal codegen_primitive_pointer_realloc node, target_def, call_args when :pointer_add codegen_primitive_pointer_add node, target_def, call_args - when :byte_size - codegen_primitive_byte_size node, target_def, call_args when :struct_new codegen_primitive_struct_new node, target_def, call_args when :struct_set @@ -466,10 +464,6 @@ module Crystal gep call_args[0], call_args[1] end - def codegen_primitive_byte_size(node, target_def, call_args) - llvm_size(type.instance_type) - end - def codegen_primitive_struct_new(node, target_def, call_args) allocate_aggregate (node.type as PointerInstanceType).element_type end @@ -856,6 +850,11 @@ module Crystal false end + def visit(node : SizeOf) + @last = trunc(llvm_size(node.exp.type.instance_type), LLVM::Int32) + false + end + def visit(node : Include) @last = llvm_nil false diff --git a/src/compiler/crystal/lexer.cr b/src/compiler/crystal/lexer.cr index 9a5955aa2285309513fd9b598a13030fb5279d33..e5fdc5a3bfffaef22ba9243448d5001e9345fa3e 100644 --- a/src/compiler/crystal/lexer.cr +++ b/src/compiler/crystal/lexer.cr @@ -688,8 +688,15 @@ module Crystal end scan_ident(start) when 's' - if next_char == 't' && next_char == 'r' && next_char == 'u' && next_char == 'c' && next_char == 't' - return check_ident_or_keyword(:struct, start) + case next_char + when 'i' + if next_char == 'z' && next_char == 'e' && next_char == 'o' && next_char == 'f' + return check_ident_or_keyword(:sizeof, start) + end + when 't' + if next_char == 'r' && next_char == 'u' && next_char == 'c' && next_char == 't' + return check_ident_or_keyword(:struct, start) + end end scan_ident(start) when 't' diff --git a/src/compiler/crystal/parser.cr b/src/compiler/crystal/parser.cr index 6c332e987508876532ef176d2c5f69fb04c9d192..ef5b84b11ff86eccc401b2f52a3091785ff7237d 100644 --- a/src/compiler/crystal/parser.cr +++ b/src/compiler/crystal/parser.cr @@ -677,6 +677,8 @@ module Crystal parse_alias when :pointerof parse_pointerof + when :sizeof + parse_sizeof when :typeof parse_typeof else @@ -2627,6 +2629,21 @@ module Crystal PointerOf.new(exp) end + def parse_sizeof + next_token_skip_space + + check :"(" + next_token_skip_space_or_newline + + exp = parse_single_type + skip_space + + check :")" + next_token_skip_space + + SizeOf.new(exp) + end + def parse_type_def next_token_skip_space_or_newline diff --git a/src/compiler/crystal/primitives.cr b/src/compiler/crystal/primitives.cr index 7429d366bb748f349d9a54c1be875507eb35be28..64e4b861ea95d9a136290600efa795e639b580ad 100644 --- a/src/compiler/crystal/primitives.cr +++ b/src/compiler/crystal/primitives.cr @@ -11,7 +11,6 @@ module Crystal define_reference_primitives define_pointer_primitives define_symbol_primitives - define_type_sizes define_math_primitives end @@ -91,13 +90,6 @@ module Crystal symbol.add_def Def.new("to_s", ([] of Arg), Primitive.new(:symbol_to_s)) end - def define_type_sizes - byte_size = Primitive.new(:byte_size) - [void, self.nil, bool, char, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64, symbol, reference, pointer].each do |t| - t.metaclass.add_def Def.new("byte_size", ([] of Arg), byte_size) - end - end - def define_math_primitives math = types["Math"].metaclass math.add_def Def.new("sqrt", [Arg.new_with_type("value", float32)], Primitive.new(:math_sqrt_float32)) diff --git a/src/compiler/crystal/to_s.cr b/src/compiler/crystal/to_s.cr index d28c0a889226a4ad17a36033233d952ca8b31431..fd845e220e6fec83c23bd2fa9fa581d746e687ef 100644 --- a/src/compiler/crystal/to_s.cr +++ b/src/compiler/crystal/to_s.cr @@ -761,6 +761,13 @@ module Crystal false end + def visit(node : SizeOf) + @str << "sizeof(" + node.exp.accept(self) + @str << ")" + false + end + def visit(node : IsA) node.obj.accept self @str << ".is_a?(" diff --git a/src/compiler/crystal/transformer.cr b/src/compiler/crystal/transformer.cr index 3d53f078f558f300e4474f52e4136209b70c428c..f0ff065f2139306bffcec93a614c949829b50c9b 100644 --- a/src/compiler/crystal/transformer.cr +++ b/src/compiler/crystal/transformer.cr @@ -163,6 +163,11 @@ module Crystal node end + def transform(node : SizeOf) + node.exp = node.exp.transform(self) + node + end + def transform(node : IsA) node.obj = node.obj.transform(self) node.const = node.const.transform(self) diff --git a/src/compiler/crystal/type_inference.cr b/src/compiler/crystal/type_inference.cr index 4fd5d53e331721d7bcf48512ef87a34b955292d9..5ea35964181b5434994688e1727db93266936c29 100644 --- a/src/compiler/crystal/type_inference.cr +++ b/src/compiler/crystal/type_inference.cr @@ -885,8 +885,6 @@ module Crystal node.type = scope when :pointer_add node.type = scope - when :byte_size - node.type = @mod.uint64 when :argc node.type = @mod.int32 when :argv @@ -1070,6 +1068,10 @@ module Crystal node.bind_to node.expressions end + def end_visit(node : SizeOf) + node.type = @mod.int32 + end + def visit(node : Rescue) if node_types = node.types types = node_types.map do |type|