mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
223 lines
7.4 KiB
Crystal
223 lines
7.4 KiB
Crystal
require "../../../spec_helper"
|
|
|
|
module Ameba::AST
|
|
describe Variable do
|
|
var_node = Crystal::Var.new("foo")
|
|
scope = Scope.new as_node "foo = 1"
|
|
|
|
describe "#initialize" do
|
|
it "creates a new variable" do
|
|
variable = Variable.new(var_node, scope)
|
|
variable.node.should_not be_nil
|
|
end
|
|
end
|
|
|
|
describe "delegation" do
|
|
it "delegates locations" do
|
|
variable = Variable.new(var_node, scope)
|
|
variable.location.should eq var_node.location
|
|
variable.end_location.should eq var_node.end_location
|
|
end
|
|
|
|
it "delegates name" do
|
|
variable = Variable.new(var_node, scope)
|
|
variable.name.should eq var_node.name
|
|
end
|
|
|
|
it "delegates to_s" do
|
|
variable = Variable.new(var_node, scope)
|
|
variable.to_s.should eq var_node.to_s
|
|
end
|
|
end
|
|
|
|
describe "#special?" do
|
|
it "returns truthy if it is a special `$?` var" do
|
|
variable = Variable.new Crystal::Var.new("$?"), scope
|
|
variable.special?.should be_truthy
|
|
end
|
|
|
|
it "returns falsey otherwise" do
|
|
variable = Variable.new Crystal::Var.new("a"), scope
|
|
variable.special?.should be_falsey
|
|
end
|
|
end
|
|
|
|
describe "#assign" do
|
|
assign_node = as_node("foo=1")
|
|
|
|
it "assigns the variable (creates a new assignment)" do
|
|
variable = Variable.new(var_node, scope)
|
|
variable.assign(assign_node, scope)
|
|
variable.assignments.empty?.should be_false
|
|
end
|
|
|
|
it "can create multiple assignments" do
|
|
variable = Variable.new(var_node, scope)
|
|
variable.assign(assign_node, scope)
|
|
variable.assign(assign_node, scope)
|
|
variable.assignments.size.should eq 2
|
|
end
|
|
end
|
|
|
|
describe "#reference" do
|
|
it "references the existed assignment" do
|
|
variable = Variable.new(var_node, scope)
|
|
variable.assign(as_node("foo=1"), scope)
|
|
variable.reference(var_node, scope)
|
|
variable.references.empty?.should be_false
|
|
end
|
|
|
|
it "adds a reference to the scope" do
|
|
scope = Scope.new as_node "foo = 1"
|
|
variable = Variable.new(var_node, scope)
|
|
variable.assign(as_node("foo=1"), scope)
|
|
variable.reference(var_node, scope)
|
|
scope.references.size.should eq 1
|
|
scope.references.first.node.to_s.should eq "foo"
|
|
end
|
|
end
|
|
|
|
describe "#captured_by_block?" do
|
|
it "returns truthy if the variable is captured by block" do
|
|
nodes = as_nodes <<-CRYSTAL
|
|
def method
|
|
a = 2
|
|
3.times { |i| a = a + i }
|
|
end
|
|
CRYSTAL
|
|
|
|
var_node = nodes.var_nodes.first
|
|
|
|
scope = Scope.new(nodes.def_nodes.first)
|
|
scope.add_variable(var_node)
|
|
scope.inner_scopes << Scope.new(nodes.block_nodes.first, scope)
|
|
|
|
variable = Variable.new(var_node, scope)
|
|
variable.reference(nodes.var_nodes.last, scope.inner_scopes.last)
|
|
|
|
variable.captured_by_block?.should be_truthy
|
|
end
|
|
|
|
it "returns falsy if the variable is not captured by the block" do
|
|
scope = Scope.new as_node <<-CRYSTAL
|
|
def method
|
|
a = 1
|
|
end
|
|
CRYSTAL
|
|
|
|
scope.add_variable(Crystal::Var.new "a")
|
|
variable = scope.variables.first
|
|
|
|
variable.captured_by_block?.should be_falsey
|
|
end
|
|
end
|
|
|
|
describe "#target_of?" do
|
|
it "returns true if the variable is a target of Crystal::Assign node" do
|
|
assign_node = as_nodes("foo=1").assign_nodes.last
|
|
variable = Variable.new assign_node.target.as(Crystal::Var), scope
|
|
variable.target_of?(assign_node).should be_true
|
|
end
|
|
|
|
it "returns true if the variable is a target of Crystal::OpAssign node" do
|
|
assign_node = as_nodes("foo=1;foo+=1").op_assign_nodes.last
|
|
variable = Variable.new assign_node.target.as(Crystal::Var), scope
|
|
variable.target_of?(assign_node).should be_true
|
|
end
|
|
|
|
it "returns true if the variable is a target of Crystal::MultiAssign node" do
|
|
assign_node = as_nodes("a,b,c={1,2,3}").multi_assign_nodes.last
|
|
assign_node.targets.size.should_not eq 0
|
|
assign_node.targets.each do |target|
|
|
variable = Variable.new target.as(Crystal::Var), scope
|
|
variable.target_of?(assign_node).should be_true
|
|
end
|
|
end
|
|
|
|
it "returns false if the node is not assign" do
|
|
variable = Variable.new(Crystal::Var.new("v"), scope)
|
|
variable.target_of?(as_node "nil").should be_false
|
|
end
|
|
|
|
it "returns false if the variable is not a target of the assign" do
|
|
variable = Variable.new(Crystal::Var.new("foo"), scope)
|
|
variable.target_of?(as_node("bar = 1")).should be_false
|
|
end
|
|
end
|
|
|
|
describe "#ignored?" do
|
|
it "is true if variable is ignored" do
|
|
variable = Variable.new(Crystal::Var.new("_var"), scope)
|
|
variable.ignored?.should be_true
|
|
end
|
|
|
|
it "is false if variable is not ignored" do
|
|
variable = Variable.new(Crystal::Var.new("v_ar"), scope)
|
|
variable.ignored?.should be_false
|
|
end
|
|
|
|
it "is true if variable is a black hole" do
|
|
variable = Variable.new(Crystal::Var.new("_"), scope)
|
|
variable.ignored?.should be_true
|
|
end
|
|
end
|
|
|
|
describe "#eql?" do
|
|
var = Crystal::Var.new("foo").at(Crystal::Location.new(nil, 1, 2))
|
|
variable = Variable.new var, scope
|
|
|
|
it "is false if node is not a Crystal::Var" do
|
|
variable.eql?(as_node("nil")).should be_false
|
|
end
|
|
|
|
it "is false if node name is different" do
|
|
variable.eql?(Crystal::Var.new "bar").should be_false
|
|
end
|
|
|
|
it "is false if node has a different location" do
|
|
variable.eql?(Crystal::Var.new "foo").should be_false
|
|
end
|
|
|
|
it "is true otherwise" do
|
|
variable.eql?(variable.node).should be_true
|
|
end
|
|
end
|
|
|
|
describe "#declared_before?" do
|
|
it "is falsey if variable doesn't have location" do
|
|
var1 = Crystal::Var.new("foo")
|
|
var2 = Crystal::Var.new("bar").at(Crystal::Location.new(nil, 1, 2))
|
|
Variable.new(var1, scope).declared_before?(var2).should be_falsey
|
|
end
|
|
|
|
it "is falsey if node doesn't have location" do
|
|
var1 = Crystal::Var.new("foo").at(Crystal::Location.new(nil, 1, 2))
|
|
var2 = Crystal::Var.new("bar")
|
|
Variable.new(var1, scope).declared_before?(var2).should be_falsey
|
|
end
|
|
|
|
it "is true if var's line_number below the node" do
|
|
var1 = Crystal::Var.new("foo").at(Crystal::Location.new(nil, 1, 2))
|
|
var2 = Crystal::Var.new("bar").at(Crystal::Location.new(nil, 2, 2))
|
|
Variable.new(var1, scope).declared_before?(var2).should be_true
|
|
end
|
|
|
|
it "is true if var's column_number is after the node" do
|
|
var1 = Crystal::Var.new("foo").at(Crystal::Location.new(nil, 1, 2))
|
|
var2 = Crystal::Var.new("bar").at(Crystal::Location.new(nil, 1, 3))
|
|
Variable.new(var1, scope).declared_before?(var2).should be_true
|
|
end
|
|
|
|
it "is false if var's location is before the node" do
|
|
var1 = Crystal::Var.new("foo").at(Crystal::Location.new(nil, 2, 2))
|
|
var2 = Crystal::Var.new("bar").at(Crystal::Location.new(nil, 1, 3))
|
|
Variable.new(var1, scope).declared_before?(var2).should be_false
|
|
end
|
|
|
|
it "is false is the node is the same var" do
|
|
var = Crystal::Var.new("foo").at(Crystal::Location.new(nil, 2, 2))
|
|
Variable.new(var, scope).declared_before?(var).should be_false
|
|
end
|
|
end
|
|
end
|
|
end
|