Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add specs for evaluation order during assignment #1015

Merged
merged 1 commit into from
Mar 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions language/fixtures/variables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,76 @@ def self.without_parenthesis a
def self.false
false
end

class EvalOrder
attr_reader :order

def initialize
@order = []
end

def reset
@order = []
end

def foo
self << "foo"
FooClass.new(self)
end

def bar
self << "bar"
BarClass.new(self)
end

def a
self << "a"
end

def b
self << "b"
end

def node
self << "node"

node = Node.new
node.left = Node.new
node.left.right = Node.new

node
end

def <<(value)
order << value
end

class FooClass
attr_reader :evaluator

def initialize(evaluator)
@evaluator = evaluator
end

def []=(_index, _value)
evaluator << "foo[]="
end
end

class BarClass
attr_reader :evaluator

def initialize(evaluator)
@evaluator = evaluator
end

def baz=(_value)
evaluator << "bar.baz="
end
end

class Node
attr_accessor :left, :right
end
end
end
80 changes: 80 additions & 0 deletions language/variables_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,86 @@
require_relative '../spec_helper'
require_relative 'fixtures/variables'

describe "Evaluation order during assignment" do
context "with single assignment" do
it "evaluates from left to right" do
obj = VariablesSpecs::EvalOrder.new
obj.instance_eval do
foo[0] = a
end

obj.order.should == ["foo", "a", "foo[]="]
end
end

context "with multiple assignment" do
ruby_version_is ""..."3.1" do
it "does not evaluate from left to right" do
obj = VariablesSpecs::EvalOrder.new

obj.instance_eval do
foo[0], bar.baz = a, b
end

obj.order.should == ["a", "b", "foo", "foo[]=", "bar", "bar.baz="]
end

it "cannot be used to swap variables with nested method calls" do
node = VariablesSpecs::EvalOrder.new.node

original_node = node
original_node_left = node.left
original_node_left_right = node.left.right

node.left, node.left.right, node = node.left.right, node, node.left
# Should evaluate in the order of:
# RHS: node.left.right, node, node.left
# LHS:
# * node(original_node), original_node.left = original_node_left_right
# * node(original_node), node.left(changed in the previous assignment to original_node_left_right),
# original_node_left_right.right = original_node
# * node = original_node_left

node.should == original_node_left
node.right.should_not == original_node
node.right.left.should_not == original_node_left_right
end
end

ruby_version_is "3.1" do
it "evaluates from left to right, receivers first then methods" do
obj = VariablesSpecs::EvalOrder.new
obj.instance_eval do
foo[0], bar.baz = a, b
end

obj.order.should == ["foo", "bar", "a", "b", "foo[]=", "bar.baz="]
end

it "can be used to swap variables with nested method calls" do
node = VariablesSpecs::EvalOrder.new.node

original_node = node
original_node_left = node.left
original_node_left_right = node.left.right

node.left, node.left.right, node = node.left.right, node, node.left
# Should evaluate in the order of:
# LHS: node, node.left(original_node_left)
# RHS: original_node_left_right, original_node, original_node_left
# Ops:
# * node(original_node), original_node.left = original_node_left_right
# * original_node_left.right = original_node
# * node = original_node_left

node.should == original_node_left
node.right.should == original_node
node.right.left.should == original_node_left_right
end
end
end
end

describe "Multiple assignment" do
context "with a single RHS value" do
it "assigns a simple MLHS" do
Expand Down