Skip to content

Commit

Permalink
Showing 19 changed files with 37 additions and 377 deletions.
19 changes: 0 additions & 19 deletions spec/compiler/formatter/formatter_spec.cr
Original file line number Diff line number Diff line change
@@ -109,31 +109,12 @@ describe Crystal::Formatter do
assert_format "#{keyword} a\n2; 3\nelse\n3\nend", "#{keyword} a\n 2; 3\nelse\n 3\nend"
end

assert_format "ifdef a\n2\nend", "{% if flag?(:a) %}\n 2\n{% end %}"
assert_format "ifdef a\n2\n3\nend", "{% if flag?(:a) %}\n 2\n 3\n{% end %}"
assert_format "ifdef a\n2\nelse\nend", "{% if flag?(:a) %}\n 2\n{% else %}\n{% end %}"
assert_format "ifdef a\nelse\n2\nend", "{% if flag?(:a) %}\n{% else %}\n 2\n{% end %}"
assert_format "ifdef a\n2\nelse\n3\nend", "{% if flag?(:a) %}\n 2\n{% else %}\n 3\n{% end %}"
assert_format "ifdef a\n2\n3\nelse\n4\n5\nend", "{% if flag?(:a) %}\n 2\n 3\n{% else %}\n 4\n 5\n{% end %}"
assert_format "ifdef a\nifdef b\n3\nelse\n4\nend\nend", "{% if flag?(:a) %}\n {% if flag?(:b) %}\n 3\n {% else %}\n 4\n {% end %}\n{% end %}"
assert_format "ifdef a\nifdef b\nelse\n4\nend\nend", "{% if flag?(:a) %}\n {% if flag?(:b) %}\n {% else %}\n 4\n {% end %}\n{% end %}"
assert_format "ifdef a\n # hello\n 2\nend", "{% if flag?(:a) %}\n # hello\n 2\n{% end %}"
assert_format "ifdef a\n2; 3\nelse\n3\nend", "{% if flag?(:a) %}\n 2; 3\n{% else %}\n 3\n{% end %}"

assert_format "if 1\n2\nelsif\n3\n4\nend", "if 1\n 2\nelsif 3\n 4\nend"
assert_format "if 1\n2\nelsif\n3\n4\nelsif 5\n6\nend", "if 1\n 2\nelsif 3\n 4\nelsif 5\n 6\nend"
assert_format "if 1\n2\nelsif\n3\n4\nelse\n6\nend", "if 1\n 2\nelsif 3\n 4\nelse\n 6\nend"

assert_format "ifdef a\n2\nelsif b\n4\nend", "{% if flag?(:a) %}\n 2\n{% elsif flag?(:b) %}\n 4\n{% end %}"
assert_format "ifdef !a\n2\nend", "{% if !flag?(:a) %}\n 2\n{% end %}"
assert_format "ifdef a && b\n2\nend", "{% if flag?(:a) && flag?(:b) %}\n 2\n{% end %}"
assert_format "ifdef a || b\n2\nend", "{% if flag?(:a) || flag?(:b) %}\n 2\n{% end %}"

assert_format "{% if 1 %}\n 2\n{% end %}\ndef foo\nend"

assert_format "1 ifdef a", "{% if flag?(:a) %}\n 1\n{% end %}"
assert_format "1 ifdef a\n2", "{% if flag?(:a) %}\n 1\n{% end %}\n2"

assert_format "if 1\n2\nend\nif 3\nend", "if 1\n 2\nend\nif 3\nend"
assert_format "if 1\nelse\n2\nend\n3", "if 1\nelse\n 2\nend\n3"

2 changes: 1 addition & 1 deletion spec/compiler/lexer/lexer_macro_spec.cr
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ describe "Lexer macro" do
token.type.should eq(:MACRO_END)
end

["begin", "do", "if", "unless", "class", "struct", "module", "def", "while", "until", "case", "macro", "fun", "lib", "union", "ifdef", "macro def"].each do |keyword|
["begin", "do", "if", "unless", "class", "struct", "module", "def", "while", "until", "case", "macro", "fun", "lib", "union", "macro def"].each do |keyword|
it "lexes macro with nested #{keyword}" do
lexer = Lexer.new(%(hello\n #{keyword} {{world}} end end))

2 changes: 1 addition & 1 deletion spec/compiler/lexer/lexer_spec.cr
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ describe "Lexer" do
:extend, :while, :until, :nil, :do, :yield, :return, :unless, :next, :break,
:begin, :lib, :fun, :type, :struct, :union, :enum, :macro, :out, :require,
:case, :when, :select, :then, :of, :abstract, :rescue, :ensure, :is_a?, :alias,
:pointerof, :sizeof, :instance_sizeof, :ifdef, :as, :as?, :typeof, :for, :in,
:pointerof, :sizeof, :instance_sizeof, :as, :as?, :typeof, :for, :in,
:with, :self, :super, :private, :protected, :asm, :uninitialized, :nil?]
it_lexes_idents ["ident", "something", "with_underscores", "with_1", "foo?", "bar!", "fooBar",
"❨╯°□°❩╯︵┻━┻"]
15 changes: 0 additions & 15 deletions spec/compiler/normalize/ifdef_spec.cr

This file was deleted.

17 changes: 1 addition & 16 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
@@ -403,14 +403,6 @@ describe "Parser" do
it_parses "if foo\n1\nelse\n2\nend", If.new("foo".call, 1.int32, 2.int32)
it_parses "if foo; 1; elsif bar; 2; else 3; end", If.new("foo".call, 1.int32, If.new("bar".call, 2.int32, 3.int32))

it_parses "ifdef foo; 1; end", IfDef.new("foo".var, 1.int32)
it_parses "ifdef foo; 1; else; 2; end", IfDef.new("foo".var, 1.int32, 2.int32)
it_parses "ifdef foo; 1; elsif bar; 2; else 3; end", IfDef.new("foo".var, 1.int32, IfDef.new("bar".var, 2.int32, 3.int32))
it_parses "ifdef (!a || b) && c; 1; end", IfDef.new(And.new(Or.new(Not.new("a".var), "b".var), "c".var), 1.int32)
it_parses "ifdef !(a || b) && c; 1; end", IfDef.new(And.new(Not.new(Or.new("a".var, "b".var)), "c".var), 1.int32)

it_parses "1 ifdef foo", IfDef.new("foo".var, 1.int32)

it_parses "include Foo", Include.new("Foo".path)
it_parses "include Foo\nif true; end", [Include.new("Foo".path), If.new(true.bool)]
it_parses "extend Foo", Extend.new("Foo".path)
@@ -692,12 +684,8 @@ describe "Parser" do
it_parses "lib LibC\n$errno : B, C -> D\nend", LibDef.new("LibC", [ExternalVar.new("errno", ProcNotation.new(["B".path, "C".path] of ASTNode, "D".path))] of ASTNode)
it_parses "lib LibC\n$errno = Foo : Int32\nend", LibDef.new("LibC", [ExternalVar.new("errno", "Int32".path, "Foo")] of ASTNode)
it_parses "lib LibC\nalias Foo = Bar\nend", LibDef.new("LibC", [Alias.new("Foo", "Bar".path)] of ASTNode)
it_parses "lib LibC; struct Foo; ifdef cond; a : Int32; else; b : Float64; end; end; end", LibDef.new("LibC", [CStructOrUnionDef.new("Foo", IfDef.new("cond".var, TypeDeclaration.new("a".var, "Int32".path), TypeDeclaration.new("b".var, "Float64".path)))] of ASTNode)
it_parses "lib LibC\nstruct Foo\nifdef cond\na : Int32\nelse\nb : Float64\nend\nend\nend", LibDef.new("LibC", [CStructOrUnionDef.new("Foo", IfDef.new("cond".var, TypeDeclaration.new("a".var, "Int32".path), TypeDeclaration.new("b".var, "Float64".path)))] of ASTNode)
it_parses "lib LibC; struct Foo; include Bar; end; end", LibDef.new("LibC", [CStructOrUnionDef.new("Foo", Include.new("Bar".path))] of ASTNode)

it_parses "lib LibC\nifdef foo\ntype A = B\nend\nend", LibDef.new("LibC", [IfDef.new("foo".var, TypeDef.new("A", "B".path))] of ASTNode)

it_parses "fun foo(x : Int32) : Int64\nx\nend", FunDef.new("foo", [Arg.new("x", restriction: "Int32".path)], "Int64".path, body: "x".var)

it_parses "lib LibC; {{ 1 }}; end", LibDef.new("LibC", body: [MacroExpression.new(1.int32)] of ASTNode)
@@ -1036,8 +1024,6 @@ describe "Parser" do

it_parses "foo { a = 1 }; a", [Call.new(nil, "foo", block: Block.new(body: Assign.new("a".var, 1.int32))), "a".call] of ASTNode

it_parses "lib LibC; ifdef foo; $foo : Int32; else; $foo : Float64; end; end", LibDef.new("LibC", IfDef.new("foo".var, ExternalVar.new("foo", "Int32".path), ExternalVar.new("foo", "Float64".path)))

it_parses "foo.bar(1).baz", Call.new(Call.new("foo".call, "bar", 1.int32), "baz")

it_parses "b.c ||= 1", Or.new(Call.new("b".call, "c"), Call.new("b".call, "c=", 1.int32))
@@ -1217,7 +1203,7 @@ describe "Parser" do
it_parses "foo 1.bar do\nend", Call.new(nil, "foo", args: [Call.new(1.int32, "bar")] of ASTNode, block: Block.new)
it_parses "return 1.bar do\nend", Return.new(Call.new(1.int32, "bar", block: Block.new))

%w(begin nil true false yield with abstract def macro require case if ifdef unless include extend class struct module enum while
%w(begin nil true false yield with abstract def macro require case if unless include extend class struct module enum while
until return next break lib fun alias pointerof sizeof instance_sizeof typeof private protected asm end do else elsif when rescue ensure).each do |keyword|
it_parses "#{keyword} : Int32", TypeDeclaration.new(keyword.var, "Int32".path)
it_parses "property #{keyword} : Int32", Call.new(nil, "property", TypeDeclaration.new(keyword.var, "Int32".path))
@@ -1466,7 +1452,6 @@ describe "Parser" do
assert_end_location "if 1; else; 2; end"
assert_end_location "if 1; elseif; 2; end"
assert_end_location "unless 1; 2; end"
assert_end_location "ifdef foo; 2; end"
assert_end_location "a = 123"
assert_end_location "a, b = 1, 2"
assert_end_location "@foo"
8 changes: 4 additions & 4 deletions spec/compiler/semantic/c_struct_spec.cr
Original file line number Diff line number Diff line change
@@ -150,15 +150,15 @@ describe "Semantic: struct" do
)) { pointer_of(types["LibC"].types["Node"]) }
end

it "supports ifdef inside struct" do
it "supports macro if inside struct" do
assert_type(%(
lib LibC
struct Foo
ifdef some_flag
{% if flag?(:some_flag) %}
a : Int32
else
{% else %}
a : Float64
end
{% end %}
end
end
6 changes: 4 additions & 2 deletions spec/compiler/semantic/lib_spec.cr
Original file line number Diff line number Diff line change
@@ -424,11 +424,13 @@ describe "Semantic: lib" do
)) { int64 }
end

it "correctly attached link flags if there's an ifdef" do
it "correctly attached link flags if there's a macro if" do
result = semantic(%(
@[Link("SDL")]
@[Link("SDLMain")]
@[Link(framework: "Cocoa")] ifdef some_flag
{% if flag?(:some_flag) %}
@[Link(framework: "Cocoa")]
{% end %}
lib LibSDL
fun init = SDL_Init(flags : UInt32) : Int32
end
8 changes: 4 additions & 4 deletions spec/compiler/semantic/union_spec.cr
Original file line number Diff line number Diff line change
@@ -43,15 +43,15 @@ describe "Semantic: union" do
") { generic_class "Bar", union_of(int32, char) }
end

it "supports ifdef inside union" do
it "supports macro if inside union" do
assert_type(%(
lib LibC
union Foo
ifdef some_flag
{% if flag?(:some_flag) %}
a : Int32
else
{% else %}
a : Float64
end
{% end %}
end
end
4 changes: 0 additions & 4 deletions src/compiler/crystal/macros.cr
Original file line number Diff line number Diff line change
@@ -794,10 +794,6 @@ module Crystal::Macros
# class Unless < ASTNode
# end

# An ifdef expression.
# class IfDef < ASTNode
# end

# Assign expression.
class Assign < ASTNode
# Returns the target assigned to.
56 changes: 0 additions & 56 deletions src/compiler/crystal/semantic/normalizer.cr
Original file line number Diff line number Diff line change
@@ -184,18 +184,6 @@ module Crystal
While.new(not_exp, node.body).at(node)
end

# Evaluate the ifdef's flags.
# If they hold, keep the "then" part.
# If they don't, keep the "else" part.
def transform(node : IfDef)
cond_value = eval_flags(node.cond)
if cond_value
node.then.transform(self)
else
node.else.transform(self)
end
end

# Check if the right hand side is dead code
def transform(node : Assign)
super
@@ -206,49 +194,5 @@ module Crystal
node
end
end

def eval_flags(node)
evaluator = FlagsEvaluator.new(program)
node.accept evaluator
evaluator.value
end

class FlagsEvaluator < Visitor
getter value : Bool

def initialize(@program : Program)
@value = false
end

def visit(node : Var)
@value = @program.has_flag?(node.name)
end

def visit(node : Not)
node.exp.accept self
@value = !@value
false
end

def visit(node : And)
node.left.accept self
left_value = @value
node.right.accept self
@value = left_value && @value
false
end

def visit(node : Or)
node.left.accept self
left_value = @value
node.right.accept self
@value = left_value || @value
false
end

def visit(node : ASTNode)
raise "Bug: shouldn't visit #{node} in FlagsEvaluator"
end
end
end
end
2 changes: 1 addition & 1 deletion src/compiler/crystal/semantic/semantic_visitor.cr
Original file line number Diff line number Diff line change
@@ -185,7 +185,7 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor
when Attribute
# Nothing
when Nop
# Nothing (might happen as a result of an evaulated ifdef)
# Nothing (might happen as a result of an evaulated macro if)
when Call
# Don't clear attributes if these were generated by a macro
unless node.expanded
35 changes: 0 additions & 35 deletions src/compiler/crystal/syntax/ast.cr
Original file line number Diff line number Diff line change
@@ -620,41 +620,6 @@ module Crystal
def_equals_and_hash @cond, @then, @else
end

# An ifdef expression.
#
# 'ifdef' cond
# then
# [
# 'else'
# else
# ]
# 'end'
#
# An if elsif end is parsed as an If whose
# else is another If.
class IfDef < ASTNode
property cond : ASTNode
property then : ASTNode
property else : ASTNode

def initialize(@cond, a_then = nil, a_else = nil)
@then = Expressions.from a_then
@else = Expressions.from a_else
end

def accept_children(visitor)
@cond.accept visitor
@then.accept visitor
@else.accept visitor
end

def clone_without_location
IfDef.new(@cond.clone, @then.clone, @else.clone)
end

def_equals_and_hash @cond, @then, @else
end

# Assign expression.
#
# target '=' value
14 changes: 2 additions & 12 deletions src/compiler/crystal/syntax/lexer.cr
Original file line number Diff line number Diff line change
@@ -795,14 +795,7 @@ module Crystal
when 'i'
case next_char
when 'f'
if peek_next_char == 'd'
next_char
if next_char == 'e' && next_char == 'f'
return check_ident_or_keyword(:ifdef, start)
end
else
return check_ident_or_keyword(:if, start)
end
return check_ident_or_keyword(:if, start)
when 'n'
if ident_part_or_end?(peek_next_char)
case next_char
@@ -2219,10 +2212,7 @@ module Crystal
next_char == 'u' && next_char == 'n' && peek_not_ident_part_or_end_next_char && :fun
when 'i'
beginning_of_line && next_char == 'f' &&
(char = next_char) && (
(!ident_part_or_end?(char) && :if) ||
(char == 'd' && next_char == 'e' && next_char == 'f' && peek_not_ident_part_or_end_next_char && :ifdef)
)
(char = next_char) && (!ident_part_or_end?(char) && :if)
when 'l'
next_char == 'i' && next_char == 'b' && peek_not_ident_part_or_end_next_char && :lib
when 'm'
Loading

0 comments on commit 8d793e7

Please sign in to comment.