class RKelly::Visitors::EvaluationVisitor
Attributes
scope_chain[R]
Public Class Methods
new(scope)
click to toggle source
Calls superclass method
# File lib/rkelly/visitors/evaluation_visitor.rb, line 7 def initialize(scope) super() @scope_chain = scope @operand = [] end
Public Instance Methods
visit_AddNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 54 def visit_AddNode(o) left = to_primitive(o.left.accept(self), 'Number') right = to_primitive(o.value.accept(self), 'Number') if left.value.is_a?(::String) || right.value.is_a?(::String) RKelly::JS::Property.new(:add, "#{left.value}#{right.value}" ) else additive_operator(:+, left, right) end end
visit_ArgumentsNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 243 def visit_ArgumentsNode(o) o.value.map { |x| x.accept(self) } end
visit_AssignExprNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 139 def visit_AssignExprNode(o) scope_chain[@operand.last] = o.value.accept(self) end
visit_BitwiseNotNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 207 def visit_BitwiseNotNode(o) orig = o.value.accept(self) number = to_int_32(orig) RKelly::JS::Property.new(nil, ~number.value) end
visit_BlockNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 194 def visit_BlockNode(o) o.value.accept(self) end
visit_DivideNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 88 def visit_DivideNode(o) left = to_number(o.left.accept(self)).value right = to_number(o.value.accept(self)).value return_val = if [left, right].any? { |x| x.respond_to?(:nan?) && x.nan? || x.respond_to?(:intinite?) && x.infinite? } RKelly::JS::NaN.new elsif [left, right].all? { |x| x == 0 } RKelly::JS::NaN.new elsif right == 0 left * (right.eql?(0) ? (1.0/0.0) : (-1.0/0.0)) else left / right end RKelly::JS::Property.new(:divide, return_val) end
visit_DotAccessorNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 180 def visit_DotAccessorNode(o) left = o.value.accept(self) right = left.value[o.accessor] right.binder = left.value right end
visit_EqualNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 187 def visit_EqualNode(o) left = o.left.accept(self) right = o.value.accept(self) RKelly::JS::Property.new(:equal_node, left.value == right.value) end
visit_ExpressionStatementNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 50 def visit_ExpressionStatementNode(o) o.value.accept(self) end
visit_FalseNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 160 def visit_FalseNode(o) RKelly::JS::Property.new(false, false) end
visit_FunctionBodyNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 198 def visit_FunctionBodyNode(o) o.value.accept(self) scope_chain.return end
visit_FunctionCallNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 170 def visit_FunctionCallNode(o) left = o.value.accept(self) arguments = o.arguments.accept(self) call_function(left, arguments) end
visit_FunctionDeclNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 20 def visit_FunctionDeclNode(o) end
visit_IfNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 33 def visit_IfNode(o) truthiness = o.conditions.accept(self) if truthiness.value && truthiness.value != 0 o.value.accept(self) else o.else && o.else.accept(self) end end
visit_LogicalNotNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 237 def visit_LogicalNotNode(o) bool = to_boolean(o.value.accept(self)) bool.value = !bool.value bool end
visit_ModulusNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 107 def visit_ModulusNode(o) left = to_number(o.left.accept(self)).value right = to_number(o.value.accept(self)).value return_val = if [left, right].any? { |x| x.respond_to?(:nan?) && x.nan? } RKelly::JS::NaN.new elsif [left, right].all? { |x| x.respond_to?(:infinite?) && x.infinite? } RKelly::JS::NaN.new elsif right == 0 RKelly::JS::NaN.new elsif left.respond_to?(:infinite?) && left.infinite? RKelly::JS::NaN.new elsif right.respond_to?(:infinite?) && right.infinite? left else left % right end RKelly::JS::Property.new(:divide, return_val) end
visit_MultiplyNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 73 def visit_MultiplyNode(o) left = to_number(o.left.accept(self)).value right = to_number(o.value.accept(self)).value return_val = if [left, right].any? { |x| x.respond_to?(:nan?) && x.nan? } RKelly::JS::NaN.new else [left, right].any? { |x| x.respond_to?(:intinite?) && x.infinite? } && [left, right].any? { |x| x == 0 } ? RKelly::JS::NaN.new : left * right end RKelly::JS::Property.new(:multiple, return_val) end
visit_NewExprNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 176 def visit_NewExprNode(o) visit_FunctionCallNode(o) end
visit_NullNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 152 def visit_NullNode(o) RKelly::JS::Property.new(nil, nil) end
visit_NumberNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 143 def visit_NumberNode(o) RKelly::JS::Property.new(o.value, o.value) end
visit_OpEqualNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 127 def visit_OpEqualNode(o) left = o.left.accept(self) right = o.value.accept(self) left.value = right.value left.function = right.function left end
visit_OpPlusEqualNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 135 def visit_OpPlusEqualNode(o) o.left.accept(self).value += o.value.accept(self).value end
visit_PostfixNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 213 def visit_PostfixNode(o) orig = o.operand.accept(self) number = to_number(orig) case o.value when '++' orig.value = number.value + 1 when '--' orig.value = number.value - 1 end number end
visit_PrefixNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 225 def visit_PrefixNode(o) orig = o.operand.accept(self) number = to_number(orig) case o.value when '++' orig.value = number.value + 1 when '--' orig.value = number.value - 1 end orig end
visit_ResolveNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 42 def visit_ResolveNode(o) scope_chain[o.value] end
visit_ReturnNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 203 def visit_ReturnNode(o) scope_chain.return = o.value.accept(self) end
visit_SourceElementsNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 13 def visit_SourceElementsNode(o) o.value.each { |x| next if scope_chain.returned? x.accept(self) } end
visit_StringNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 164 def visit_StringNode(o) RKelly::JS::Property.new(:string, o.value.gsub(/\A['"]/, '').gsub(/['"]$/, '') ) end
visit_SubtractNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 67 def visit_SubtractNode(o) RKelly::JS::Property.new(:subtract, o.left.accept(self).value - o.value.accept(self).value ) end
visit_ThisNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 46 def visit_ThisNode(o) scope_chain.this end
visit_TrueNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 156 def visit_TrueNode(o) RKelly::JS::Property.new(true, true) end
visit_TypeOfNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 247 def visit_TypeOfNode(o) val = o.value.accept(self) return RKelly::JS::Property.new(:string, 'object') if val.value.nil? case val.value when String RKelly::JS::Property.new(:string, 'string') when Numeric RKelly::JS::Property.new(:string, 'number') when true RKelly::JS::Property.new(:string, 'boolean') when false RKelly::JS::Property.new(:string, 'boolean') when :undefined RKelly::JS::Property.new(:string, 'undefined') else RKelly::JS::Property.new(:object, 'object') end end
visit_UnaryMinusNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 272 def visit_UnaryMinusNode(o) orig = o.value.accept(self) v = to_number(orig) v.value = v.value == 0 ? -0.0 : 0 - v.value v end
visit_UnaryPlusNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 267 def visit_UnaryPlusNode(o) orig = o.value.accept(self) to_number(orig) end
visit_VarDeclNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 27 def visit_VarDeclNode(o) @operand << o.name o.value.accept(self) if o.value @operand.pop end
visit_VarStatementNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 23 def visit_VarStatementNode(o) o.value.each { |x| x.accept(self) } end
visit_VoidNode(o)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 147 def visit_VoidNode(o) o.value.accept(self) RKelly::JS::Property.new(:undefined, :undefined) end
Private Instance Methods
additive_operator(operator, left, right)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 390 def additive_operator(operator, left, right) left, right = to_number(left).value, to_number(right).value left = left.respond_to?(:nan?) && left.nan? ? 0.0/0.0 : left right = right.respond_to?(:nan?) && right.nan? ? 0.0/0.0 : right result = left.send(operator, right) result = result.respond_to?(:nan?) && result.nan? ? JS::NaN.new : result RKelly::JS::Property.new(operator, result) end
call_function(property, arguments = [])
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 402 def call_function(property, arguments = []) function = property.function || property.value case function when RKelly::JS::Function scope_chain.new_scope { |chain| function.js_call(chain, *arguments) } when UnboundMethod RKelly::JS::Property.new(:ruby, function.bind(property.binder).call(*(arguments.map { |x| x.value})) ) else RKelly::JS::Property.new(:ruby, function.call(*(arguments.map { |x| x.value })) ) end end
to_boolean(object)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 344 def to_boolean(object) return RKelly::JS::Property.new(false, false) unless object.value value = object.value boolean = case value when :undefined false when true true when Numeric value == 0 || value.respond_to?(:nan?) && value.nan? ? false : true when ::String value.length == 0 ? false : true when RKelly::JS::Base true else raise end RKelly::JS::Property.new(boolean, boolean) end
to_int_32(object)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 365 def to_int_32(object) number = to_number(object) value = number.value return number if value == 0 if value.respond_to?(:nan?) && (value.nan? || value.infinite?) RKelly::JS::Property.new(nil, 0) end value = ((value < 0 ? -1 : 1) * value.abs.floor) % (2 ** 32) if value >= 2 ** 31 RKelly::JS::Property.new(nil, value - (2 ** 32)) else RKelly::JS::Property.new(nil, value) end end
to_number(object)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 306 def to_number(object) return RKelly::JS::Property.new('0', 0) unless object.value return_val = case object.value when :undefined RKelly::JS::NaN.new when false 0 when true 1 when Numeric object.value when ::String s = object.value.gsub(/(\A[\s\xA0]*|[\s\xA0]*\Z)/, '') if s.length == 0 0 else case s when /^([+-])?Infinity/ $1 == '-' ? -1.0/0.0 : 1.0/0.0 when /\A[-+]?\d+\.\d*(?:[eE][-+]?\d+)?$|\A[-+]?\d+(?:\.\d*)?[eE][-+]?\d+$|\A[-+]?\.\d+(?:[eE][-+]?\d+)?$/, /\A[-+]?0[xX][\da-fA-F]+$|\A[+-]?0[0-7]*$|\A[+-]?\d+$/ s.gsub!(/\.(\D)/, '.0\1') if s =~ /\.\w/ s.gsub!(/\.$/, '.0') if s =~ /\.$/ s.gsub!(/^\./, '0.') if s =~ /^\./ s.gsub!(/^([+-])\./, '\10.') if s =~ /^[+-]\./ s = s.gsub(/^[0]*/, '') if /^0[1-9]+$/.match(s) eval(s) else RKelly::JS::NaN.new end end when RKelly::JS::Base return to_number(to_primitive(object, 'Number')) end RKelly::JS::Property.new(nil, return_val) end
to_primitive(object, preferred_type = nil)
click to toggle source
# File lib/rkelly/visitors/evaluation_visitor.rb, line 380 def to_primitive(object, preferred_type = nil) return object unless object.value case object.value when false, true, :undefined, ::String, Numeric RKelly::JS::Property.new(nil, object.value) when RKelly::JS::Base call_function(object.value.default_value(preferred_type)) end end