Class: RKelly::Visitors::EvaluationVisitor

Inherits:
Visitor
  • Object
show all
Defined in:
lib/rkelly/visitors/evaluation_visitor.rb

Constant Summary

Constants inherited from Visitor

Visitor::ALL_NODES, Visitor::ARRAY_VALUE_NODES, Visitor::BINARY_NODES, Visitor::CONDITIONAL_NODES, Visitor::FUNC_CALL_NODES, Visitor::FUNC_DECL_NODES, Visitor::NAME_VALUE_NODES, Visitor::PREFIX_POSTFIX_NODES, Visitor::SINGLE_VALUE_NODES, Visitor::TERMINAL_NODES

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Visitor

#accept, #visit_BracketAccessorNode, #visit_ForInNode, #visit_ForNode, #visit_TryNode

Constructor Details

#initialize(scope) ⇒ EvaluationVisitor

Returns a new instance of EvaluationVisitor.



5
6
7
8
9
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 5

def initialize(scope)
  super()
  @scope_chain = scope
  @operand = []
end

Instance Attribute Details

#scope_chainObject (readonly)

Returns the value of attribute scope_chain.



4
5
6
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 4

def scope_chain
  @scope_chain
end

Instance Method Details

#visit_AddNode(o) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 52

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) ⇒ Object



241
242
243
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 241

def visit_ArgumentsNode(o)
  o.value.map { |x| x.accept(self) }
end

#visit_AssignExprNode(o) ⇒ Object



137
138
139
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 137

def visit_AssignExprNode(o)
  scope_chain[@operand.last] = o.value.accept(self)
end

#visit_BitwiseNotNode(o) ⇒ Object



205
206
207
208
209
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 205

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) ⇒ Object



192
193
194
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 192

def visit_BlockNode(o)
  o.value.accept(self)
end

#visit_DivideNode(o) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 86

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) ⇒ Object



178
179
180
181
182
183
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 178

def visit_DotAccessorNode(o)
  left = o.value.accept(self)
  right = left.value[o.accessor]
  right.binder = left.value
  right
end

#visit_EqualNode(o) ⇒ Object



185
186
187
188
189
190
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 185

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) ⇒ Object



48
49
50
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 48

def visit_ExpressionStatementNode(o)
  o.value.accept(self)
end

#visit_FalseNode(o) ⇒ Object



158
159
160
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 158

def visit_FalseNode(o)
  RKelly::JS::Property.new(false, false)
end

#visit_FunctionBodyNode(o) ⇒ Object



196
197
198
199
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 196

def visit_FunctionBodyNode(o)
  o.value.accept(self)
  scope_chain.return
end

#visit_FunctionCallNode(o) ⇒ Object



168
169
170
171
172
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 168

def visit_FunctionCallNode(o)
  left      = o.value.accept(self)
  arguments = o.arguments.accept(self)
  call_function(left, arguments)
end

#visit_FunctionDeclNode(o) ⇒ Object



18
19
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 18

def visit_FunctionDeclNode(o)
end

#visit_IfNode(o) ⇒ Object



31
32
33
34
35
36
37
38
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 31

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) ⇒ Object



235
236
237
238
239
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 235

def visit_LogicalNotNode(o)
  bool = to_boolean(o.value.accept(self))
  bool.value = !bool.value
  bool
end

#visit_ModulusNode(o) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 105

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) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 71

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) ⇒ Object



174
175
176
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 174

def visit_NewExprNode(o)
  visit_FunctionCallNode(o)
end

#visit_NullNode(o) ⇒ Object



150
151
152
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 150

def visit_NullNode(o)
  RKelly::JS::Property.new(nil, nil)
end

#visit_NumberNode(o) ⇒ Object



141
142
143
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 141

def visit_NumberNode(o)
  RKelly::JS::Property.new(o.value, o.value)
end

#visit_OpEqualNode(o) ⇒ Object



125
126
127
128
129
130
131
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 125

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) ⇒ Object



133
134
135
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 133

def visit_OpPlusEqualNode(o)
  o.left.accept(self).value += o.value.accept(self).value
end

#visit_PostfixNode(o) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 211

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) ⇒ Object



223
224
225
226
227
228
229
230
231
232
233
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 223

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) ⇒ Object



40
41
42
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 40

def visit_ResolveNode(o)
  scope_chain[o.value]
end

#visit_ReturnNode(o) ⇒ Object



201
202
203
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 201

def visit_ReturnNode(o)
  scope_chain.return = o.value.accept(self)
end

#visit_SourceElementsNode(o) ⇒ Object



11
12
13
14
15
16
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 11

def visit_SourceElementsNode(o)
  o.value.each { |x|
    next if scope_chain.returned?
    x.accept(self)
  }
end

#visit_StringNode(o) ⇒ Object



162
163
164
165
166
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 162

def visit_StringNode(o)
  RKelly::JS::Property.new(:string,
    o.value.gsub(/\A['"]/, '').gsub(/['"]$/, '')
  )
end

#visit_SubtractNode(o) ⇒ Object



65
66
67
68
69
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 65

def visit_SubtractNode(o)
  RKelly::JS::Property.new(:subtract,
    o.left.accept(self).value - o.value.accept(self).value
  )
end

#visit_ThisNode(o) ⇒ Object



44
45
46
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 44

def visit_ThisNode(o)
  scope_chain.this
end

#visit_TrueNode(o) ⇒ Object



154
155
156
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 154

def visit_TrueNode(o)
  RKelly::JS::Property.new(true, true)
end

#visit_TypeOfNode(o) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 245

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) ⇒ Object



270
271
272
273
274
275
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 270

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) ⇒ Object



265
266
267
268
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 265

def visit_UnaryPlusNode(o)
  orig = o.value.accept(self)
  to_number(orig)
end

#visit_VarDeclNode(o) ⇒ Object



25
26
27
28
29
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 25

def visit_VarDeclNode(o)
  @operand << o.name
  o.value.accept(self) if o.value
  @operand.pop
end

#visit_VarStatementNode(o) ⇒ Object



21
22
23
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 21

def visit_VarStatementNode(o)
  o.value.each { |x| x.accept(self) }
end

#visit_VoidNode(o) ⇒ Object



145
146
147
148
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 145

def visit_VoidNode(o)
  o.value.accept(self)
  RKelly::JS::Property.new(:undefined, :undefined)
end