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.



7
8
9
10
11
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 7

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

Instance Attribute Details

#scope_chainObject (readonly)

Returns the value of attribute scope_chain.



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

def scope_chain
  @scope_chain
end

Instance Method Details

#visit_AddNode(o) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
# 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) ⇒ Object



243
244
245
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 243

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

#visit_AssignExprNode(o) ⇒ Object



139
140
141
# 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) ⇒ Object



207
208
209
210
211
# 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) ⇒ Object



194
195
196
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 194

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

#visit_DivideNode(o) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# 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) ⇒ Object



180
181
182
183
184
185
# 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) ⇒ Object



187
188
189
190
191
192
# 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) ⇒ Object



50
51
52
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 50

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

#visit_FalseNode(o) ⇒ Object



160
161
162
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 160

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

#visit_FunctionBodyNode(o) ⇒ Object



198
199
200
201
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 198

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

#visit_FunctionCallNode(o) ⇒ Object



170
171
172
173
174
# 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) ⇒ Object



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

def visit_FunctionDeclNode(o)
end

#visit_IfNode(o) ⇒ Object



33
34
35
36
37
38
39
40
# 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) ⇒ Object



237
238
239
240
241
# 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) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# 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) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 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) ⇒ Object



176
177
178
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 176

def visit_NewExprNode(o)
  visit_FunctionCallNode(o)
end

#visit_NullNode(o) ⇒ Object



152
153
154
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 152

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

#visit_NumberNode(o) ⇒ Object



143
144
145
# 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) ⇒ Object



127
128
129
130
131
132
133
# 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) ⇒ Object



135
136
137
# 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) ⇒ Object



213
214
215
216
217
218
219
220
221
222
223
# 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) ⇒ Object



225
226
227
228
229
230
231
232
233
234
235
# 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) ⇒ Object



42
43
44
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 42

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

#visit_ReturnNode(o) ⇒ Object



203
204
205
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 203

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

#visit_SourceElementsNode(o) ⇒ Object



13
14
15
16
17
18
# 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) ⇒ Object



164
165
166
167
168
# 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) ⇒ Object



67
68
69
70
71
# 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) ⇒ Object



46
47
48
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 46

def visit_ThisNode(o)
  scope_chain.this
end

#visit_TrueNode(o) ⇒ Object



156
157
158
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 156

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

#visit_TypeOfNode(o) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# 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) ⇒ Object



272
273
274
275
276
277
# 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) ⇒ Object



267
268
269
270
# 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) ⇒ Object



27
28
29
30
31
# 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) ⇒ Object



23
24
25
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 23

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

#visit_VoidNode(o) ⇒ Object



147
148
149
150
# File 'lib/rkelly/visitors/evaluation_visitor.rb', line 147

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