Newer
Older
Ary Borenszweig
committed
#!/usr/bin/env bin/crystal --run
require "../../spec_helper"
describe "MacroExpander" do
it "expands simple macro" do
assert_macro "", "1 + 2", [] of ASTNode, "1 + 2"
end
it "expands macro with string sustitution" do
Ary Borenszweig
committed
assert_macro "x", "{{x}}", [StringLiteral.new("hello")] of ASTNode, %("hello")
Ary Borenszweig
committed
end
it "expands macro with symbol sustitution" do
Ary Borenszweig
committed
assert_macro "x", "{{x}}", [SymbolLiteral.new("hello")] of ASTNode, ":hello"
Ary Borenszweig
committed
end
it "expands macro with argument-less call sustitution" do
assert_macro "x", "{{x}}", [Call.new(nil, "hello")] of ASTNode, "hello"
end
it "expands macro with boolean" do
assert_macro "", "{{true}}", [] of ASTNode, "true"
end
it "expands macro with integer" do
assert_macro "", "{{1}}", [] of ASTNode, "1"
end
it "expands macro with char" do
assert_macro "", "{{'a'}}", [] of ASTNode, "'a'"
end
it "expands macro with string" do
Ary Borenszweig
committed
assert_macro "", %({{"hello"}}), [] of ASTNode, %("hello")
Ary Borenszweig
committed
end
it "expands macro with symbol" do
Ary Borenszweig
committed
assert_macro "", %({{:foo}}), [] of ASTNode, %(:foo)
Ary Borenszweig
committed
end
it "expands macro with nil" do
assert_macro "", %({{nil}}), [] of ASTNode, %(nil)
end
it "expands macro with array" do
assert_macro "", %({{[1, 2, 3]}}), [] of ASTNode, %([1, 2, 3])
end
it "expands macro with hash" do
assert_macro "", %({{{a: 1, b: 2}}}), [] of ASTNode, "{:a => 1, :b => 2}"
end
it "expands macro with tuple" do
assert_macro "", %({{{1, 2, 3}}}), [] of ASTNode, %({1, 2, 3})
end
it "expands macro with range" do
assert_macro "", %({{1..3}}), [] of ASTNode, %(1..3)
end
Ary Borenszweig
committed
it "expands macro with string interpolation" do
Ary Borenszweig
committed
assert_macro "", "{{ \"hello\#{1 == 1}world\" }}", [] of ASTNode, %("hellotrueworld")
Ary Borenszweig
committed
end
Ary Borenszweig
committed
it "expands macro with var sustitution" do
assert_macro "x", "{{x}}", [Var.new("hello")] of ASTNode, "hello"
end
it "expands macro with or (1)" do
assert_macro "x", "{{x || 1}}", [NilLiteral.new] of ASTNode, "1"
end
it "expands macro with or (2)" do
assert_macro "x", "{{x || 1}}", [Var.new("hello")] of ASTNode, "hello"
end
it "expands macro with and (1)" do
assert_macro "x", "{{x && 1}}", [NilLiteral.new] of ASTNode, "nil"
end
it "expands macro with and (2)" do
assert_macro "x", "{{x && 1}}", [Var.new("hello")] of ASTNode, "1"
end
describe "if" do
it "expands macro with if when truthy" do
assert_macro "", "{%if true%}hello{%end%}", [] of ASTNode, "hello"
end
Ary Borenszweig
committed
it "expands macro with if when falsey" do
assert_macro "", "{%if false%}hello{%end%}", [] of ASTNode, ""
end
Ary Borenszweig
committed
it "expands macro with if else when falsey" do
assert_macro "", "{%if false%}hello{%else%}bye{%end%}", [] of ASTNode, "bye"
end
it "expands macro with if with nop" do
assert_macro "x", "{%if x%}hello{%else%}bye{%end%}", [Nop.new] of ASTNode, "bye"
end
it "expands macro with if with not" do
assert_macro "", "{%if !true%}hello{%else%}bye{%end%}", [] of ASTNode, "bye"
Ary Borenszweig
committed
end
describe "for" do
it "expands macro with for over array literal" do
assert_macro "x", "{%for e in x %}{{e}}{%end%}", [ArrayLiteral.new([Var.new("hello"), Var.new("world")] of ASTNode)] of ASTNode, "helloworld"
end
Ary Borenszweig
committed
it "expands macro with for over array literal with index" do
assert_macro "x", "{%for e, i in x%}{{e}}{{i}}{%end%}", [ArrayLiteral.new([Var.new("hello"), Var.new("world")] of ASTNode)] of ASTNode, "hello0world1"
end
Ary Borenszweig
committed
it "expands macro with for over embedded array literal" do
assert_macro "", "{%for e in [1, 2]%}{{e}}{%end%}", [] of ASTNode, "12"
end
it "expands macro with for over hash literal" do
assert_macro "x", "{%for k, v in x%}{{k}}{{v}}{%end%}", [HashLiteral.new([Var.new("a"), Var.new("b")] of ASTNode, [Var.new("c"), Var.new("d")] of ASTNode)] of ASTNode, "acbd"
end
it "expands macro with for over hash literal with index" do
assert_macro "x", "{%for k, v, i in x%}{{k}}{{v}}{{i}}{%end%}", [HashLiteral.new([Var.new("a"), Var.new("b")] of ASTNode, [Var.new("c"), Var.new("d")] of ASTNode)] of ASTNode, "ac0bd1"
end
it "expands macro with for over tuple literal" do
assert_macro "x", "{%for e, i in x%}{{e}}{{i}}{%end%}", [TupleLiteral.new([Var.new("a"), Var.new("b")] of ASTNode)] of ASTNode, "a0b1"
end
it "expands macro with for over range literal" do
assert_macro "", "{%for e in 1..3 %}{{e}}{%end%}", [] of ASTNode, "123"
end
it "expands macro with for over range literal, evaluating elements" do
assert_macro "x, y", "{%for e in x..y %}{{e}}{%end%}", [NumberLiteral.new(3), NumberLiteral.new(6)] of ASTNode, "3456"
end
it "expands macro with for over range literal, evaluating elements (exclusive)" do
assert_macro "x, y", "{%for e in x...y %}{{e}}{%end%}", [NumberLiteral.new(3), NumberLiteral.new(6)] of ASTNode, "345"
Ary Borenszweig
committed
end
describe "node methods" do
Ary Borenszweig
committed
describe "stringify" do
it "expands macro with stringify call on string" do
assert_macro "x", "{{x.stringify}}", [StringLiteral.new("hello")] of ASTNode, "\"\\\"hello\\\"\""
end
it "expands macro with stringify call on symbol" do
assert_macro "x", "{{x.stringify}}", [SymbolLiteral.new("hello")] of ASTNode, %(":hello")
end
it "expands macro with stringify call on call" do
assert_macro "x", "{{x.stringify}}", [Call.new(nil, "hello")] of ASTNode, %("hello")
end
it "expands macro with stringify call on number" do
assert_macro "x", "{{x.stringify}}", [NumberLiteral.new(1)] of ASTNode, %("1")
Ary Borenszweig
committed
end
Ary Borenszweig
committed
Ary Borenszweig
committed
describe "id" do
it "expands macro with id call on string" do
assert_macro "x", "{{x.id}}", [StringLiteral.new("hello")] of ASTNode, "hello"
end
it "expands macro with id call on symbol" do
assert_macro "x", "{{x.id}}", [SymbolLiteral.new("hello")] of ASTNode, "hello"
end
it "expands macro with id call on call" do
assert_macro "x", "{{x.id}}", [Call.new(nil, "hello")] of ASTNode, "hello"
end
it "expands macro with id call on number" do
assert_macro "x", "{{x.id}}", [NumberLiteral.new(1)] of ASTNode, %(1)
Ary Borenszweig
committed
end
Ary Borenszweig
committed
it "executes == on numbers (true)" do
assert_macro "", "{%if 1 == 1%}hello{%else%}bye{%end%}", [] of ASTNode, "hello"
end
Ary Borenszweig
committed
it "executes == on numbers (false)" do
assert_macro "", "{%if 1 == 2%}hello{%else%}bye{%end%}", [] of ASTNode, "bye"
end
Ary Borenszweig
committed
it "executes != on numbers (true)" do
assert_macro "", "{%if 1 != 2%}hello{%else%}bye{%end%}", [] of ASTNode, "hello"
end
Ary Borenszweig
committed
it "executes != on numbers (false)" do
assert_macro "", "{%if 1 != 1%}hello{%else%}bye{%end%}", [] of ASTNode, "bye"
end
Ary Borenszweig
committed
end
describe "number methods" do
it "executes > (true)" do
assert_macro "", "{%if 2 > 1%}hello{%else%}bye{%end%}", [] of ASTNode, "hello"
end
Ary Borenszweig
committed
it "executes > (false)" do
assert_macro "", "{%if 2 > 3%}hello{%else%}bye{%end%}", [] of ASTNode, "bye"
end
Ary Borenszweig
committed
it "executes >= (true)" do
assert_macro "", "{%if 1 >= 1%}hello{%else%}bye{%end%}", [] of ASTNode, "hello"
end
Ary Borenszweig
committed
it "executes >= (false)" do
assert_macro "", "{%if 2 >= 3%}hello{%else%}bye{%end%}", [] of ASTNode, "bye"
end
Ary Borenszweig
committed
it "executes < (true)" do
assert_macro "", "{%if 1 < 2%}hello{%else%}bye{%end%}", [] of ASTNode, "hello"
end
Ary Borenszweig
committed
it "executes < (false)" do
assert_macro "", "{%if 3 < 2%}hello{%else%}bye{%end%}", [] of ASTNode, "bye"
end
Ary Borenszweig
committed
it "executes <= (true)" do
assert_macro "", "{%if 1 <= 1%}hello{%else%}bye{%end%}", [] of ASTNode, "hello"
end
Ary Borenszweig
committed
it "executes <= (false)" do
assert_macro "", "{%if 3 <= 2%}hello{%else%}bye{%end%}", [] of ASTNode, "bye"
end
Ary Borenszweig
committed
end
Ary Borenszweig
committed
describe "string methods" do
it "executes split without arguments" do
assert_macro "", %({{"1 2 3".split}}), [] of ASTNode, %(["1", "2", "3"])
end
Ary Borenszweig
committed
it "executes split with argument" do
assert_macro "", %({{"1-2-3".split("-")}}), [] of ASTNode, %(["1", "2", "3"])
end
Ary Borenszweig
committed
it "executes split with char argument" do
assert_macro "", %({{"1-2-3".split('-')}}), [] of ASTNode, %(["1", "2", "3"])
end
Ary Borenszweig
committed
it "executes strip" do
Ary Borenszweig
committed
assert_macro "", %({{" hello ".strip}}), [] of ASTNode, %("hello")
Ary Borenszweig
committed
it "executes downcase" do
Ary Borenszweig
committed
assert_macro "", %({{"HELLO".downcase}}), [] of ASTNode, %("hello")
Ary Borenszweig
committed
it "executes upcase" do
Ary Borenszweig
committed
assert_macro "", %({{"hello".upcase}}), [] of ASTNode, %("HELLO")
Ary Borenszweig
committed
Ary Borenszweig
committed
assert_macro "", %({{"hello".capitalize}}), [] of ASTNode, %("Hello")
it "executes lines" do
assert_macro "x", %({{x.lines}}), [StringLiteral.new("1\n2\n3")] of ASTNode, %(["1", "2", "3"])
end
Ary Borenszweig
committed
it "executes length" do
assert_macro "", %({{"hello".length}}), [] of ASTNode, "5"
end
Ary Borenszweig
committed
it "executes empty" do
assert_macro "", %({{"hello".empty?}}), [] of ASTNode, "false"
end
Ary Borenszweig
committed
it "executes string [Range] inclusive" do
Ary Borenszweig
committed
assert_macro "", %({{"hello"[1..-2]}}), [] of ASTNode, %("ell")
Ary Borenszweig
committed
it "executes string [Range] exclusive" do
Ary Borenszweig
committed
assert_macro "", %({{"hello"[1...-2]}}), [] of ASTNode, %("el")
it "executes string chomp" do
assert_macro "", %({{"hello\n".chomp}}), [] of ASTNode, %("hello")
end
Ary Borenszweig
committed
end
describe "array methods" do
it "executes index 0" do
assert_macro "", %({{[1, 2, 3][0]}}), [] of ASTNode, "1"
end
Ary Borenszweig
committed
it "executes index 1" do
assert_macro "", %({{[1, 2, 3][1]}}), [] of ASTNode, "2"
end
it "executes index out of bounds" do
assert_macro "", %({{[1, 2, 3][3]}}), [] of ASTNode, "nil"
end
it "executes length" do
assert_macro "", %({{[1, 2, 3].length}}), [] of ASTNode, "3"
end
Ary Borenszweig
committed
it "executes empty?" do
assert_macro "", %({{[1, 2, 3].empty?}}), [] of ASTNode, "false"
end
Ary Borenszweig
committed
it "executes identify" do
assert_macro "", %({{"A::B".identify}}), [] of ASTNode, "\"A__B\""
assert_macro "", %({{"A".identify}}), [] of ASTNode, "\"A\""
end
it "executes join" do
Ary Borenszweig
committed
assert_macro "", %({{[1, 2, 3].join ", "}}), [] of ASTNode, %("1, 2, 3")
Ary Borenszweig
committed
it "executes join with strings" do
Ary Borenszweig
committed
assert_macro "", %({{["a", "b"].join ", "}}), [] of ASTNode, %("a, b")
Ary Borenszweig
committed
it "executes map" do
assert_macro "", %({{[1, 2, 3].map { |e| e == 2 }}}), [] of ASTNode, "[false, true, false]"
end
Ary Borenszweig
committed
it "executes map with arg" do
assert_macro "x", %({{x.map { |e| e }}}), [ArrayLiteral.new([Call.new(nil, "hello")] of ASTNode)] of ASTNode, "[hello]"
end
Ary Borenszweig
committed
it "executes select" do
assert_macro "", %({{[1, 2, 3].select { |e| e == 1 }}}), [] of ASTNode, "[1]"
end
Ary Borenszweig
committed
it "executes any? (true)" do
assert_macro "", %({{[1, 2, 3].any? { |e| e == 1 }}}), [] of ASTNode, "true"
end
Ary Borenszweig
committed
it "executes any? (false)" do
assert_macro "", %({{[1, 2, 3].any? { |e| e == 4 }}}), [] of ASTNode, "false"
end
Ary Borenszweig
committed
it "executes all? (true)" do
assert_macro "", %({{[1, 1, 1].all? { |e| e == 1 }}}), [] of ASTNode, "true"
end
Ary Borenszweig
committed
it "executes all? (false)" do
assert_macro "", %({{[1, 2, 1].all? { |e| e == 1 }}}), [] of ASTNode, "false"
end
Ary Borenszweig
committed
it "executes first" do
assert_macro "", %({{[1, 2, 3].first}}), [] of ASTNode, "1"
end
it "executes last" do
assert_macro "", %({{[1, 2, 3].last}}), [] of ASTNode, "3"
end
it "executes argify" do
assert_macro "", %({{[1, 2, 3].argify}}), [] of ASTNode, "1, 2, 3"
end
it "executes argify with symbols and strings" do
assert_macro "", %({{[:foo, "hello", 3].argify}}), [] of ASTNode, %(:foo, "hello", 3)
end
describe "hash methods" do
it "executes length" do
assert_macro "", %({{{a: 1, b: 3}.length}}), [] of ASTNode, "2"
end
it "executes empty?" do
assert_macro "", %({{{a: 1}.empty?}}), [] of ASTNode, "false"
end
it "executes index" do
assert_macro "", %({{{a: 1}[:a]}}), [] of ASTNode, "1"
end
it "executes index not found" do
assert_macro "", %({{{a: 1}[:b]}}), [] of ASTNode, "nil"
end
describe "tuple methods" do
it "executes length" do
assert_macro "", %({{{1, 2, 3}.length}}), [] of ASTNode, "3"
end
it "executes empty?" do
assert_macro "", %({{{1, 2, 3}.empty?}}), [] of ASTNode, "false"
end
it "executes index 1" do
assert_macro "", %({{{1, 2, 3}[1]}}), [] of ASTNode, "2"
end
describe "metavar methods" do
Ary Borenszweig
committed
it "executes nothing" do
assert_macro "x", %({{x}}), [MetaVar.new("foo", Program.new.int32)] of ASTNode, %(foo)
end
it "executes name" do
Ary Borenszweig
committed
assert_macro "x", %({{x.name}}), [MetaVar.new("foo", Program.new.int32)] of ASTNode, %("foo")
end
it "executes id" do
assert_macro "x", %({{x.id}}), [MetaVar.new("foo", Program.new.int32)] of ASTNode, %(foo)
it "executes assign" do
assert_macro "", %({{a = 1}}{{a}}), [] of ASTNode, "1"
end
Ary Borenszweig
committed
describe "type method" do
it "executes name" do
assert_macro("x", "{{x.name}}", %("String")) do |program|
[MacroType.new(program.string)] of ASTNode
end
end
it "executes instance_vars" do
Ary Borenszweig
committed
assert_macro("x", "{{x.instance_vars.map &.stringify}}", %(["length", "c"])) do |program|
Ary Borenszweig
committed
[MacroType.new(program.string)] of ASTNode
end
end
it "executes superclass" do
assert_macro("x", "{{x.superclass}}", %(Reference)) do |program|
[MacroType.new(program.string)] of ASTNode
end
end
end
describe "env" do
it "has key" do
ENV["FOO"] = "foo"
assert_macro "", %({{env("FOO")}}), [] of ASTNode, %("foo")
ENV.delete "FOO"
end
it "doesn't have key" do
ENV.delete "FOO"
assert_macro "", %({{env("FOO")}}), [] of ASTNode, %(nil)
end
end