Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 443572e5b4c5
Choose a base ref
...
head repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 69d731bfa73f
Choose a head ref
  • 3 commits
  • 34 files changed
  • 1 contributor

Commits on Jul 27, 2016

  1. Make Slice(T)[...] coerce the numbers to T if T is a number type. F…

    …ixes #3055
    Ary Borenszweig committed Jul 27, 2016
    Copy the full SHA
    64fb781 View commit details
  2. Use Bytes[...] instead of UInt8.slice(...) (a bit shorter and mor…

    …e clear)
    Ary Borenszweig committed Jul 27, 2016
    Copy the full SHA
    28205fa View commit details
  3. Compiler: refactors

    Ary Borenszweig committed Jul 27, 2016
    Copy the full SHA
    69d731b View commit details
Showing with 2,145 additions and 2,907 deletions.
  1. +1 −1 spec/compiler/semantic/alias_spec.cr
  2. +10 −10 spec/compiler/semantic/block_spec.cr
  3. +1 −1 spec/compiler/semantic/const_spec.cr
  4. +1 −1 spec/spec_helper.cr
  5. +9 −9 spec/std/char/reader_spec.cr
  6. +2 −2 spec/std/crypto/md5_spec.cr
  7. +1 −1 spec/std/http/web_socket_spec.cr
  8. +2 −2 spec/std/io/buffered_spec.cr
  9. +2 −2 spec/std/io/io_spec.cr
  10. +6 −0 spec/std/slice_spec.cr
  11. +1 −1 spec/std/string_spec.cr
  12. +68 −0 src/compiler/crystal/codegen/link.cr
  13. +11 −10 src/compiler/crystal/semantic.cr
  14. +116 −124 src/compiler/crystal/semantic/abstract_def_checker.cr
  15. +21 −3 src/compiler/crystal/semantic/ast.cr
  16. +30 −46 src/compiler/crystal/semantic/call.cr
  17. +5 −91 src/compiler/crystal/semantic/class_vars_initializer_visitor.cr
  18. +83 −165 src/compiler/crystal/semantic/instance_vars_initializer_visitor.cr
  19. +206 −133 src/compiler/crystal/semantic/main_visitor.cr
  20. +2 −28 src/compiler/crystal/semantic/normalizer.cr
  21. +89 −97 src/compiler/crystal/semantic/recursive_struct_checker.cr
  22. +62 −309 src/compiler/crystal/semantic/{base_type_visitor.cr → semantic_visitor.cr}
  23. +5 −0 src/compiler/crystal/semantic/to_s.cr
  24. +612 −732 src/compiler/crystal/semantic/top_level_visitor.cr
  25. +1 −21 src/compiler/crystal/semantic/transformer.cr
  26. +516 −518 src/compiler/crystal/semantic/type_declaration_processor.cr
  27. +220 −361 src/compiler/crystal/semantic/type_declaration_visitor.cr
  28. +7 −135 src/compiler/crystal/semantic/type_guess_visitor.cr
  29. +37 −47 src/compiler/crystal/semantic/type_lookup.cr
  30. +0 −18 src/compiler/crystal/syntax/ast.cr
  31. +0 −5 src/compiler/crystal/syntax/to_s.cr
  32. +0 −4 src/compiler/crystal/syntax/transformer.cr
  33. +5 −26 src/compiler/crystal/types.cr
  34. +13 −4 src/slice.cr
2 changes: 1 addition & 1 deletion spec/compiler/semantic/alias_spec.cr
Original file line number Diff line number Diff line change
@@ -223,7 +223,7 @@ describe "Semantic: alias" do
assert_error %(
alias Foo = typeof(1)
),
"can't use typeof inside alias declaration"
"can't use 'typeof' here"
end

it "can use .class in alias (#2835)" do
20 changes: 10 additions & 10 deletions spec/compiler/semantic/block_spec.cr
Original file line number Diff line number Diff line change
@@ -505,7 +505,7 @@ describe "Block inference" do
end
end
),
"can't declare def inside block"
"can't declare def dynamically"
end

it "errors if declares macro inside block" do
@@ -519,7 +519,7 @@ describe "Block inference" do
end
end
),
"can't declare macro inside block"
"can't declare macro dynamically"
end

it "errors if declares fun inside block" do
@@ -547,7 +547,7 @@ describe "Block inference" do
end
end
),
"can't declare class inside block"
"can't declare class dynamically"
end

it "errors if declares module inside block" do
@@ -561,7 +561,7 @@ describe "Block inference" do
end
end
),
"can't declare module inside block"
"can't declare module dynamically"
end

it "errors if declares lib inside block" do
@@ -575,7 +575,7 @@ describe "Block inference" do
end
end
),
"can't declare lib inside block"
"can't declare lib dynamically"
end

it "errors if declares alias inside block" do
@@ -588,7 +588,7 @@ describe "Block inference" do
alias A = Int32
end
),
"can't declare alias inside block"
"can't declare alias dynamically"
end

it "errors if declares include inside block" do
@@ -601,7 +601,7 @@ describe "Block inference" do
include Int32
end
),
"can't include inside block"
"can't include dynamically"
end

it "errors if declares extend inside block" do
@@ -614,7 +614,7 @@ describe "Block inference" do
extend Int32
end
),
"can't extend inside block"
"can't extend dynamically"
end

it "errors if declares enum inside block" do
@@ -629,7 +629,7 @@ describe "Block inference" do
end
end
),
"can't declare enum inside block"
"can't declare enum dynamically"
end

it "allows alias as block fun type" do
@@ -934,7 +934,7 @@ describe "Block inference" do
end
end
),
"can't declare class inside block"
"can't declare class dynamically"
end

it "doesn't assign block variable type to last value (#694)" do
2 changes: 1 addition & 1 deletion spec/compiler/semantic/const_spec.cr
Original file line number Diff line number Diff line change
@@ -221,7 +221,7 @@ describe "Semantic: const" do
A = 1
end
),
"can't declare constant inside block"
"can't declare constant dynamically"
end

it "errors on dynamic constant assignment inside if" do
2 changes: 1 addition & 1 deletion spec/spec_helper.cr
Original file line number Diff line number Diff line change
@@ -179,7 +179,7 @@ def assert_normalize(from, to, flags = nil)
program.flags = flags if flags
normalizer = Normalizer.new(program)
from_nodes = Parser.parse(from)
to_nodes = normalizer.normalize(from_nodes)
to_nodes = program.normalize(from_nodes)
to_nodes.to_s.strip.should eq(to.strip)
end

18 changes: 9 additions & 9 deletions spec/std/char/reader_spec.cr
Original file line number Diff line number Diff line change
@@ -79,35 +79,35 @@ describe "Char::Reader" do
end

it "errors if 0x80 <= first_byte < 0xC2" do
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0x80)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0xC1)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0x80]) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0xC1]) }
end

it "errors if (second_byte & 0xC0) != 0x80" do
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0xd0, 0)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0xd0, 0]) }
end

it "errors if first_byte == 0xE0 && second_byte < 0xA0" do
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0xe0, 0x9F, 0xA0)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0xe0, 0x9F, 0xA0]) }
end

it "errors if first_byte < 0xF0 && (third_byte & 0xC0) != 0x80" do
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0xe0, 0xA0, 0)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0xe0, 0xA0, 0]) }
end

it "errors if first_byte == 0xF0 && second_byte < 0x90" do
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0xf0, 0x8F, 0xA0)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0xf0, 0x8F, 0xA0]) }
end

it "errors if first_byte == 0xF4 && second_byte >= 0x90" do
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0xf4, 0x90, 0xA0)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0xf4, 0x90, 0xA0]) }
end

it "errors if first_byte < 0xF5 && (fourth_byte & 0xC0) != 0x80" do
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0xf4, 0x8F, 0xA0, 0)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0xf4, 0x8F, 0xA0, 0]) }
end

it "errors if first_byte >= 0xF5" do
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new UInt8.slice(0xf5, 0x8F, 0xA0, 0xA0)) }
expect_raises(InvalidByteSequenceError) { Char::Reader.new(String.new Bytes[0xf5, 0x8F, 0xA0, 0xA0]) }
end
end
4 changes: 2 additions & 2 deletions spec/std/crypto/md5_spec.cr
Original file line number Diff line number Diff line change
@@ -7,14 +7,14 @@ describe Crypto::MD5 do
end

it "calculates hash from UInt8 slices" do
s = UInt8.slice(0x66, 0x6f, 0x6f) # f,o,o
s = Bytes[0x66, 0x6f, 0x6f] # f,o,o
Crypto::MD5.hex_digest(s).should eq("acbd18db4cc2f85cedef654fccc4a4d8")
end

it "can take a block" do
Crypto::MD5.hex_digest do |ctx|
ctx.update "f"
ctx.update UInt8.slice(0x6f, 0x6f)
ctx.update Bytes[0x6f, 0x6f]
end.should eq("acbd18db4cc2f85cedef654fccc4a4d8")
end
end
2 changes: 1 addition & 1 deletion spec/std/http/web_socket_spec.cr
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ require "spec"
require "http/web_socket"

private macro packet(*bytes)
UInt8.slice({{*bytes}}).pointer({{bytes.size}})
Bytes[{{*bytes}}].pointer({{bytes.size}})
end

private def assert_text_packet(packet, size, final = false)
4 changes: 2 additions & 2 deletions spec/std/io/buffered_spec.cr
Original file line number Diff line number Diff line change
@@ -130,7 +130,7 @@ describe "IO::Buffered" do
io.read_char.should be_nil

io = MemoryIO.new
io.write UInt8.slice(0xf8, 0xff, 0xff, 0xff)
io.write Bytes[0xf8, 0xff, 0xff, 0xff]
io.rewind
io = IO::BufferedWrapper.new(io)

@@ -139,7 +139,7 @@ describe "IO::Buffered" do
end

io = MemoryIO.new
io.write UInt8.slice(0x81)
io.write_byte 0x81_u8
io.rewind
io = IO::BufferedWrapper.new(io)
expect_raises(InvalidByteSequenceError) do
4 changes: 2 additions & 2 deletions spec/std/io/io_spec.cr
Original file line number Diff line number Diff line change
@@ -283,12 +283,12 @@ describe IO do
io.read_char.should eq('界')
io.read_char.should be_nil

io.write UInt8.slice(0xf8, 0xff, 0xff, 0xff)
io.write Bytes[0xf8, 0xff, 0xff, 0xff]
expect_raises(InvalidByteSequenceError) do
io.read_char
end

io.write UInt8.slice(0x81)
io.write_byte 0x81_u8
expect_raises(InvalidByteSequenceError) do
io.read_char
end
6 changes: 6 additions & 0 deletions spec/std/slice_spec.cr
Original file line number Diff line number Diff line change
@@ -314,6 +314,12 @@ describe "Slice" do
slice[2].should eq("foo")
end

it "does macro [] with numbers (#3055)" do
slice = Bytes[1, 2, 3]
slice.should be_a(Bytes)
slice.to_a.should eq([1, 2, 3])
end

it "uses percent vars in [] macro (#2954)" do
slices = itself(Slice[1, 2], Slice[3])
slices[0].to_a.should eq([1, 2])
2 changes: 1 addition & 1 deletion spec/std/string_spec.cr
Original file line number Diff line number Diff line change
@@ -1888,7 +1888,7 @@ describe "String" do
end

it "decodes with skip" do
bytes = UInt8.slice(186, 195, 140, 202, 199)
bytes = Bytes[186, 195, 140, 202, 199]
String.new(bytes, "GB2312", invalid: :skip).should eq("好是")
end
end
68 changes: 68 additions & 0 deletions src/compiler/crystal/codegen/link.cr
Original file line number Diff line number Diff line change
@@ -10,6 +10,74 @@ module Crystal
def static?
@static
end

def self.from(attr : ASTNode)
name = attr.name
args = attr.args
named_args = attr.named_args

if name != "Link"
attr.raise "illegal attribute for lib, valid attributes are: Link"
end

if args.empty? && !named_args
attr.raise "missing link arguments: must at least specify a library name"
end

lib_name = nil
lib_ldflags = nil
lib_static = false
lib_framework = nil
count = 0

args.each do |arg|
case count
when 0
arg.raise "'lib' link argument must be a String" unless arg.is_a?(StringLiteral)
lib_name = arg.value
when 1
arg.raise "'ldflags' link argument must be a String" unless arg.is_a?(StringLiteral)
lib_ldflags = arg.value
when 2
arg.raise "'static' link argument must be a Bool" unless arg.is_a?(BoolLiteral)
lib_static = arg.value
when 3
arg.raise "'framework' link argument must be a String" unless arg.is_a?(StringLiteral)
lib_framework = arg.value
else
attr.wrong_number_of "link arguments", args.size, "1..4"
end

count += 1
end

named_args.try &.each do |named_arg|
value = named_arg.value

case named_arg.name
when "lib"
named_arg.raise "'lib' link argument already specified" if count > 0
named_arg.raise "'lib' link argument must be a String" unless value.is_a?(StringLiteral)
lib_name = value.value
when "ldflags"
named_arg.raise "'ldflags' link argument already specified" if count > 1
named_arg.raise "'ldflags' link argument must be a String" unless value.is_a?(StringLiteral)
lib_ldflags = value.value
when "static"
named_arg.raise "'static' link argument already specified" if count > 2
named_arg.raise "'static' link argument must be a Bool" unless value.is_a?(BoolLiteral)
lib_static = value.value
when "framework"
named_arg.raise "'framework' link argument already specified" if count > 3
named_arg.raise "'framework' link argument must be a String" unless value.is_a?(StringLiteral)
lib_framework = value.value
else
named_arg.raise "unknown link argument: '#{named_arg.name}' (valid arguments are 'lib', 'ldflags', 'static' and 'framework')"
end
end

new(lib_name, lib_ldflags, lib_static, lib_framework)
end
end

class Program
21 changes: 11 additions & 10 deletions src/compiler/crystal/semantic.cr
Original file line number Diff line number Diff line change
@@ -4,10 +4,10 @@ require "./syntax/visitor"
require "./semantic/*"

# The overall algorithm for semantic analysis of a program is:
# - top level (TopLevelVisitor): declare clases, modules, macros, defs and other top-level stuff
# - top level: declare clases, modules, macros, defs and other top-level stuff
# - new methods: create `new` methods for every `initialize` method
# - check abstract defs (AbstractDefChecker): check that abstract defs are implemented
# - type declarations (TypeDeclarationVisitor): process type declarations like `@x : Int32`
# - type declarations: process type declarations like `@x : Int32`
# - check abstract defs: check that abstract defs are implemented
# - class_vars_initializers (ClassVarsInitializerVisitor): process initializers like `@@x = 1`
# - instance_vars_initializers (InstanceVarsInitializerVisitor): process initializers like `@x = 1`
# - main: process "main" code, calls and method bodies (the whole program).
@@ -40,7 +40,7 @@ module Crystal
processor.check_non_nilable_class_vars_without_initializers

Crystal.timing("Semantic (ivars initializers)", stats) do
visit_instance_vars_initializers(node)
node.accept InstanceVarsInitializerVisitor.new(self)
end
result = Crystal.timing("Semantic (main)", stats) do
visit_main(node)
@@ -50,7 +50,7 @@ module Crystal
cleanup_files
end
Crystal.timing("Semantic (recursive struct check)", stats) do
check_recursive_structs
RecursiveStructChecker.new(self).run
end
result
end
@@ -62,17 +62,18 @@ module Crystal
# where a full semantic of the program is not needed.
def top_level_semantic(node, stats = false)
Crystal.timing("Semantic (top level)", stats) do
visit_top_level(node)
node.accept TopLevelVisitor.new(self)
end
Crystal.timing("Semantic (new)", stats) do
define_new_methods
end
Crystal.timing("Semantic (abstract def check)", stats) do
check_abstract_defs
node, processor = Crystal.timing("Semantic (type declarations)", stats) do
TypeDeclarationProcessor.new(self).process(node)
end
Crystal.timing("Semantic (type declarations)", stats) do
visit_type_declarations(node)
Crystal.timing("Semantic (abstract def check)", stats) do
AbstractDefChecker.new(self).run
end
{node, processor}
end
end
end
Loading