Skip to content

Commit

Permalink
Macro methods: set type of empty array literal
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored and ysbaddaden committed Mar 12, 2018
1 parent ed0aad8 commit 50aacaa
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 31 deletions.
16 changes: 8 additions & 8 deletions spec/compiler/macro/macro_methods_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,15 @@ describe "macro methods" do
end

it "executes split without arguments" do
assert_macro "", %({{"1 2 3".split}}), [] of ASTNode, %(["1", "2", "3"])
assert_macro "", %({{"1 2 3".split}}), [] of ASTNode, %(["1", "2", "3"] of ::String)
end

it "executes split with argument" do
assert_macro "", %({{"1-2-3".split("-")}}), [] of ASTNode, %(["1", "2", "3"])
assert_macro "", %({{"1-2-3".split("-")}}), [] of ASTNode, %(["1", "2", "3"] of ::String)
end

it "executes split with char argument" do
assert_macro "", %({{"1-2-3".split('-')}}), [] of ASTNode, %(["1", "2", "3"])
assert_macro "", %({{"1-2-3".split('-')}}), [] of ASTNode, %(["1", "2", "3"] of ::String)
end

it "executes strip" do
Expand All @@ -276,11 +276,11 @@ describe "macro methods" do
end

it "executes chars" do
assert_macro "x", %({{x.chars}}), [StringLiteral.new("123")] of ASTNode, %(['1', '2', '3'])
assert_macro "x", %({{x.chars}}), [StringLiteral.new("123")] of ASTNode, %(['1', '2', '3'] of ::Char)
end

it "executes lines" do
assert_macro "x", %({{x.lines}}), [StringLiteral.new("1\n2\n3")] of ASTNode, %(["1", "2", "3"])
assert_macro "x", %({{x.lines}}), [StringLiteral.new("1\n2\n3")] of ASTNode, %(["1", "2", "3"] of ::String)
end

it "executes size" do
Expand Down Expand Up @@ -999,9 +999,9 @@ describe "macro methods" do
end

it "executes options" do
assert_macro "", %({{ //.options }}), [] of ASTNode, %([])
assert_macro "", %({{ /a/i.options }}), [] of ASTNode, %([:i])
assert_macro "", %({{ /re/mix.options }}), [] of ASTNode, %([:i, :m, :x])
assert_macro "", %({{ //.options }}), [] of ASTNode, %([] of ::Symbol)
assert_macro "", %({{ /a/i.options }}), [] of ASTNode, %([:i] of ::Symbol)
assert_macro "", %({{ /re/mix.options }}), [] of ASTNode, %([:i, :m, :x] of ::Symbol)
end
end

Expand Down
78 changes: 57 additions & 21 deletions src/compiler/crystal/macros/methods.cr
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ module Crystal
when "capitalize"
interpret_argless_method(method, args) { StringLiteral.new(@value.capitalize) }
when "chars"
interpret_argless_method(method, args) { ArrayLiteral.map(@value.chars) { |value| CharLiteral.new(value) } }
interpret_argless_method(method, args) { ArrayLiteral.map(@value.chars, Path.global("Char")) { |value| CharLiteral.new(value) } }
when "chomp"
interpret_argless_method(method, args) { StringLiteral.new(@value.chomp) }
when "downcase"
Expand Down Expand Up @@ -651,11 +651,11 @@ module Crystal
when "size"
interpret_argless_method(method, args) { NumberLiteral.new(@value.size) }
when "lines"
interpret_argless_method(method, args) { ArrayLiteral.map(@value.lines) { |value| StringLiteral.new(value) } }
interpret_argless_method(method, args) { ArrayLiteral.map(@value.lines, Path.global("String")) { |value| StringLiteral.new(value) } }
when "split"
case args.size
when 0
ArrayLiteral.map(@value.split) { |value| StringLiteral.new(value) }
ArrayLiteral.map(@value.split, Path.global("String")) { |value| StringLiteral.new(value) }
when 1
first_arg = args.first
case first_arg
Expand All @@ -667,7 +667,7 @@ module Crystal
splitter = first_arg.to_s
end

ArrayLiteral.map(@value.split(splitter)) { |value| StringLiteral.new(value) }
ArrayLiteral.map(@value.split(splitter), Path.global("String")) { |value| StringLiteral.new(value) }
else
wrong_number_of_arguments "StringLiteral#split", args.size, "0..1"
end
Expand Down Expand Up @@ -1036,7 +1036,7 @@ module Crystal
options << :i if @options.ignore_case?
options << :m if @options.multiline?
options << :x if @options.extended?
ArrayLiteral.map(options) { |opt| SymbolLiteral.new(opt.to_s) }
ArrayLiteral.map(options, Path.global("Symbol")) { |opt| SymbolLiteral.new(opt.to_s) }
end
else
super
Expand Down Expand Up @@ -1536,24 +1536,37 @@ module Crystal
def self.type_vars(type)
if type.is_a?(GenericClassInstanceType)
if type.is_a?(TupleInstanceType)
ArrayLiteral.map(type.tuple_types) do |tuple_type|
TypeNode.new(tuple_type)
if type.tuple_types.empty?
empty_no_return_array
else
ArrayLiteral.map(type.tuple_types) do |tuple_type|
TypeNode.new(tuple_type)
end
end
else
ArrayLiteral.map(type.type_vars.values) do |type_var|
if type_var.is_a?(Var)
TypeNode.new(type_var.type)
else
type_var
if type.type_vars.empty?
empty_no_return_array
else
ArrayLiteral.map(type.type_vars.values) do |type_var|
if type_var.is_a?(Var)
TypeNode.new(type_var.type)
else
type_var
end
end
end
end
elsif type.is_a?(GenericType)
ArrayLiteral.map(type.as(GenericType).type_vars) do |type_var|
MacroId.new(type_var)
t = type.as(GenericType)
if t.type_vars.empty?
empty_no_return_array
else
ArrayLiteral.map(t.type_vars) do |type_var|
MacroId.new(type_var)
end
end
else
ArrayLiteral.new
empty_no_return_array
end
end

Expand All @@ -1563,12 +1576,17 @@ module Crystal
MetaVar.new(name[1..-1], ivar.type)
end
else
ArrayLiteral.new
empty_no_return_array
end
end

def self.ancestors(type)
ArrayLiteral.map(type.ancestors) { |ancestor| TypeNode.new(ancestor) }
ancestors = type.ancestors
if ancestors.empty?
empty_no_return_array
else
ArrayLiteral.map(type.ancestors) { |ancestor| TypeNode.new(ancestor) }
end
end

def self.superclass(type)
Expand All @@ -1579,11 +1597,21 @@ module Crystal
end

def self.subclasses(type)
ArrayLiteral.map(type.devirtualize.subclasses) { |subtype| TypeNode.new(subtype) }
subclasses = type.devirtualize.subclasses
if subclasses.empty?
empty_no_return_array
else
ArrayLiteral.map(subclasses) { |subtype| TypeNode.new(subtype) }
end
end

def self.all_subclasses(type)
ArrayLiteral.map(type.devirtualize.all_subclasses) { |subtype| TypeNode.new(subtype) }
subclasses = type.devirtualize.all_subclasses
if subclasses.empty?
empty_no_return_array
else
ArrayLiteral.map(subclasses) { |subtype| TypeNode.new(subtype) }
end
end

def self.union_types(type)
Expand All @@ -1592,8 +1620,12 @@ module Crystal
end

def self.constants(type)
names = type.types.map { |name, member_type| MacroId.new(name).as(ASTNode) }
ArrayLiteral.new names
if type.types.empty?
empty_no_return_array
else
names = type.types.map { |name, member_type| MacroId.new(name).as(ASTNode) }
ArrayLiteral.new names
end
end

def self.has_constant?(type, name)
Expand Down Expand Up @@ -2150,6 +2182,10 @@ private def macro_raise(node, args, interpreter)
node.raise msg, exception_type: Crystal::MacroRaiseException
end

private def empty_no_return_array
Crystal::ArrayLiteral.new(of: Crystal::Path.global("NoReturn"))
end

def filter(object, klass, block, interpreter, keep = true)
block_arg = block.args.first?

Expand Down
4 changes: 2 additions & 2 deletions src/compiler/crystal/syntax/ast.cr
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ module Crystal
def initialize(@elements = [] of ASTNode, @of = nil, @name = nil)
end

def self.map(values)
new(values.map { |value| (yield value).as(ASTNode) })
def self.map(values, of = nil)
new(values.map { |value| (yield value).as(ASTNode) }, of: of)
end

def accept_children(visitor)
Expand Down

0 comments on commit 50aacaa

Please sign in to comment.