diff --git a/Makefile b/Makefile index 03a1aafd34ff..7e8070d16921 100644 --- a/Makefile +++ b/Makefile @@ -139,31 +139,9 @@ llvm_ext: $(LLVM_EXT_OBJ) format: ## Format sources ./bin/crystal tool format$(if $(check), --check) src spec samples scripts -generate_data: ## Run generator scripts for Unicode, SSL config, ... (usually with `-B`/`--always-make` flag) - -generate_data: spec/std/string/graphemes_break_spec.cr -spec/std/string/graphemes_break_spec.cr: scripts/generate_grapheme_break_specs.cr - $(CRYSTAL) run $< - -generate_data: src/string/grapheme/properties.cr -src/string/grapheme/properties.cr: scripts/generate_grapheme_properties.cr - $(CRYSTAL) run $< - -generate_data: src/openssl/ssl/defaults.cr -src/openssl/ssl/defaults.cr: scripts/generate_ssl_server_defaults.cr - $(CRYSTAL) run $< - -generate_data: src/unicode/data.cr -src/unicode/data.cr: scripts/generate_unicode_data.cr - $(CRYSTAL) run $< - -generate_data: src/crystal/system/win32/zone_names.cr -src/crystal/system/win32/zone_names.cr: scripts/generate_windows_zone_names.cr - $(CRYSTAL) run $< - -generate_data: src/html/entities.cr -src/html/entities.cr: scripts/generate_html_entities.cr scripts/html_entities.ecr - $(CRYSTAL) run $< +.PHONY: generate_data +generate_data: ## Run generator scripts for Unicode, SSL config, ... + $(MAKE) -B -f scripts/generate_data.mk .PHONY: install install: $(O)/crystal man/crystal.1.gz ## Install the compiler at DESTDIR diff --git a/Makefile.win b/Makefile.win index 595a26f5fd00..e2b18741657e 100644 --- a/Makefile.win +++ b/Makefile.win @@ -35,7 +35,7 @@ static ?= ## Enable static linking target ?= ## Cross-compilation target interpreter ?= ## Enable interpreter feature check ?= ## Enable only check when running format -order ?= ## Enable order for spec execution (values: "default" | "random" | seed number) +order ?=random ## Enable order for spec execution (values: "default" | "random" | seed number) MAKEFLAGS += --no-builtin-rules .SUFFIXES: @@ -141,31 +141,9 @@ llvm_ext: $(LLVM_EXT_OBJ) format: ## Format sources .\bin\crystal tool format$(if $(check), --check) src spec samples scripts -generate_data: ## Run generator scripts for Unicode, SSL config, ... (usually with `-B`/`--always-make` flag) - -generate_data: spec\std\string\graphemes_break_spec.cr -spec\std\string\graphemes_break_spec.cr: scripts\generate_grapheme_break_specs.cr - $(CRYSTAL) run $< - -generate_data: src\string\grapheme\properties.cr -src\string\grapheme\properties.cr: scripts\generate_grapheme_properties.cr - $(CRYSTAL) run $< - -generate_data: src\openssl\ssl\defaults.cr -src\openssl\ssl\defaults.cr: scripts\generate_ssl_server_defaults.cr - $(CRYSTAL) run $< - -generate_data: src\unicode\data.cr -src\unicode\data.cr: scripts\generate_unicode_data.cr - $(CRYSTAL) run $< - -generate_data: src\crystal\system\win32\zone_names.cr -src\crystal\system\win32\zone_names.cr: scripts\generate_windows_zone_names.cr - $(CRYSTAL) run $< - -generate_data: src\html\entities.cr -src\html\entities.cr: scripts\generate_html_entities.cr scripts\html_entities.ecr - $(CRYSTAL) run $< +.PHONY: generate_data +generate_data: ## Run generator scripts for Unicode, SSL config, ... + $(MAKE) -B -f scripts/generate_data.mk .PHONY: install install: $(O)\crystal.exe ## Install the compiler at prefix diff --git a/scripts/generate_data.mk b/scripts/generate_data.mk new file mode 100644 index 000000000000..ad04f0fd0c82 --- /dev/null +++ b/scripts/generate_data.mk @@ -0,0 +1,37 @@ + +## Run all data generators +## $ make -f scripts/generate_data.mk + +ifeq ($(OS),Windows_NT) + BIN_CRYSTAL=bin\crystal +else + BIN_CRYSTAL=bin/crystal +endif + +.PHONY: all +all: ## Run all generators + $(BIN_CRYSTAL) run scripts/generate_grapheme_break_specs.cr + $(BIN_CRYSTAL) run scripts/generate_grapheme_properties.cr + $(BIN_CRYSTAL) run scripts/generate_ssl_server_defaults.cr + $(BIN_CRYSTAL) run scripts/generate_unicode_data.cr + $(BIN_CRYSTAL) run scripts/generate_windows_zone_names.cr + $(BIN_CRYSTAL) run scripts/generate_html_entities.cr + +ifneq ($(OS),Windows_NT) +.PHONY: help +help: ## Show this help + @echo + @printf '\033[34mtargets:\033[0m\n' + @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) |\ + sort |\ + awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' + @echo + @printf '\033[34moptional variables:\033[0m\n' + @grep -hE '^[a-zA-Z_-]+ \?=.*?## .*$$' $(MAKEFILE_LIST) |\ + sort |\ + awk 'BEGIN {FS = " \\?=.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' + @echo + @printf '\033[34mrecipes:\033[0m\n' + @grep -hE '^##.*$$' $(MAKEFILE_LIST) |\ + awk 'BEGIN {FS = "## "}; /^## [a-zA-Z_-]/ {printf " \033[36m%s\033[0m\n", $$2}; /^## / {printf " %s\n", $$2}' +endif diff --git a/spec/compiler/interpreter/sizeof_spec.cr b/spec/compiler/interpreter/sizeof_spec.cr index 4eb5216b28e5..4c52247b9687 100644 --- a/spec/compiler/interpreter/sizeof_spec.cr +++ b/spec/compiler/interpreter/sizeof_spec.cr @@ -7,4 +7,16 @@ describe Crystal::Repl::Interpreter do interpret("sizeof(typeof(1))").should eq(4) end end + + context "instance_sizeof" do + it "interprets instance_sizeof typeof" do + interpret(<<-CRYSTAL).should eq(16) + class Foo + @x = 0_i64 + end + + instance_sizeof(typeof(Foo.new)) + CRYSTAL + end + end end diff --git a/spec/compiler/semantic/c_type_spec.cr b/spec/compiler/semantic/c_type_spec.cr index dd034ae231e7..cb2e367a9593 100644 --- a/spec/compiler/semantic/c_type_spec.cr +++ b/spec/compiler/semantic/c_type_spec.cr @@ -2,24 +2,50 @@ require "../../spec_helper" describe "Semantic: type" do it "can call methods of original type" do - assert_type(" + assert_type(<<-CRYSTAL, inject_primitives: true) { uint64 } lib Lib type X = Void* fun foo : X end Lib.foo.address - ", inject_primitives: true) { uint64 } + CRYSTAL end it "can call methods of parent type" do - assert_error(" + assert_error(<<-CRYSTAL, "undefined method 'baz'") lib Lib type X = Void* fun foo : X end Lib.foo.baz - ", "undefined method 'baz'") + CRYSTAL + end + + it "can access instance variables of original type" do + assert_type(<<-CRYSTAL) { int32 } + lib Lib + struct X + x : Int32 + end + + type Y = X + fun foo : Y + end + + Lib.foo.@x + CRYSTAL + end + + it "errors if original type doesn't support instance variables" do + assert_error(<<-CRYSTAL, "can't use instance variables inside primitive types (at Int32)") + lib Lib + type X = Int32 + fun foo : X + end + + Lib.foo.@x + CRYSTAL end end diff --git a/spec/std/big/big_int_spec.cr b/spec/std/big/big_int_spec.cr index 8a86939efbac..68eba643a571 100644 --- a/spec/std/big/big_int_spec.cr +++ b/spec/std/big/big_int_spec.cr @@ -283,6 +283,34 @@ describe "BigInt" do -5.to_big_i.remainder(-3).should eq(-2) end + it "#bit" do + x = 123.to_big_i + x.bit(-10.to_big_i ** 99).should eq(0) + x.bit(-(2.to_big_i ** 64)).should eq(0) + x.bit(-1).should eq(0) + x.bit(0).should eq(1) + x.bit(2).should eq(0) + x.bit(3).should eq(1) + x.bit(6).should eq(1) + x.bit(7).should eq(0) + x.bit(64).should eq(0) + x.bit(2.to_big_i ** 64).should eq(0) + x.bit(10.to_big_i ** 99).should eq(0) + + x = ~(123.to_big_i) + x.bit(-10.to_big_i ** 99).should eq(0) + x.bit(-(2.to_big_i ** 64)).should eq(0) + x.bit(-1).should eq(0) + x.bit(0).should eq(0) + x.bit(2).should eq(1) + x.bit(3).should eq(0) + x.bit(6).should eq(0) + x.bit(7).should eq(1) + x.bit(64).should eq(1) + x.bit(2.to_big_i ** 64).should eq(1) + x.bit(10.to_big_i ** 99).should eq(1) + end + it "does bitwise and" do (123.to_big_i & 321).should eq(65) (BigInt.new("96238761238973286532") & 86325735648).should eq(69124358272) diff --git a/spec/std/file_spec.cr b/spec/std/file_spec.cr index 53d28bdcee4e..3c020fee36a1 100644 --- a/spec/std/file_spec.cr +++ b/spec/std/file_spec.cr @@ -941,7 +941,7 @@ describe "File" do pending! "Spec cannot run as superuser" end {% end %} - expect_raises(File::AccessDeniedError) { File.read(path) } + expect_raises(File::AccessDeniedError, "Error opening file with mode 'r': '#{path.inspect_unquoted}'") { File.read(path) } end end {% end %} @@ -958,7 +958,7 @@ describe "File" do pending! "Spec cannot run as superuser" end {% end %} - expect_raises(File::AccessDeniedError) { File.write(path, "foo") } + expect_raises(File::AccessDeniedError, "Error opening file with mode 'w': '#{path.inspect_unquoted}'") { File.write(path, "foo") } end end diff --git a/spec/std/string_spec.cr b/spec/std/string_spec.cr index 8a372a370677..178fa81a172c 100644 --- a/spec/std/string_spec.cr +++ b/spec/std/string_spec.cr @@ -2343,6 +2343,33 @@ describe "String" do "foo".matches?(/bar/).should eq(false) end + it "#matches_full?" do + pending! if {{ Regex::Engine.resolve.name == "Regex::PCRE" }} + "foo".matches_full?(/foo/).should be_true + "fooo".matches_full?(/foo/).should be_false + "ofoo".matches_full?(/foo/).should be_false + "pattern".matches_full?(/(\A)?pattern(\z)?/).should be_true + "_pattern_".matches_full?(/(\A)?pattern(\z)?/).should be_false + end + + it "#match_full" do + pending! if {{ Regex::Engine.resolve.name == "Regex::PCRE" }} + "foo".match_full(/foo/).not_nil![0].should eq "foo" + "fooo".match_full(/foo/).should be_nil + "ofoo".match_full(/foo/).should be_nil + "pattern".match_full(/(\A)?pattern(\z)?/).not_nil![0].should eq "pattern" + "_pattern_".match_full(/(\A)?pattern(\z)?/).should be_nil + end + + it "#match_full!" do + pending! if {{ Regex::Engine.resolve.name == "Regex::PCRE" }} + "foo".match_full!(/foo/).not_nil![0].should eq "foo" + expect_raises(Regex::Error) { "fooo".match_full!(/foo/) } + expect_raises(Regex::Error) { "ofoo".match_full!(/foo/) } + "pattern".match_full!(/(\A)?pattern(\z)?/).not_nil![0].should eq "pattern" + expect_raises(Regex::Error) { "_pattern_".match_full!(/(\A)?pattern(\z)?/) } + end + it "has size (same as size)" do "ใในใ".size.should eq(3) end diff --git a/src/big/big_int.cr b/src/big/big_int.cr index b0530c7b7592..e6b5f0214297 100644 --- a/src/big/big_int.cr +++ b/src/big/big_int.cr @@ -385,6 +385,12 @@ struct BigInt < Int BigInt.new { |mpz| LibGMP.com(mpz, self) } end + def bit(bit : Int) + return 0 if bit < 0 + return self < 0 ? 1 : 0 if bit > LibGMP::BitcntT::MAX + LibGMP.tstbit(self, LibGMP::BitcntT.new!(bit)) + end + def &(other : BigInt) : BigInt BigInt.new { |mpz| LibGMP.and(mpz, self, other) } end diff --git a/src/big/lib_gmp.cr b/src/big/lib_gmp.cr index 9caf408f1494..3cae0de64b77 100644 --- a/src/big/lib_gmp.cr +++ b/src/big/lib_gmp.cr @@ -116,6 +116,8 @@ lib LibGMP fun xor = __gmpz_xor(rop : MPZ*, op1 : MPZ*, op2 : MPZ*) fun com = __gmpz_com(rop : MPZ*, op : MPZ*) + fun tstbit = __gmpz_tstbit(op : MPZ*, bit_index : BitcntT) : Int + fun fdiv_q_2exp = __gmpz_fdiv_q_2exp(q : MPZ*, n : MPZ*, b : BitcntT) fun mul_2exp = __gmpz_mul_2exp(rop : MPZ*, op1 : MPZ*, op2 : BitcntT) diff --git a/src/compiler/crystal/interpreter/compiler.cr b/src/compiler/crystal/interpreter/compiler.cr index 1faf5db32bb6..03d7430a0fe6 100644 --- a/src/compiler/crystal/interpreter/compiler.cr +++ b/src/compiler/crystal/interpreter/compiler.cr @@ -1422,6 +1422,14 @@ class Crystal::Repl::Compiler < Crystal::Visitor false end + def visit(node : InstanceSizeOf) + return false unless @wants_value + + put_i32 inner_instance_sizeof_type(node.exp), node: node + + false + end + def visit(node : TypeNode) return false unless @wants_value @@ -3361,25 +3369,8 @@ class Crystal::Repl::Compiler < Crystal::Visitor @instructions.instructions.size end - private def aligned_sizeof_type(node : ASTNode) : Int32 - @context.aligned_sizeof_type(node) - end - - private def aligned_sizeof_type(type : Type?) : Int32 - @context.aligned_sizeof_type(type) - end - - private def inner_sizeof_type(node : ASTNode) : Int32 - @context.inner_sizeof_type(node) - end - - private def inner_sizeof_type(type : Type?) : Int32 - @context.inner_sizeof_type(type) - end - - private def aligned_instance_sizeof_type(type : Type) : Int32 - @context.aligned_instance_sizeof_type(type) - end + private delegate inner_sizeof_type, aligned_sizeof_type, + inner_instance_sizeof_type, aligned_instance_sizeof_type, to: @context private def ivar_offset(type : Type, name : String) : Int32 if type.extern_union? diff --git a/src/compiler/crystal/interpreter/context.cr b/src/compiler/crystal/interpreter/context.cr index e91b615713f2..268d67448125 100644 --- a/src/compiler/crystal/interpreter/context.cr +++ b/src/compiler/crystal/interpreter/context.cr @@ -316,7 +316,19 @@ class Crystal::Repl::Context end def aligned_instance_sizeof_type(type : Type) : Int32 - align(@program.instance_size_of(type.sizeof_type).to_i32) + align(inner_instance_sizeof_type(type)) + end + + def inner_instance_sizeof_type(node : ASTNode) : Int32 + inner_instance_sizeof_type(node.type?) + end + + def inner_instance_sizeof_type(type : Type) : Int32 + @program.instance_size_of(type.sizeof_type).to_i32 + end + + def inner_instance_sizeof_type(type : Nil) : Int32 + 0 end def offset_of(type : Type, index : Int32) : Int32 diff --git a/src/compiler/crystal/tools/doc/html/type.html b/src/compiler/crystal/tools/doc/html/type.html index cd8115e74f5c..10c7e51fedd3 100644 --- a/src/compiler/crystal/tools/doc/html/type.html +++ b/src/compiler/crystal/tools/doc/html/type.html @@ -95,8 +95,8 @@