Class: RubyLisp::Function
- Inherits:
-
Proc
- Object
- Proc
- RubyLisp::Function
- Defined in:
- lib/rubylisp/function.rb
Instance Attribute Summary collapse
-
#bindings ⇒ Object
Returns the value of attribute bindings.
-
#body ⇒ Object
Returns the value of attribute body.
-
#env ⇒ Object
Returns the value of attribute env.
-
#is_macro ⇒ Object
Returns the value of attribute is_macro.
-
#lambda ⇒ Object
Returns the value of attribute lambda.
-
#name ⇒ Object
Returns the value of attribute name.
Instance Method Summary collapse
- #construct_arities(asts) ⇒ Object
- #gen_env(arity, args, env) ⇒ Object
- #get_arity(args) ⇒ Object
-
#initialize(name, env, asts, &block) ⇒ Function
constructor
A new instance of Function.
Constructor Details
#initialize(name, env, asts, &block) ⇒ Function
Returns a new instance of Function.
46 47 48 49 50 51 52 53 |
# File 'lib/rubylisp/function.rb', line 46 def initialize(name, env, asts, &block) super() @name = name @env = env @arities = construct_arities(asts) @is_macro = false @lambda = block end |
Instance Attribute Details
#bindings ⇒ Object
Returns the value of attribute bindings.
44 45 46 |
# File 'lib/rubylisp/function.rb', line 44 def bindings @bindings end |
#body ⇒ Object
Returns the value of attribute body.
44 45 46 |
# File 'lib/rubylisp/function.rb', line 44 def body @body end |
#env ⇒ Object
Returns the value of attribute env.
44 45 46 |
# File 'lib/rubylisp/function.rb', line 44 def env @env end |
#is_macro ⇒ Object
Returns the value of attribute is_macro.
44 45 46 |
# File 'lib/rubylisp/function.rb', line 44 def is_macro @is_macro end |
#lambda ⇒ Object
Returns the value of attribute lambda.
44 45 46 |
# File 'lib/rubylisp/function.rb', line 44 def lambda @lambda end |
#name ⇒ Object
Returns the value of attribute name.
44 45 46 |
# File 'lib/rubylisp/function.rb', line 44 def name @name end |
Instance Method Details
#construct_arities(asts) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/rubylisp/function.rb', line 55 def construct_arities(asts) arities_hash = asts.each_with_object({'arities' => [], 'required' => 0}) do |ast, result| arity = Arity.new(ast) if arity.rest_args.empty? # Prevent conflicts like [x] vs. [y] if result['arities'].any? {|existing| existing.required_args.count == arity.required_args.count && existing.rest_args.empty? } raise RuntimeError, "Can't have multiple overloads with the same arity." end # Prevent conflicts like [& xs] vs. [x] if result['rest_required'] unless arity.required_args.count <= result['rest_required'] raise RuntimeError, "Can't have a fixed arity function with more params than a " + "variadic function." end end else # Prevent conflicts like [x] vs. [& xs] if arity.required_args.count < result['required'] raise RuntimeError, "Can't have a fixed arity function with more params than a " + "variadic function." end # Prevent conflicts like [x & xs] vs. [x y & ys] if result['arities'].any? {|existing| !existing.rest_args.empty?} raise RuntimeError, "Can't have more than one variadic overload." end result['rest_required'] = arity.required_args.count end result['required'] = [result['required'], arity.required_args.count].max result['arities'] << arity end arities_hash['arities'] end |
#gen_env(arity, args, env) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/rubylisp/function.rb', line 121 def gen_env(arity, args, env) # set out_env to the current namespace so that `def` occurring within # the fn's environment will define things in the namespace in which the # function is called out_env = env.out_env || env.find_namespace env = Environment.new(outer: @env, out_env: out_env) # so the fn can call itself recursively env.set(@name, self) if arity.rest_args.empty? # bind values to the required args arity.required_args.zip(args).each do |k, v| env.set(k, v) end else # bind values to the required args (the rest args are skipped here) arity.required_args.zip(args).each do |k, v| env.set(k, v) end # bind the rest argument to the remaining arguments or nil rest_args = if args.count > arity.required_args.count args[arity.required_args.count..-1].to_list else nil end env.set(arity.rest_args.first, rest_args) end env end |
#get_arity(args) ⇒ Object
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/rubylisp/function.rb', line 102 def get_arity(args) # Assert that there are enough arguments provided for the arities we have. sexp = list [Symbol.new(@name), *args] variadic = @arities.find {|arity| !arity.rest_args.empty?} fixed_arities = @arities.select {|arity| arity.rest_args.empty?} fixed = fixed_arities.find {|arity| arity.required_args.count == args.count} # Return the arity most appropriate for the number of args provided. if fixed fixed elsif variadic assert_at_least_n_args sexp, variadic.required_args.count variadic else raise RuntimeError, "Wrong number of args (#{args.count}) passed to #{@name}" end end |