Skip to content

Commit

Permalink
another round of fixing arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
iliabylich committed Jan 3, 2020
1 parent 79e3742 commit bceb7ff
Show file tree
Hide file tree
Showing 13 changed files with 216 additions and 232 deletions.
1 change: 1 addition & 0 deletions executor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ def execute_send((options, _flag, block_iseq))
end
end


if (options[:flag] & VM_CALL_ARGS_SPLAT).nonzero? && kwarg_names.nil?
*head, tail = args
args = [*head, *tail]
Expand Down
18 changes: 2 additions & 16 deletions tags/language/block_tags.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
fails:A block yielded a single Array assigns the Array to a single rest argument
fails:A block yielded a single Array assigns nil to unassigned required arguments
fails:A block yielded a single Array assigns elements to post arguments
fails:A block yielded a single Array assigns elements to required arguments when a keyword rest argument is present
fails:A block yielded a single Array assigns symbol keys from a Hash to keyword arguments
fails:A block yielded a single Array assigns symbol keys from a Hash returned by #to_hash to keyword arguments
fails:A block yielded a single Array calls #to_hash on the argument and uses resulting hash as first argument when optional argument and keyword argument accepted
fails:A block yielded a single Array does not treat hashes with string keys as keyword arguments
fails:A block yielded a single Array calls #to_hash on the last element if keyword arguments are present
fails:A block yielded a single Array assigns the last element to a non-keyword argument if #to_hash returns nil
fails:A block yielded a single Array calls #to_hash on the last element when there are more arguments than parameters
fails:A block yielded a single Array raises a TypeError if #to_hash does not return a Hash
fails:A block yielded a single Array raises the error raised inside #to_hash
fails:A block yielded a single Array when non-symbol keys are in a keyword arguments Hash separates non-symbol keys and symbol keys
fails:A block yielded a single Object calls #to_ary on the object when taking multiple arguments
fails:A block yielded a single Object receives the object if #to_ary returns nil
fails:A block yielded a single Object raises a TypeError if #to_ary does not return an Array
fails:A block allows to define a block variable with the same name as the enclosing block
fails:A block does not capture a local when the block argument has the same name
fails:A block taking |a| arguments assigns the first value yielded to the argument
fails:A block taking |a, b| arguments destructures a splatted Array
fails:A block taking |a, b| arguments calls #to_ary to convert a single yielded object to an Array
Expand All @@ -29,12 +22,5 @@ fails:A block taking |*a| arguments does not call #to_ary if the single yielded
fails:A block taking |a, | arguments calls #to_ary to convert a single yielded object to an Array
fails:A block taking |a, | arguments raises a TypeError if #to_ary does not return an Array
fails:A block taking |(a, b), c| arguments calls #to_ary to convert a single yielded object to an Array
fails:A block taking |*a, b:| merges the hash into the splatted array
fails:A block arguments with _ extracts arguments with _
fails:A block arguments with _ assigns the first variable named
fails:Post-args appear after a splat
fails:Post-args are required
fails:Post-args with optional args gathers remaining args in the splat
fails:Post-args with optional args overrides the optional arg before gathering in the splat
fails:Post-args with optional args uses the required arg before the optional and the splat
fails:Post-args with optional args overrides the optional args from left to right before gathering the splat
1 change: 0 additions & 1 deletion tags/language/for_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:The for expression returns expr
fails:The for expression allows 'break' to have an argument which becomes the value of the for expression
16 changes: 1 addition & 15 deletions tags/language/hash_tags.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
fails:Hash literal {} should return an empty hash
fails:Hash literal {} should return a new hash populated with the given elements
fails:Hash literal freezes string keys on initialization
fails:Hash literal checks duplicated keys on initialization
fails:Hash literal accepts a hanging comma
fails:Hash literal recognizes '=' at the end of the key
fails:Hash literal constructs a new hash with the given elements
fails:Hash literal ignores a hanging comma
fails:Hash literal accepts mixed 'key: value' and 'key => value' syntax
fails:Hash literal accepts mixed 'key: value', 'key => value' and '"key"': value' syntax
fails:Hash literal expands an '**{}' element into the containing Hash literal initialization
fails:Hash literal expands an '**obj' element into the containing Hash literal initialization
fails:Hash literal expands a BasicObject using ** into the containing Hash literal initialization
fails:Hash literal expands an '**{}' element with the last key/value pair taking precedence
fails:Hash literal merges multiple nested '**obj' in Hash literals
fails:Hash literal calls #to_hash to expand an '**obj' element
fails:Hash literal raises a TypeError if any splatted elements keys are not symbols
fails:Hash literal raises a TypeError if #to_hash does not return a Hash
14 changes: 6 additions & 8 deletions tags/language/lambda_tags.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
fails:A lambda literal -> () { } returns a lambda
fails:A lambda literal -> () { } assigns variables from parameters for definition '@a = -> (a={}) { a }'
fails:A lambda literal -> () { } assigns variables from parameters for definition '@a = -> (**) { }'
fails:A lambda literal -> () { } assigns variables from parameters for definition '@a = -> (**k) { k }'
fails:A lambda literal -> () { } assigns variables from parameters for definition '@a = -> (*, **k) { k }'
fails:A lambda literal -> () { } assigns variables from parameters for definition '@a = -> (&b) { b }'
fails:A lambda literal -> () { } assigns variables from parameters for definition '@a = -> (*, &b) { b }'
fails:"A lambda literal -> () { } assigns variables from parameters for definition \n @a = -> (a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l) do\n [a, b, c, d, e, f, g, h, k, l]\n end"
fails:"A lambda literal -> () { } assigns variables from parameters for definition \n @a = -> a, b=1, *c, d, e:, f: 2, g:, **k, &l do\n [a, b, c, d, e, f, g, k, l]\n end"
fails:A lambda expression 'lambda { ... }' returns a lambda
fails:A lambda expression 'lambda { ... }' with an implicit block can be created
fails:"A lambda expression 'lambda { ... }' assigns variables from parameters for definition \n def m(*a) yield(*a) end\n @a = lambda { |a| a }"
fails:A lambda expression 'lambda { ... }' assigns variables from parameters for definition '@a = lambda { |a, | a }'
fails:"A lambda expression 'lambda { ... }' assigns variables from parameters for definition \n def m(a) yield a end\n def m2() yield end\n @a = lambda { |a, | a }"
fails:A lambda expression 'lambda { ... }' assigns variables from parameters for definition '@a = lambda { |a={}| a }'
fails:A lambda expression 'lambda { ... }' assigns variables from parameters for definition '@a = lambda { |**| }'
fails:A lambda expression 'lambda { ... }' assigns variables from parameters for definition '@a = lambda { |**k| k }'
fails:A lambda expression 'lambda { ... }' assigns variables from parameters for definition '@a = lambda { |*, **k| k }'
fails:A lambda expression 'lambda { ... }' assigns variables from parameters for definition '@a = lambda { |&b| b }'
fails:A lambda expression 'lambda { ... }' assigns variables from parameters for definition '@a = lambda { |*, &b| b }'
fails:"A lambda expression 'lambda { ... }' assigns variables from parameters for definition \n @a = lambda do |a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l|\n [a, b, c, d, e, f, g, h, k, l]\n end"
fails:"A lambda expression 'lambda { ... }' assigns variables from parameters for definition \n @a = lambda do |a, b=1, *c, d, e:, f: 2, g:, **k, &l|\n [a, b, c, d, e, f, g, k, l]\n end"
29 changes: 0 additions & 29 deletions tags/language/method_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions tags/language/proc_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
fails:A Proc taking zero arguments raises an ArgumentError if a value is passed
fails:A Proc taking || arguments raises an ArgumentError if a value is passed
fails:A Proc taking |a, *b| arguments does not destructure a single Array value yielded
fails:A Proc taking |a, | arguments raises an ArgumentError when passed more than one value
fails:A Proc taking |a, | arguments does not destructure when passed a single Array
12 changes: 0 additions & 12 deletions tags/language/send_tags.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,2 @@
fails:Invoking a method with only mandatory arguments raises ArgumentError if the methods arity doesn't match
fails:Invoking a method with optional arguments raises ArgumentError if extra arguments are passed
fails:Invoking a method with mandatory and optional arguments raises an ArgumentError if too many values are passed
fails:Invoking a private getter method does not permit self as a receiver
fails:Invoking a method accepts final explicit literal Hash arguments after the splat
fails:Invoking a method accepts final implicit literal Hash arguments after the splat
fails:Invoking a method accepts final Hash arguments after the splat
fails:Invoking a method accepts mandatory and explicit literal Hash arguments after the splat
fails:Invoking a method accepts mandatory and implicit literal Hash arguments after the splat
fails:Invoking a method accepts mandatory and Hash arguments after the splat
fails:Invoking a method expands the Array elements from the splat after executing the arguments and block if no other arguments follow the splat
fails:Invoking a method with optional argument(s), expands an array to arguments grouped in parentheses
fails:Invoking a method with required args after the rest arguments binds the required arguments first
fails:Invoking a method with mandatory arguments after optional arguments binds the required arguments first
2 changes: 0 additions & 2 deletions tags/language/yield_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ fails:The yield call taking a single argument yielding to a lambda passes an emp
fails:The yield call taking a single argument yielding to a lambda passes a single, multi-value Array
fails:The yield call taking a single argument yielding to a lambda should not destructure an Array into multiple arguments
fails:The yield call taking multiple arguments raises a LocalJumpError when the method is not passed a block
fails:The yield call taking multiple arguments raises an ArgumentError if too many arguments are passed to a lambda
fails:The yield call taking a single splatted argument raises a LocalJumpError when the method is not passed a block
fails:The yield call taking multiple arguments with a splat raises a LocalJumpError when the method is not passed a block
fails:The yield call taking multiple arguments with a splat passes the arguments to the block
Expand All @@ -16,4 +15,3 @@ fails:The yield call taking multiple arguments with a splat passes the Array ele
fails:The yield call taking multiple arguments with a splat does not pass an argument value if the splatted argument is nil
fails:The yield call taking matching arguments with splats and post args raises a LocalJumpError when the method is not passed a block
fails:The yield call taking matching arguments with splats and post args passes the arguments to the block
fails:The yield call taking a splat and a keyword argument passes it as an array of the values and a hash
7 changes: 2 additions & 5 deletions vm/frames/block_frame.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,11 @@ def initialize(parent_frame:, arg_values:, block:)
def prepare
values = arg_values

if iseq.args_info[:block_start]
values << block
end

MethodArguments.new(
iseq: iseq,
values: values,
locals: locals
locals: locals,
block: iseq.args_info[:block_start] ? block : nil
).extract(arity_check: is_lambda)

@kwoptarg_ids = (iseq.args_info[:keyword] || []).grep(Array).map { |name,| locals.find(name: name).id }
Expand Down
7 changes: 2 additions & 5 deletions vm/frames/method_frame.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,11 @@ def initialize(parent_nesting:, _self:, arg_values:, block:)
def prepare
values = arg_values

if iseq.args_info[:block_start]
values << block
end

MethodArguments.new(
iseq: iseq,
values: values,
locals: locals
locals: locals,
block: iseq.args_info[:block_start] ? block : nil
).extract(arity_check: true)

@kwoptarg_ids = (iseq.args_info[:keyword] || []).grep(Array).map { |name,| locals.find(name: name).id }
Expand Down
78 changes: 78 additions & 0 deletions vm/helpers/categorized_arguments.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
class CategorizedArguments
attr_reader :req, :opt, :rest, :post, :kw, :kwrest, :block

def initialize(arg_names, args_info)
@req = []
@opt = []
@rest = nil
@post = []
@kw = []
@kwrest = []
@block = nil

parse!(arg_names.dup, args_info.dup)
end

KwReq = Struct.new(:name, keyword_init: true)
InlineKwOpt = Struct.new(:name, :default, keyword_init: true)
DynamicKwOpt = Struct.new(:name, keyword_init: true)

def parse!(arg_names, args_info)
(args_info[:lead_num] || 0).times do
req << take_arg(arg_names)
end

opt_info = args_info[:opt].dup || []
opt_info.shift
opt_info.each do |label|
opt << [take_arg(arg_names), label]
end

if args_info[:rest_start]
@rest = take_arg(arg_names)
end

(args_info[:post_num] || 0).times do
post << take_arg(arg_names)
end

(args_info[:keyword] || []).each do |kwarg|
arg =
case kwarg
when Symbol
KwReq.new(name: kwarg)
when Array
if kwarg.length == 2
# inline default
InlineKwOpt.new(name: kwarg[0], default: kwarg[1])
else
# complex default, set in the iseq
DynamicKwOpt.new(name: kwarg[0])
end
else
raise VM::InternalError, "Unknown kwarg #{kwarg}"
end

arg_names.delete(arg.name)
kw << arg
end

if args_info[:kwrest]
kwrest << take_arg(arg_names) << take_arg(arg_names)
end

if args_info[:block_start]
@block = take_arg(arg_names)
end
end

def take_arg(arg_names)
arg_name_or_idx = arg_names.shift

if arg_name_or_idx.is_a?(Integer)
arg_name_or_idx += 1
end

arg_name_or_idx
end
end
Loading

0 comments on commit bceb7ff

Please sign in to comment.