class Crystal::LiteralExpander

Defined in:

compiler/crystal/semantic/literal_expander.cr

Constructors

Macro Summary

Instance Method Summary

Instance methods inherited from class Reference

==(other : self)
==(other : JSON::Any)
==(other : YAML::Any)
==(other)
==
, dup dup, hash(hasher) hash, initialize initialize, inspect(io : IO) : Nil inspect, object_id : UInt64 object_id, pretty_print(pp) : Nil pretty_print, same?(other : Reference) : Bool
same?(other : Nil)
same?
, to_s(io : IO) : Nil to_s

Constructor methods inherited from class Reference

new new, unsafe_construct(address : Pointer, *args, **opts) : self unsafe_construct

Class methods inherited from class Reference

pre_initialize(address : Pointer) pre_initialize

Instance methods inherited from class Object

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other)
===
, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash
hash
, in?(collection : Object) : Bool
in?(*values : Object) : Bool
in?
, inspect(io : IO) : Nil
inspect : String
inspect
, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil!
not_nil!
, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String
to_json
, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil
to_pretty_json
, to_s(io : IO) : Nil
to_s : String
to_s
, to_yaml(io : IO) : Nil
to_yaml : String
to_yaml
, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

Class methods inherited from class Object

from_json(string_or_io : String | IO, root : String)
from_json(string_or_io : String | IO)
from_json
, from_yaml(string_or_io : String | IO) from_yaml

Macros inherited from class Object

class_getter(*names, &block) class_getter, class_getter!(*names) class_getter!, class_getter?(*names, &block) class_getter?, class_property(*names, &block) class_property, class_property!(*names) class_property!, class_property?(*names, &block) class_property?, class_setter(*names) class_setter, def_clone def_clone, def_equals(*fields) def_equals, def_equals_and_hash(*fields) def_equals_and_hash, def_hash(*fields) def_hash, delegate(*methods, to object) delegate, forward_missing_to(delegate) forward_missing_to, getter(*names, &block) getter, getter!(*names) getter!, getter?(*names, &block) getter?, property(*names, &block) property, property!(*names) property!, property?(*names, &block) property?, setter(*names) setter

Constructor Detail

def self.new(program : Program) #

[View source]

Macro Detail

macro check_implicit_obj(type) #

[View source]

Instance Method Detail

def complex_elem_temp_vars(elems : Array, &) #

[View source]
def complex_elem_temp_vars(elems : Array(ASTNode)) #

[View source]
def expand(node : ArrayLiteral) #

Converts an array literal to creating an Array and storing the values:

From:

[] of T

To:

Array(T).new

From:

[1, 2, 3]

To:

ary = ::Array(typeof(1, 2, 3)).unsafe_build(3)
buf = ary.to_unsafe
buf[0] = 1
buf[1] = 2
buf[2] = 3
ary

From:

[1, *exp2, *exp3, 4]

To:

temp1 = exp2
temp2 = exp3
ary = ::Array(typeof(1, ::Enumerable.element_type(temp1), ::Enumerable.element_type(temp2), 4)).new(2)
ary << 1
ary.concat(temp1)
ary.concat(temp2)
ary << 4
ary

[View source]
def expand(node : HashLiteral) #

Converts a hash literal into creating a Hash and assigning keys and values.

Equivalent to a hash-like literal using ::Hash.


[View source]
def expand(node : RegexLiteral) #

From:

/regex/flags

To declaring a constant with this value (if not already declared):

Regex.new("regex", Regex::Options.new(flags))

and then reading from that constant. That is, we cache regex literals to avoid recompiling them all of the time.

Only do this for regex literals that don't contain interpolation. If there's an interpolation, expand to: Regex.new(interpolation, flags)


[View source]
def expand(node : And) #

Convert and to if:

From:

a && b

To:

if temp = a
  b
else
  temp
end

[View source]
def expand(node : Or) #

Convert or to if

From:

a || b

To:

if temp = a
  temp
else
  b
end

[View source]
def expand(node : RangeLiteral) #

Transform a range literal into creating a Range object.

From:

1 .. 3

To:

Range.new(1, 3, true)

From:

1 ... 3

To:

Range.new(1, 3, false)


[View source]
def expand(node : StringInterpolation) #

Convert an interpolation to a call to String.interpolation

From:

"foo#{bar}baz#{qux}"

To:

String.interpolation("foo", bar, "baz", qux)

[View source]
def expand(node : Case) #

Convert a Case into a series of if ... elseif ... end:

From:

case foo
when bar, baz
  1
when bun
  2
else
  3
end

To:

temp = foo
if bar === temp || baz === temp
  1
elsif bun === temp
  2
else
  3
end

But, when the "when" has a constant name, it's transformed to is_a?:

From:

case foo
when Bar
  1
end

To:

temp = foo
if temp.is_a?(Bar)
  1
end

We also take care to expand multiple conds

From:

case {x, y}
when {1, 2}, {3, 4}
  3
end

To:

if (1 === x && y === 2) || (3 === x && 4 === y)
  3
end

[View source]
def expand(node : Select) #

Convert a select statement into a case statement based on Channel.select

From:

select
when foo then body
when x = bar then x.baz
end

To:

%index, %value = ::Channel.select({foo_select_action, bar_select_action})
case %index
when 0
  body
when 1
  x = value.as(typeof(foo))
  x.baz
else
  ::raise("BUG: invalid select index")
end

If there's an else branch, use Channel.non_blocking_select.

From:

select
when foo then body
else qux
end

To:

%index, %value = ::Channel.non_blocking_select({foo_select_action})
case %index
when 0
  body
else
  qux
end

[View source]
def expand(node : MultiAssign) #

Transform a multi assign into many assigns.


[View source]
def expand(node : ProcPointer) #

Expand this:

->foo.bar(X, Y)

To this:

tmp = foo
->(x : X, y : Y) { tmp.bar(x, y) }

Expand this:

->Foo.bar(X, Y)

To this:

->(x : X, y : Y) { Foo.bar(x, y) }

Expand this:

->bar(X, Y)

To this:

->(x : X, y : Y) { bar(x, y) }

in case the implicit self is a class or a virtual class.


[View source]
def expand(node) #

[View source]
def expand_named(node : ArrayLiteral, generic_type : ASTNode | Nil) #

Converts an array-like literal to creating a container and storing the values:

From:

T{1, 2, 3}

To:

ary = T.new
ary << 1
ary << 2
ary << 3
ary

From:

T{1, *exp2, *exp3, 4}

To:

ary = T.new
ary << 1
exp2.each { |v| ary << v }
exp3.each { |v| ary << v }
ary << 4
ary

If T is an uninstantiated generic type, injects a typeof with the element types.


[View source]
def expand_named(node : HashLiteral, generic_type : ASTNode | Nil) #

Converts a hash-like literal into creating a Hash and assigning keys and values:

From:

T{}

To:

T.new

From:

{} of K => V

To:

::Hash(K, V).new

From:

T{a => b, c => d}

To:

hash = T.new
hash[a] = b
hash[c] = d
hash

Or if T is an uninstantiated generic type:

hash = T(typeof(a, c), typeof(b, d)).new
hash[a] = b
hash[c] = d
hash

[View source]
def new_temp_var(key = nil) #

[View source]
def select_action_name(name) #

[View source]
def transform_multi_assign_target(target, value) #

[View source]
def typeof_exp(node : ArrayLiteral, temp_vars : Array(Var | Nil) | Nil = nil) #

[View source]