class AST::FunctionCall attr_reader :function, :arguments def initialize(function, arguments) @function = function @arguments = arguments end def ==(other) other.is_a?(AST::FunctionCall) && other.function == @function && other.arguments == @arguments end def execute(env) function = env.get(@function.name) if function.is_a?(AST::FunctionDefinition) if @arguments.size != function.parameters.size raise "Arity mismatch in call to function #{function.name}" end function.parameters.each_with_index do |param, i| env.set(param.name, @arguments[i].execute(env)) end value = nil function.body.statements.each do |statement| value = statement.execute(env) end value elsif function.is_a?(Proc) arguments = @arguments.map { |arg| arg.execute(env) } function.call(*arguments) end end end