10 result
= RootNode.new
(val
[0])
16 { result.push val
[1] }
23 result
= FuncallNode.new
(@fname
, val
[0][0], val
[0][1], [val
[1]])
29 defun
: DEF IDENT param EOL stmt_list END
31 result
= DefNode.new
(@fname
, val
[0][0], val
[1][1],
32 Function.new
(@fname
, val
[0][0], val
[2], val
[4]))
35 param
: '(' name_list
')'
43 { result
= [val
[0][1]] }
45 { result.push val
[2][1] }
47 if_stmt
: IF stmt THEN EOL stmt_list else_stmt END
49 result
= IfNode.new
(@fname
, val
[0][0], val
[1], val
[4], val
[5])
52 else_stmt: ELSE EOL stmt_list
57 while_stmt: WHILE stmt DO EOL stmt_list END
59 result
= WhileNode.new
(@fname
, val
[0][0], val
[1], val
[4])
62 funcall
: IDENT
'(' args
')'
64 result
= FuncallNode.new
(@fname
, val
[0][0], val
[0][1], val
[2])
68 result
= FuncallNode.new
(@fname
, val
[0][0], val
[0][1], [])
80 assign
: IDENT
'=' expr
82 result
= AssignNode.new
(@fname
, val
[0][0], val
[0][1], val
[2])
87 result
= FuncallNode.new
(@fname
, val
[0].lineno
, '+', [val
[0], val
[2]])
91 result
= FuncallNode.new
(@fname
, val
[0].lineno
, '-', [val
[0], val
[2]])
95 result
= FuncallNode.new
(@fname
, val
[0].lineno
, '*', [val
[0], val
[2]])
99 result
= FuncallNode.new
(@fname
, val
[0].lineno
, '/', [val
[0], val
[2]])
107 |
'-' primary
=UMINUS
108 { result
= FuncallNode.new
(@fname
, val
[0].lineno
, '-@', [val
[1]]) }
111 { result
= NilNode.new
(@fname
, *val
[0]) }
113 { result
= TrueNode.new
(@fname
, *val
[0]) }
115 { result
= FalseNode.new
(@fname
, *val
[0]) }
118 result
= VarRefNode.new
(@fname
, val
[0][0], val
[0][1])
122 result
= LiteralNode.new
(@fname
, *val
[0])
126 result
= StringNode.new
(@fname
, *val
[0])
157 when
/\A\s
+/, /\A\
#.*\z/
159 when
/\A
[a
-zA
-Z_
]\w*/
161 @q.push
([RESERVED
[word
]||
:IDENT
, [@lineno
, word.intern
]])
163 @q.push
([:NUMBER
, [@lineno
, $
&.to_i
]])
164 when
/\A
['"](?:[^"'\\]+|
\\.
)*['"]/
165 @q.push([:STRING, [@lineno, eval($&)]])
167 @q.push([$&, [@lineno, $&]])
169 raise RuntimeError, 'must not happen
'
173 @q.push
([:EOL
, [@lineno
, nil
]])
175 @q.push
([false
, '$'])
184 def on_error
(t
, v
, vstack
)
191 raise Racc
::ParseError
, "#{@fname}:#{line}: syntax error on #{v.inspect}"
196 class IntpError
< StandardError
; end
199 def initialize
(fname
, linno
)
207 def exec_list
(intp
, nodes
)
209 nodes.each
{|i| v
= i.evaluate
(intp
) }
214 raise IntpError
, "in #{filename}:#{lineno}: #{msg}"
218 "#{type.name}/#{lineno}"
222 class RootNode
< Node
229 exec_list Intp.new
, @tree
233 class FuncallNode
< Node
234 def initialize
(fname
, lineno
, func
, args
)
241 arg
= @args.collect
{|i| i.evaluate
}
243 if recv.respond_to?
(@func
, true
)
245 elsif arg
[0] && arg
[0].respond_to?
(@func
)
248 intp_error
! "undefined method #{@func.id2name}"
250 recv.send
(@func
, *arg
)
255 def initialize
(fname
, lineno
, cond
, tstmt
, fstmt
)
263 if @condition.evaluate
266 exec_list @fstmt if @fstmt
271 class WhileNode
< Node
272 def initialize
(fname
, lineno
, cond
, body
)
279 while @condition.evaluate
!= 0 do
285 class AssignNode
< Node
286 def initialize
(fname
, lineno
, vtable
, vname
, val
)
294 @vtable
[@vname
] = @val.evaluate
298 class VarRefNode
< Node
299 def initialize
(fname
, lineno
, vname
)
305 if intp.frame.lvar? @vname
308 intp.call_function_or
(@vname
, []) do
309 intp_error
! "unknown method or local variable #{@vname.id2name}"
315 class StringNode
< Node
316 def initialize
(fname
, lineno
, str
)
326 class LiteralNode
< Node
327 def initialize
(fname
, lineno
, val
)
338 def initialize
(fname
, lineno
, val
)
347 class TrueNode
< Node
348 def initialize
(fname
, lineno
, val
)
357 class FalseNode
< Node
358 def initialize
(fname
, lineno
, val
)
372 @stack.push
(IntpFrame.new
('(Toplevel)'))
379 def define_function
(fname
, node
)
381 raise IntpError
, "function #{fname.id2name} defined twice"
386 def call_function_or
(fname
, args
)
387 call_intp_function_or
(fname
, args
) do
388 call_ruby_toplevel_or
(fname
, args
) do
394 def call_intp_function_or
(fname
, args
)
395 if func
= @ftab
[fname
]
396 frame
= IntpFrame.new fname
398 func.call self
, frame
, args
405 def call_ruby_toplevel_or
(fname
, args
)
406 if @obj.respond_to? fname
, true
407 @obj.send fname
, *args
415 def initialize
(fname
)
436 def initialize
(file
, nineno
, fname
, func
)
443 intp.define_function @funcname
, @funcobj
447 class Function
< Node
448 def initialize
(file
, lineno
, param
, body
)
454 def call
(intp
, frame
, args
)
455 unless args.size
= @params.size
456 raise
(IntpArgumentError
, 'wrong # of arg for %S() (%d for %d)' %
[frame.fname
, args.size
, @params.size
])
458 args.each_with_index do |v
,i|
459 frame
[@params
[i
]] = v
461 exec_list intp
, @body
465 class FuncallNode
< Node
466 def initialize
(file
, lineno
, func
, args
)
473 arg
= @args.collect
{|i| i.evaluate intp
}
476 intp.call_function_or
(@funcname
, arg
) do
477 if arg.empty? or
!arg
[0].respond_to? @funcname
478 intp_error
! "undefined function #{@funcname.id2name}"
481 rescue INtpArgumentError
, ArgumentError
482 intp_error
! $
!.message
490 File.open
(ARGV
[0]) do |f|
491 tree
= TestParser.new.parse
(f
, ARGV
[0])
494 tree
= TestParser.new.parse
($stdin, '-')
498 rescue Racc
::ParseError
, IntpError
, Errno
::ENOENT
499 $stderr.puts
"#{File.basename($0)}: #{$!}"