nendo 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1349 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+ #
4
+ # evaluator.rb - "evaluator for nendo"
5
+ #
6
+ # Copyright (c) 2009-2010 Kiyoka Nishiyama <kiyoka@sumibi.org>
7
+ #
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions
10
+ # are met:
11
+ #
12
+ # 1. Redistributions of source code must retain the above copyright
13
+ # notice, this list of conditions and the following disclaimer.
14
+ #
15
+ # 2. Redistributions in binary form must reproduce the above copyright
16
+ # notice, this list of conditions and the following disclaimer in the
17
+ # documentation and/or other materials provided with the distribution.
18
+ #
19
+ # 3. Neither the name of the authors nor the names of its contributors
20
+ # may be used to endorse or promote products derived from this
21
+ # software without specific prior written permission.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ #
35
+ module Nendo
36
+
37
+ # Translate S expression to Ruby expression and Evaluation
38
+ class Evaluator
39
+ include BuiltinFunctions
40
+ EXEC_TYPE_NORMAL = 1
41
+ EXEC_TYPE_ANONYMOUS = 2
42
+ EXEC_TYPE_TAILCALL = 3
43
+
44
+ def initialize( core, debug = false )
45
+ @core = core
46
+ @indent = " "
47
+ @binding = binding
48
+ @debug = debug
49
+ @trace_debug = false
50
+ @lexicalVars = []
51
+ @syntaxHash = {}
52
+ @optimize_level = 2
53
+ @backtrace = {}
54
+ @backtrace_counter = 1;
55
+ @displayErrorsFlag = true;
56
+ @char_table_lisp_to_ruby = {
57
+ # list (! $ % & * + - . / : < = > ? @ ^ _ ~ ...)
58
+ '!' => '_EXMARK',
59
+ '$' => '_DOMARK',
60
+ '%' => '_PAMARK',
61
+ '&' => '_ANMARK',
62
+ '*' => '_ASMARK',
63
+ '+' => '_PLMARK',
64
+ '-' => '_MIMARK',
65
+ # '.'
66
+ '/' => '_SLMARK',
67
+ ':' => '_COMARK',
68
+ '<' => '_LTMARK',
69
+ '=' => '_EQMARK',
70
+ '>' => '_GTMARK',
71
+ '?' => '_QUMARK',
72
+ '@' => '_ATMARK',
73
+ '^' => '_NKMARK',
74
+ # '_'
75
+ '~' => '_CHMARK',
76
+ '...' => '_DOTDOTDOT',
77
+ }
78
+ @char_table_ruby_to_lisp = @char_table_lisp_to_ruby.invert
79
+
80
+ @core_syntax_list = [ :quote, :"syntax-quote", :if , :begin , :lambda , :macro , :"&block" , :"%let" , :letrec , :define, :set!, :error, :"%syntax", :"define-syntax", :"let-syntax", :"%guard" ]
81
+ @core_syntax_hash = Hash.new
82
+ @core_syntax_list.each { |x|
83
+ renamed = ("/nendo/core/" + x.to_s).intern
84
+ @core_syntax_hash[ x ] = renamed
85
+ }
86
+
87
+ # toplevel binding
88
+ @global_lisp_binding = Hash.new
89
+
90
+ # initialize builtin functions as Proc objects
91
+ rubyExp = self.methods.select { |x|
92
+ x.to_s.match( /^_/ )
93
+ }.map { |name|
94
+ [
95
+ defMethodStr( name, false ),
96
+ sprintf( "@%s = self.method( :%s ).to_proc", name, name ),
97
+ sprintf( "@global_lisp_binding['%s'] = self.method( :%s_METHOD ).to_proc", name, name ),
98
+ ].join( " ; " )
99
+ }.join( " ; " )
100
+ eval( rubyExp, @binding )
101
+
102
+ # initialize builtin syntax as LispCoreSyntax
103
+ rubyExp = @core_syntax_hash.map { |k,v|
104
+ name1 = toRubySymbol( k )
105
+ name2 = toRubySymbol( v )
106
+ [ sprintf( "@%s = LispCoreSyntax.new( :\"%s\" ) ", name1, k ),
107
+ sprintf( "@global_lisp_binding['%s'] = @%s ", name1, name1 ),
108
+ sprintf( "@%s = @%s ", name2, name1 ),
109
+ sprintf( "@global_lisp_binding['%s'] = @%s ", name1, name2 ) ].join( " ; " )
110
+ }.join( " ; " )
111
+ eval( rubyExp, @binding )
112
+
113
+ # reset gensym counter
114
+ @gensym_counter = 0
115
+
116
+ # call depth counter
117
+ @call_depth = 0
118
+ @call_counters = Hash.new
119
+
120
+ # compiled ruby code
121
+ # { 'filename1' => [ 'code1' 'code2' ... ],
122
+ # 'filename2' => [ 'code1' 'code2' ... ], ... }
123
+ @compiled_code = Hash.new
124
+ @source_info_hash = Hash.new
125
+
126
+ global_lisp_define( toRubySymbol( "%compile-phase-functions" ), Cell.new())
127
+ load_path = $LOAD_PATH + [ File.dirname(__FILE__) ]
128
+ global_lisp_define( toRubySymbol( "*load-path*" ), load_path.to_list )
129
+ global_lisp_define( toRubySymbol( "*nendo-version*" ), Nendo::Core.version )
130
+ end
131
+
132
+ def global_lisp_define( rubySymbol, val )
133
+ @___tmp = val
134
+ eval( sprintf( "@%s = @___tmp;", rubySymbol ), @binding )
135
+ eval( sprintf( "@global_lisp_binding['%s'] = @___tmp;", rubySymbol ), @binding )
136
+ end
137
+
138
+ def setArgv( argv )
139
+ self.global_lisp_define( toRubySymbol( "*argv*"), argv.to_list )
140
+ end
141
+
142
+ def setOptimizeLevel( level )
143
+ @optimize_level = level
144
+ end
145
+
146
+ def getOptimizeLevel
147
+ @optimize_level
148
+ end
149
+
150
+ def setDisplayErrors( flag )
151
+ @displayErrorsFlag = flag
152
+ end
153
+
154
+ def lispMethodEntry( name, _log )
155
+ @call_depth += 1
156
+ if @trace_debug and _log
157
+ puts " " * @call_depth + "ENTRY: " + name
158
+ end
159
+ end
160
+ def lispMethodExit( name, _log )
161
+ if @trace_debug and _log
162
+ puts " " * @call_depth + "exit: " + name
163
+ end
164
+ @call_depth -= 1
165
+ end
166
+
167
+ def defMethodStr( name, _log )
168
+ [ "def self." + name.to_s + "_METHOD( origname, pred, args ) ",
169
+ " lispMethodEntry( origname, " + _log.to_s + " ) ; ",
170
+ " ret = callProcedure( '" + name.to_s + "', origname, pred, args ) ;",
171
+ " lispMethodExit( origname, " + _log.to_s + " ) ; ",
172
+ " return ret ",
173
+ "end " ].join
174
+ end
175
+
176
+ def _gensym( )
177
+ @gensym_counter += 1
178
+ filename = if @lastSourcefile.is_a? String
179
+ Digest::SHA1.hexdigest( @lastSourcefile )
180
+ else
181
+ ""
182
+ end
183
+ sprintf( "__gensym__%s_%d", filename, @gensym_counter ).intern
184
+ end
185
+
186
+ def forward_gensym_counter( )
187
+ @gensym_counter += 10000
188
+ end
189
+
190
+ def toRubyValue( val )
191
+ if NilClass == val.class
192
+ "nil"
193
+ elsif TrueClass == val.class
194
+ val.to_s
195
+ elsif FalseClass == val.class
196
+ val.to_s
197
+ else
198
+ val.to_s
199
+ end
200
+ end
201
+
202
+ def toRubySymbol( name )
203
+ if SyntacticClosure == name.class
204
+ "_" + name.to_s
205
+ else
206
+ name = name.to_s if Symbol == name.class
207
+ if 0 == name.length
208
+ ""
209
+ else
210
+ name.gsub!( Regexp.new( Regexp.escape( '...' )), @char_table_lisp_to_ruby[ '...' ] )
211
+ arr = name.gsub( /["]/, '' ).split( /[.]/ )
212
+ tmp = arr[0]
213
+ tmp.gsub!( /[:][:]/, " " ) # save '::'
214
+ @char_table_lisp_to_ruby.each_pair { |key,val|
215
+ tmp.gsub!( Regexp.new( Regexp.escape( key )), val )
216
+ }
217
+ arr[0] = tmp.gsub( /[ ][ ]/, "::" )
218
+ if arr[0].match( /^[A-Z]/ )
219
+ # nothing to do
220
+ elsif arr[0] == ""
221
+ arr[0] = 'Kernel'
222
+ else
223
+ arr[0] = '_' + arr[0]
224
+ end
225
+ arr.join( "." )
226
+ end
227
+ end
228
+ end
229
+
230
+ def isRubyInterface( name )
231
+ name.to_s.match( /[.]/ )
232
+ end
233
+
234
+ def toLispSymbol( name )
235
+ name = name.to_s if Symbol == name.class
236
+ raise ArgumentError, sprintf( "Error: `%s' is not a lisp symbol", name ) if not ('_' == name[0])
237
+ name = name[1..-1]
238
+ @char_table_ruby_to_lisp.each_pair { |key,val|
239
+ name = name.gsub( Regexp.new( key ), val )
240
+ }
241
+ name
242
+ end
243
+
244
+ def errorMessageOf_toRubyArgument( origname, no, req, got )
245
+ sprintf( "Error: [%s] wrong number of arguments for closure `%s' (requires %d, but got %d)", no, origname, req, got )
246
+ end
247
+
248
+ def toRubyArgument( origname, pred, args )
249
+ len = args.length
250
+ num = pred.arity
251
+ if 0 == num
252
+ raise ArgumentError, errorMessageOf_toRubyArgument( origname, 1, num, len ) if 0 != len
253
+ []
254
+ elsif 0 < num
255
+ if 0 == len
256
+ raise ArgumentError, errorMessageOf_toRubyArgument( origname, 4, num, len )
257
+ else
258
+ raise ArgumentError, errorMessageOf_toRubyArgument( origname, 2, num, len ) if num != len
259
+ args
260
+ end
261
+ else
262
+ num = num.abs( )-1
263
+ raise ArgumentError, errorMessageOf_toRubyArgument( origname, 3, num, len ) if num > len
264
+ params = []
265
+ rest = []
266
+ args.each_with_index { |x,i|
267
+ if i < num
268
+ params << x
269
+ else
270
+ rest << x
271
+ end
272
+ }
273
+ result = []
274
+ if 0 < params.length
275
+ result = params
276
+ end
277
+ if 0 == rest.length
278
+ result << Cell.new
279
+ else
280
+ result << rest.to_list
281
+ end
282
+ result
283
+ end
284
+ end
285
+
286
+ def trampCall( result )
287
+ while result.class == DelayedCallPacket
288
+ result = __send__( result.rubysym + "_METHOD", result.origname, result.pred, result.args )
289
+ end
290
+ result
291
+ end
292
+
293
+ def method_missing( name, *args )
294
+ if @global_lisp_binding[name].is_a? Proc
295
+ @global_lisp_binding[name].call( args[0], args[1], args[2] )
296
+ else
297
+ callProcedure( name, args[0], args[1], args[2] )
298
+ end
299
+ end
300
+
301
+ def delayCall( rubysym, origname, pred, args )
302
+ case @optimize_level
303
+ when 0 # no optimize
304
+ callProcedure( rubysym, origname, pred, args )
305
+ else # tail call optimization
306
+ DelayedCallPacket.new( rubysym, origname, pred, args )
307
+ end
308
+ end
309
+
310
+ def callProcedure( rubysym, origname, pred, args )
311
+ if @call_counters.has_key?( origname )
312
+ @call_counters[ origname ] += 1
313
+ else
314
+ @call_counters[ origname ] = 1
315
+ end
316
+ result = pred.call( *toRubyArgument( origname, pred, args ))
317
+
318
+ @call_counters[ origname ] -= 1
319
+
320
+ result
321
+ end
322
+
323
+ # for code generation of Ruby's argument values
324
+ # in case: str = ","
325
+ # [1,"2",3] => [
326
+ # [ 1, ","]
327
+ # ["2", ","]
328
+ # [ 3 ]
329
+ # ]
330
+ def separateWith( arr, str )
331
+ seps = []
332
+ (arr.length-1).times {|n| seps << str }
333
+ arr.zip( seps ).map{ |x|
334
+ x.select { |elem| elem }
335
+ }
336
+ end
337
+
338
+ def isDefines( sym )
339
+ [ :define, :set!, :"define-syntax", @core_syntax_hash[ :define ], @core_syntax_hash[ :set! ], @core_syntax_hash[ :"define-syntax" ] ].include?( sym )
340
+ end
341
+
342
+ def embedBacktraceInfo( sourcefile, lineno )
343
+ @backtrace[ sprintf( "%s:%s", sourcefile, lineno ) ] = @backtrace_counter
344
+ @backtrace_counter += 1
345
+ end
346
+
347
+ def generateEmbedBacktraceInfo( sourcefile, lineno, arr )
348
+ if sourcefile and lineno
349
+ [ "begin",
350
+ [ sprintf( 'embedBacktraceInfo( "%s", %s ); ', sourcefile, lineno ), arr ],
351
+ "end"
352
+ ]
353
+ else
354
+ arr
355
+ end
356
+ end
357
+
358
+ def optimizedFunc( origname, rubysym, args )
359
+ case origname
360
+ when '+', '-', '*'
361
+ case args.length
362
+ when 0
363
+ [ "#{rubysym}_ARGS0(", ")" ]
364
+ when 1
365
+ [ "#{rubysym}_ARGS1(", args[0], ")" ]
366
+ when 2
367
+ [ "#{rubysym}_ARGS2(", args[0], args[1], ")" ]
368
+ when 3
369
+ [ "#{rubysym}_ARGS3(", args[0], args[1], args[2], ")" ]
370
+ else
371
+ false
372
+ end
373
+ when 'car', 'cdr', 'not', 'length', 'null?', 'reverse', 'uniq',
374
+ 'write', 'write-to-string', 'display', 'print',
375
+ 'procedure?', 'macro?', 'symbol?', 'keyword?', 'syntax?', 'core-syntax?',
376
+ 'pair?', '%list?', 'integer?', 'number?', 'string?', 'macroexpand-1',
377
+ 'to-s', 'to-i', 'nil?', 'to-list', 'to-arr',
378
+ 'intern', 'string->symbol', 'symbol->string', 'read-from-string'
379
+ raise ArgumentError, "Error: #{origname} requires 1 argument. " unless 1 == args.length
380
+ [ "#{rubysym}(", args[0], ")" ]
381
+ when 'cons', '=', ">", ">=", "<", "<=", "eq?", "equal?", 'set-car!', 'set-cdr!'
382
+ raise ArgumentError, "Error: #{origname} requires 2 arguments. " unless 2 == args.length
383
+ [ "#{rubysym}(", args[0], args[1], ")" ]
384
+ else
385
+ false
386
+ end
387
+ end
388
+
389
+ def execFunc( funcname, args, sourcefile, lineno, locals, sourceInfo, execType )
390
+ if isDefines( funcname )
391
+ ar = args.cdr.map { |x| x.car }
392
+ variable_sym = toRubySymbol( args.car.to_s.sub( /^:/, "" ))
393
+ global_cap = locals.flatten.include?( variable_sym.split( /[.]/ )[0] ) ? nil : "@"
394
+ if global_cap and sourceInfo
395
+ sourceInfo.setVarname( toLispSymbol( variable_sym ))
396
+ end
397
+ [ "begin",
398
+ [
399
+ if global_cap
400
+ [
401
+ defMethodStr( variable_sym, true ),
402
+ sprintf( "@global_lisp_binding['%s'] = self.method( :%s_METHOD )", variable_sym, variable_sym )
403
+ ]
404
+ else
405
+ ""
406
+ end,
407
+ sprintf( "%s%s = ", global_cap, variable_sym ),
408
+ "trampCall(", [ ar ], ")"],
409
+ "end"
410
+ ]
411
+ elsif :error == funcname or @core_syntax_hash[ :error ] == funcname
412
+ arr = if args.length < 2
413
+ args.car
414
+ else
415
+ [ args.car + " ' ' + ",
416
+ "_write_MIMARKto_MIMARKstring(",
417
+ args.cdr.car,
418
+ ")" ]
419
+ end
420
+ [
421
+ 'begin raise RuntimeError, ',
422
+ arr,
423
+ "rescue => __e ",
424
+ sprintf( " __e.set_backtrace( [\"%s:%d\"] + __e.backtrace )", sourcefile, lineno ),
425
+ " raise __e",
426
+ "end "]
427
+ else
428
+ if (EXEC_TYPE_ANONYMOUS != execType) and isRubyInterface( funcname )
429
+ # Ruby method
430
+ # 1) convert arguments
431
+ translatedArr = args.map { |x| x.car }
432
+ # 2) generate caller code part
433
+ lispSymbolReference( toRubySymbol( funcname ), locals, translatedArr, sourcefile, lineno )
434
+ else
435
+ # Nendo function
436
+ arr = separateWith( args.map { |x| x.car }, "," )
437
+ origname = funcname.to_s
438
+ sym = toRubySymbol( origname )
439
+ if EXEC_TYPE_ANONYMOUS == execType
440
+ [sprintf( "trampCall( callProcedure( nil, 'anonymouse', " ),
441
+ [ funcname ] + [ "," ],
442
+ "[", arr, "]",
443
+ " ))"]
444
+ else
445
+ result = false
446
+ if (execType == EXEC_TYPE_NORMAL) and (not locals.flatten.include?( sym ))
447
+ if 1 < @optimize_level
448
+ result = optimizedFunc( origname, sym, arr )
449
+ end
450
+ end
451
+ if result
452
+ generateEmbedBacktraceInfo( sourcefile, lineno, result )
453
+ else
454
+ _call = case execType
455
+ when EXEC_TYPE_NORMAL
456
+ if locals.flatten.include?( sym )
457
+ [ "trampCall( callProcedure( '" + sym + "', ", "))" ] # local function
458
+ else
459
+ [ sprintf( "trampCall( self.%s_METHOD( ", sym ), "))" ] # toplevel function
460
+ end
461
+ when EXEC_TYPE_TAILCALL
462
+ [ sprintf( "delayCall( '%s', ", sym ), ")" ]
463
+ end
464
+
465
+ temp = [
466
+ sprintf( "%s '%s',", _call[0], origname ),
467
+ [lispSymbolReference( sym, locals, nil, sourcefile, lineno )] + [","],
468
+ "[", arr, "]",
469
+ sprintf( " %s", _call[1] )]
470
+ generateEmbedBacktraceInfo( sourcefile, lineno, temp )
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end
476
+
477
+ def makeSetVariable( car, cdr, locals, sourceInfo )
478
+ cdr.cdr.each { |x|
479
+ if Cell == x.class
480
+ x.car = translate( x.car, locals, sourceInfo )
481
+ end
482
+ }
483
+ execFunc( car, cdr, car.sourcefile, car.lineno, locals, sourceInfo, EXEC_TYPE_ANONYMOUS )
484
+ end
485
+
486
+ def makeBegin( args, locals )
487
+ ar = args.map { |e|
488
+ translate( e.car, locals )
489
+ }
490
+ ["begin", ar, "end"]
491
+ end
492
+
493
+ # returns [ argsyms[], string ]
494
+ def toRubyParameter( argform )
495
+ argsyms = []
496
+ locals = []
497
+ rest = false
498
+ if _symbol_QUMARK( argform )
499
+ rest = argform
500
+ else
501
+ argsyms = argform.map { |x| toRubySymbol( x.car ) }
502
+ locals = argsyms.clone
503
+ if argform.lastAtom
504
+ rest = argform.getLastAtom
505
+ end
506
+ end
507
+ if rest
508
+ rest = toRubySymbol( rest )
509
+ locals << rest
510
+ argsyms << "*__rest__"
511
+ [ locals, sprintf( "|%s| %s = __rest__[0] ; ", argsyms.join( "," ), rest ) ]
512
+ else
513
+ [ locals, sprintf( "|%s|", argsyms.join( "," )) ]
514
+ end
515
+ end
516
+
517
+ def makeClosure( sym, args, locals )
518
+ first = args.car
519
+ rest = args.cdr
520
+ ( _locals, argStr ) = toRubyParameter( first )
521
+ str = case sym
522
+ when :macro
523
+ sprintf( "LispMacro.new { %s ", argStr )
524
+ when :lambda
525
+ sprintf( "Proc.new { %s ", argStr )
526
+ when :"%syntax"
527
+ sprintf( "LispSyntax.new { %s ", argStr )
528
+ when :"&block"
529
+ sprintf( "&Proc.new { %s ", argStr )
530
+ else
531
+ raise "Error: makeClosure: unknown symbol type " + sym
532
+ end
533
+ ar = rest.map { |e|
534
+ translate( e.car, locals.clone + [_locals])
535
+ }
536
+ [ str, ar, "}" ]
537
+ end
538
+
539
+ def makeIf( args, locals )
540
+ _condition = translate( args.car, locals )
541
+ _then = translate( args.cdr.car, locals )
542
+ _else = nil
543
+ if 2 < args.length
544
+ _else = translate( args.cdr.cdr.car, locals )
545
+ end
546
+ if _else
547
+ ["if ( ", _condition, " ) then",
548
+ [ _then ],
549
+ "else",
550
+ [ _else ],
551
+ "end"]
552
+ else
553
+ ["if ( ", _condition, " ) then",
554
+ [ _then ],
555
+ "end"]
556
+ end
557
+ end
558
+
559
+ def makeLet( args, locals )
560
+ _name = "___lambda"
561
+ argvals = []
562
+ rest = args.cdr
563
+ if _null_QUMARK( args.car )
564
+ # nothing to do
565
+ lambda_head = sprintf( "%s = lambda { || ", _name )
566
+ else
567
+ argsyms = args.car.map { |x|
568
+ toRubySymbol( x.car.car.to_s )
569
+ }
570
+ argvals = args.car.map.with_index { |x,i|
571
+ translate( x.car.cdr.car, locals )
572
+ }
573
+ lambda_head = sprintf( "%s = lambda { |%s| ", _name, argsyms.join( "," ))
574
+ end
575
+ ["begin",
576
+ [lambda_head,
577
+ rest.map { |e| translate( e.car, locals.clone + [argsyms] ) },
578
+ sprintf( "} ; %s.call(", _name ),
579
+ separateWith( argvals, "," ),
580
+ sprintf( " )")],
581
+ "end"]
582
+ end
583
+
584
+ def makeLetrec( args, locals )
585
+ _name = "___lambda"
586
+ argvals = []
587
+ argsyms = []
588
+ rest = args.cdr
589
+ if _null_QUMARK( args.car )
590
+ # nothing to do
591
+ lambda_head = sprintf( "%s = lambda { || ", _name )
592
+ else
593
+ argsyms = args.car.map { |x|
594
+ toRubySymbol( x.car.car.to_s )
595
+ }
596
+ argvals = args.car.map { |x|
597
+ translate( x.car.cdr.car, locals.clone + [argsyms] )
598
+ }
599
+ lambda_head = sprintf( "%s = lambda { |%s| ", _name, argsyms.join( "," ))
600
+ end
601
+ ["begin",
602
+ [lambda_head,
603
+ argsyms.zip( argvals ).map { |x| [ x[0], " = ", x[1] ] },
604
+ rest.map { |e| translate( e.car, locals.clone + [argsyms] ) },
605
+ sprintf( "} ; %s.call(", _name ),
606
+ argsyms.map { |x| "nil" }.join( "," ),
607
+ sprintf( " )")],
608
+ "end"]
609
+ end
610
+
611
+ def makeGuard( args, locals )
612
+ _var = toRubySymbol( args.car )
613
+ _locals = locals.clone + [_var]
614
+ _case = translate( args.cdr.car, _locals )
615
+ _thunk = translate( args.cdr.cdr.car, _locals )
616
+ ["begin",
617
+ [ _thunk ],
618
+ "rescue => " + _var,
619
+ [ _case ],
620
+ "end" ]
621
+ end
622
+
623
+ def apply( car, cdr, sourcefile, lineno, locals, sourceInfo, execType )
624
+ cdr.each { |x|
625
+ if Cell == x.class
626
+ x.car = translate( x.car, locals, sourceInfo )
627
+ end
628
+ }
629
+ execFunc( car, cdr, sourcefile, lineno, locals, sourceInfo, execType )
630
+ end
631
+
632
+ def genQuote( sexp, str = "" )
633
+ origStr = str
634
+ case sexp
635
+ when Cell
636
+ if sexp.isNull
637
+ str += "Cell.new()"
638
+ else
639
+ arr = sexp.map { |x| genQuote( x.car ) }
640
+ str += "Cell.new("
641
+ str += arr.join( ",Cell.new(" )
642
+ str += "," + genQuote( sexp.getLastAtom ) if sexp.lastAtom
643
+ str += arr.map{ |e| ")" }.join
644
+ end
645
+ when Array
646
+ arr = sexp.map { |x| genQuote( x ) }
647
+ str += "[" + arr.join(",") + "]"
648
+ when Symbol
649
+ str += sprintf( ":\"%s\"", sexp.to_s )
650
+ when String, LispString
651
+ str += sprintf( "\"%s\"", LispString.escape( sexp ))
652
+ when LispKeyword
653
+ str += sprintf( "LispKeyword.new( \"%s\" )", sexp.key.to_s )
654
+ when TrueClass, FalseClass, NilClass # reserved symbols
655
+ str += toRubyValue( sexp )
656
+ when SyntacticClosure
657
+ str += sprintf( ":\"%s\"", sexp.originalSymbol.to_s )
658
+ when Nil
659
+ str += "Cell.new()"
660
+ else
661
+ str += sprintf( "%s", sexp )
662
+ end
663
+ str
664
+ end
665
+
666
+ def trampCallCap( sym )
667
+ if isRubyInterface( sym )
668
+ arr = sym.split( /[.]/ )
669
+ arr[0] = sprintf( "trampCall(%s)", arr[0] )
670
+ arr.join( "." )
671
+ else
672
+ "trampCall(" + sym + ")"
673
+ end
674
+ end
675
+
676
+ def lispSymbolReference( sym, locals, translatedArr, sourcefile, lineno )
677
+ variable_sym = sym.split( /[.]/ )[0]
678
+ global_cap = if variable_sym.match( /^[A-Z]/ )
679
+ nil
680
+ else
681
+ locals.flatten.include?( variable_sym ) ? nil : "@"
682
+ end
683
+ expression = if translatedArr
684
+ [trampCallCap( sprintf( "%s%s(", global_cap, sym )),
685
+ separateWith( translatedArr, "," ),
686
+ sprintf( " )" )]
687
+ else
688
+ [trampCallCap( sprintf( "%s%s", global_cap, sym ))]
689
+ end
690
+ if global_cap
691
+ ["begin",
692
+ [sprintf( "if @global_lisp_binding.has_key?('%s') then", variable_sym ),
693
+ expression,
694
+ sprintf( 'else raise NameError.new( "Error: undefined variable %s", "%s" ) end', variable_sym, variable_sym ),
695
+ sprintf( 'rescue => __e ; __e.set_backtrace( ["%s:%d"] + __e.backtrace ) ; raise __e', sourcefile, lineno )],
696
+ "end"]
697
+ else
698
+ ["begin",
699
+ [expression,
700
+ sprintf( 'rescue => __e ; __e.set_backtrace( ["%s:%d"] + __e.backtrace ) ; raise __e', sourcefile, lineno )],
701
+ "end"]
702
+ end
703
+ end
704
+
705
+ # Lisp->Ruby translater
706
+ # - locals is array of closure's local variable list
707
+ # when S-expression is
708
+ # (let ((a 1)
709
+ # (b 2))
710
+ # (let ((c 3))
711
+ # (print (+ a b c))))
712
+ # => locals must be [["_a" "_b"]["_c"]] value.
713
+ def translate( sexp, locals, sourceInfo = nil )
714
+ case sexp
715
+ when Cell
716
+ inv = @core_syntax_hash.invert
717
+ car = if inv.has_key?( sexp.car )
718
+ inv[ sexp.car ]
719
+ else
720
+ sexp.car
721
+ end
722
+ if :quote == car
723
+ genQuote( sexp.second )
724
+ elsif :"syntax-quote" == car
725
+ [ "Cell.new(:\"syntax-quote\", ", genQuote( sexp.cdr ), ")" ]
726
+ elsif sexp.isDotted
727
+ raise NameError, "Error: can't eval dotted pair."
728
+ elsif sexp.isNull
729
+ [ "Cell.new()" ]
730
+ elsif isDefines( car )
731
+ self.makeSetVariable( car, sexp.cdr, locals, sourceInfo )
732
+ elsif :begin == car
733
+ self.makeBegin( sexp.cdr, locals )
734
+ elsif :lambda == car
735
+ self.makeClosure( :lambda, sexp.cdr, locals )
736
+ elsif :macro == car
737
+ self.makeClosure( :macro, sexp.cdr, locals )
738
+ elsif :"%syntax" == car
739
+ self.makeClosure( :"%syntax", sexp.cdr, locals )
740
+ elsif :"&block" == car
741
+ self.makeClosure( :"&block", sexp.cdr, locals )
742
+ elsif :if == car
743
+ self.makeIf( sexp.cdr, locals )
744
+ elsif :"%let" == car
745
+ self.makeLet( sexp.cdr, locals )
746
+ elsif :letrec == car
747
+ self.makeLetrec( sexp.cdr, locals )
748
+ elsif :"%guard" == car
749
+ self.makeGuard( sexp.cdr, locals )
750
+ elsif :"%tailcall" == car
751
+ if sexp.cdr.car.is_a? Cell
752
+ sexp = sexp.cdr.car
753
+ if isDefines( sexp.car )
754
+ translate( sexp, locals, sourceInfo )
755
+ else
756
+ if sexp.car.is_a? Cell
757
+ self.apply( translate( sexp.car, locals, sourceInfo ), sexp.cdr, sexp.car.car.sourcefile, sexp.car.car.lineno, locals, sourceInfo, EXEC_TYPE_ANONYMOUS )
758
+ else
759
+ self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals, sourceInfo, EXEC_TYPE_TAILCALL )
760
+ end
761
+ end
762
+ else
763
+ raise RuntimeError, "Error: special form tailcall expects function call expression."
764
+ end
765
+ elsif Cell == sexp.car.class
766
+ self.apply( translate( sexp.car, locals, sourceInfo ), sexp.cdr, sexp.car.car.sourcefile, sexp.car.car.lineno, locals, sourceInfo, EXEC_TYPE_ANONYMOUS )
767
+ else
768
+ self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals, sourceInfo, EXEC_TYPE_NORMAL )
769
+ end
770
+ when Array
771
+ raise RuntimeError, "Error: can't eval unquoted vector."
772
+ else
773
+ case sexp
774
+ when Symbol
775
+ sym = sexp.to_s
776
+ sym = toRubySymbol( sym )
777
+ lispSymbolReference( sym, locals, nil, sexp.sourcefile, sexp.lineno )
778
+ when Fixnum
779
+ sexp.to_s
780
+ when String, LispString
781
+ sprintf( "\"%s\"", LispString.escape( sexp ))
782
+ when LispRegexp
783
+ if sexp.ignoreCase
784
+ sprintf( "Regexp.new( \"%s\", Regexp::IGNORECASE)", sexp.escape )
785
+ else
786
+ sprintf( "Regexp.new( \"%s\")", sexp.escape )
787
+ end
788
+ when LispKeyword
789
+ sprintf( "LispKeyword.new( \"%s\" )", sexp.key )
790
+ when Nil
791
+ "Nil.new"
792
+ when TrueClass, FalseClass, NilClass # reserved symbols
793
+ toRubyValue( sexp )
794
+ when SyntacticClosure
795
+ toRubySymbol( sexp )
796
+ else
797
+ sexp.to_s
798
+ end
799
+ end
800
+ end
801
+
802
+
803
+ # warp sexp by lexicalVars
804
+ def __wrapNestedLet( sexp, lexicalVars )
805
+ if 0 == lexicalVars.size
806
+ sexp
807
+ else
808
+ elem = lexicalVars.shift
809
+ Cell.new( :"%let",
810
+ Cell.new(
811
+ Cell.new(
812
+ Cell.new( elem[0], elem[1] )),
813
+ Cell.new( __wrapNestedLet( sexp, lexicalVars ) )))
814
+ end
815
+ end
816
+
817
+ def __removeSameLexicalScopeVariables( frame )
818
+ frame.select {|x|
819
+ # search same varname and different value
820
+ found = frame.any? {|y|
821
+ x[0] == y[0] and (not _equal_QUMARK( x[1], y[1] ))
822
+ }
823
+ if found
824
+ x
825
+ else
826
+ false
827
+ end
828
+ }
829
+ end
830
+
831
+ def macroexpandInit( initVal )
832
+ @macroExpandCount = initVal
833
+ end
834
+
835
+ def macroexpandEngineLoop( sexp, syntaxArray, lexicalVars )
836
+ converge = true
837
+ begin
838
+ newSexp = macroexpandEngine( sexp, syntaxArray, lexicalVars )
839
+ converge = _equal_QUMARK( newSexp, sexp )
840
+ sexp = newSexp
841
+ end until converge or (@macroExpandCount <= 0)
842
+ sexp
843
+ end
844
+
845
+ def macroexpandEngine( sexp, syntaxArray, lexicalVars )
846
+ if @macroExpandCount <= 0
847
+ sexp
848
+ else
849
+ __macroexpandEngine( sexp, syntaxArray, lexicalVars )
850
+ end
851
+ end
852
+
853
+ #
854
+ # expand (syntax-rules ...) => (%syntax-rules ...)
855
+ #
856
+ def __expandSyntaxRules( rules, syntaxArray, lexicalVars )
857
+ if :"%syntax-rules" == rules.car
858
+ rules
859
+ else
860
+ ellipse = rules.second
861
+ pattern_body_list = rules.cdr.cdr
862
+
863
+ lst = []
864
+ lst << :"syntax-rules"
865
+ lst << ellipse
866
+ pattern_body_list.each {|xx|
867
+ pattern_body = xx.car
868
+ pattern = pattern_body.first
869
+ body = pattern_body.second
870
+ new_pattern_body = [ pattern, macroexpandEngine( body, syntaxArray, lexicalVars ) ].to_list
871
+ lst << new_pattern_body
872
+ }
873
+ lst.to_list
874
+ end
875
+ end
876
+
877
+ # eval (syntax-rules ...) sexp
878
+ #
879
+ # return:
880
+ # (%syntax-rules
881
+ # ((v1 <<@syntaxHash's key1>>)
882
+ # (v2 <<@syntaxHash's key2>>)
883
+ # body))
884
+ #
885
+ # example:
886
+ # (%syntax-rules
887
+ # ((v1 "x = 10 // (+ x v1)")
888
+ # (v2 "y = 20 // (+ y v2)"))
889
+ # (+ v1 v2))
890
+ #
891
+ def __evalSyntaxRules( rules, lexicalVars )
892
+ if :"%syntax-rules" == rules.car
893
+ rules.second
894
+ else
895
+ lexvars = lexicalVars.select { |x|
896
+ if _symbol_MIMARKinclude_QUMARK( rules, x[0].intern )
897
+ x
898
+ elsif lexicalVars.find {|y| _symbol_MIMARKinclude_QUMARK( y[1], x[0].intern ) }
899
+ x
900
+ else
901
+ false
902
+ end
903
+ }
904
+
905
+ __setupLexicalScopeVariables( lexvars )
906
+ keyStr = lexvars.map {|z|
907
+ z[0].to_s + " / " + write_to_string( z[1] )
908
+ }.join( " / " )
909
+ keyStr += " // " + write_to_string( rules )
910
+ if @syntaxHash.has_key?( keyStr )
911
+ true
912
+ else
913
+ @syntaxHash[ keyStr ] = [ lexvars,
914
+ self.lispEval( rules, "dynamic syntax-rules sexp (no source) ", 1 ) ]
915
+ end
916
+ __setupLexicalScopeVariables( [] )
917
+ keyStr
918
+ end
919
+ end
920
+
921
+ # args:
922
+ #
923
+ # syntaxArray ... let-syntax's identifiers
924
+ # [
925
+ # [ identifier-name, key of @syntaxHash, sexp of (syntax-rules ...), frame_of_let-syntax ],
926
+ # .
927
+ # .
928
+ # ]
929
+ # lexicalVars ... let's identifiers
930
+ # [
931
+ # [ identifier-name, macroexpandEngine( let's body ) ],
932
+ # ]
933
+ #
934
+ #
935
+ def __macroexpandEngine( sexp, syntaxArray, lexicalVars )
936
+ case sexp
937
+ when Cell
938
+ car = sexp.car
939
+ if :quote == car or :"syntax-quote" == car or @core_syntax_hash[ :quote ] == car or @core_syntax_hash[ :"syntax-quote" ] == car
940
+ sexp
941
+ elsif :"%let" == car or :letrec == car or @core_syntax_hash[ :"%let" ] == car or @core_syntax_hash[ :letrec ] == car
942
+ # catch lexical identifiers of `let' and `letrec'.
943
+ arr = sexp.second.map { |x|
944
+ [ x.car.car, macroexpandEngine( x.car.cdr, syntaxArray, lexicalVars ) ]
945
+ }
946
+ lst = arr.map {|x| Cell.new( x[0], x[1] ) }.to_list
947
+ ret = Cell.new( car,
948
+ Cell.new( lst,
949
+ macroexpandEngine( sexp.cdr.cdr, syntaxArray, lexicalVars + arr )))
950
+ ret
951
+ elsif :"let-syntax" == car
952
+ sexp.second.each {|x|
953
+ if not x.car.second.is_a? Cell
954
+ raise SyntaxError, "Error: let-syntax get only '((name (syntax-rules ...)))' form but got: " + write_to_string( x )
955
+ elsif not ( x.car.second.first == :"syntax-rules" or x.car.second.first == :"%syntax-rules")
956
+ raise SyntaxError, "Error: let-syntax get only '((name (syntax-rules ...)))' form but got: " + write_to_string( x )
957
+ end
958
+ }
959
+ arr_tmp = sexp.second.map { |x|
960
+ [ x.car.first, __expandSyntaxRules( x.car.second, syntaxArray, lexicalVars ) ]
961
+ }
962
+ arr = arr_tmp.map {|x|
963
+ [ x[0], __evalSyntaxRules( x[1], lexicalVars ), x[1], lexicalVars ]
964
+ }
965
+
966
+ # trial (expand recursively)
967
+ arr_tmp = arr.map { |x|
968
+ [ x[0], __expandSyntaxRules( x[2], syntaxArray + arr, lexicalVars ) ]
969
+ }
970
+ arr = arr_tmp.map {|x|
971
+ [ x[0], __evalSyntaxRules( x[1], lexicalVars ), x[1], lexicalVars ]
972
+ }
973
+
974
+ # keywords = ((let-syntax-keyword ( let-syntax-body ))
975
+ # (let-syntax-keyword ( let-syntax-body ))
976
+ # ..)
977
+ newKeywords = arr.map { |e|
978
+ [ e[0], [ :"%syntax-rules", e[1]].to_list ].to_list
979
+ }.to_list
980
+
981
+ ret = Cell.new( :"let-syntax",
982
+ Cell.new( newKeywords, macroexpandEngine( sexp.cdr.cdr, syntaxArray + arr, lexicalVars )))
983
+
984
+ ret
985
+ else
986
+ sym = toRubySymbol( car.to_s )
987
+ newSexp = sexp
988
+ if isRubyInterface( sym )
989
+ # do nothing
990
+ sexp
991
+ elsif _symbol_QUMARK( car ) and eval( sprintf( "(defined? @%s and LispMacro == @%s.class)", sym,sym ), @binding )
992
+ eval( sprintf( "@__macro = @%s", sym ), @binding )
993
+ newSexp = trampCall( callProcedure( nil, sym, @__macro, sexp.cdr.to_arr ))
994
+ elsif _symbol_QUMARK( car ) and eval( sprintf( "(defined? @%s and LispSyntax == @%s.class)", sym,sym ), @binding )
995
+ # expected input is
996
+ # (syntaxName arg1 arg2 ...)
997
+ # will be transformed
998
+ # (syntaxName (syntaxName arg1 arg2 ...) () (global-variables))
999
+ eval( sprintf( "@__syntax = @%s", sym ), @binding )
1000
+ newSexp = trampCall( callProcedure( nil, sym, @__syntax, [ sexp, Cell.new(), _global_MIMARKvariables( ) ] ))
1001
+ elsif _symbol_QUMARK( car ) and syntaxArray.map {|arr| arr[0].intern}.include?( car.intern )
1002
+ # lexical macro expandeding
1003
+ symbol_and_syntaxObj = syntaxArray.reverse.find {|arr| car == arr[0]}
1004
+ keys = syntaxArray.reverse.map { |arr| arr[0] }
1005
+ if not symbol_and_syntaxObj
1006
+ raise "can't find valid syntaxObject"
1007
+ end
1008
+ vars = symbol_and_syntaxObj[3].map { |arr| arr[0] }
1009
+ lexvars = @syntaxHash[ symbol_and_syntaxObj[1] ][0]
1010
+ lispSyntax = @syntaxHash[ symbol_and_syntaxObj[1] ][1]
1011
+ newSexp = trampCall( callProcedure( nil, symbol_and_syntaxObj[0], lispSyntax, [
1012
+ sexp,
1013
+ Cell.new(),
1014
+ (_global_MIMARKvariables( ).to_arr + keys + vars).to_list ] ))
1015
+ newSexp = __wrapNestedLet( newSexp, __removeSameLexicalScopeVariables( lexicalVars + lexvars ))
1016
+ end
1017
+ if _equal_QUMARK( newSexp, sexp )
1018
+ sexp.map { |x|
1019
+ if x.car.is_a? Cell
1020
+ macroexpandEngine( x.car, syntaxArray, lexicalVars )
1021
+ else
1022
+ x.car
1023
+ end
1024
+ }.to_list( sexp.lastAtom, sexp.getLastAtom )
1025
+ else
1026
+ @macroExpandCount -= 1
1027
+ newSexp
1028
+ end
1029
+ end
1030
+ else
1031
+ sexp
1032
+ end
1033
+ end
1034
+
1035
+ def macroexpandPhase( sexp )
1036
+ macroexpandInit( 100000 )
1037
+ _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword(
1038
+ _strip_MIMARKsyntax_MIMARKquote(
1039
+ macroexpandEngineLoop( sexp, [], [] )))
1040
+ end
1041
+
1042
+ def ppRubyExp( level, exp )
1043
+ indent = @indent * level
1044
+ exp.map { |x|
1045
+ if Array == x.class
1046
+ ppRubyExp( level+1, x )
1047
+ else
1048
+ str = sprintf( "%s", x )
1049
+ if str.match( /^[,]/ ) or str.match( /^ = / )
1050
+ sprintf( "%s%s", indent, str )
1051
+ else
1052
+ sprintf( "\n%s%s", indent, str )
1053
+ end
1054
+ end
1055
+ }
1056
+ end
1057
+
1058
+ def displayTopOfCalls( exception )
1059
+ if @displayErrorsFlag
1060
+ STDERR.puts( "\n <<< Top of calls >>>" )
1061
+ strs = []
1062
+ @call_counters.each_key { |funcname|
1063
+ if 0 < @call_counters[ funcname ]
1064
+ strs << sprintf( " %7d : %-20s", @call_counters[ funcname ], funcname )
1065
+ end
1066
+ }
1067
+ strs.sort.reverse.each { |str|
1068
+ STDERR.puts( str )
1069
+ }
1070
+ end
1071
+ end
1072
+
1073
+ def displayBacktrace( exception )
1074
+ if @displayErrorsFlag
1075
+ STDERR.puts( "\n <<< Backtrace of Nendo >>>" )
1076
+ arr = @backtrace.map { |key,val| [key,val] }.sort_by { |x| x[1] }.reverse
1077
+ arr[0...10].each { |x|
1078
+ STDERR.printf( " from %s \n", x[0] )
1079
+ }
1080
+ STDERR.puts( " ...\n\n" )
1081
+ end
1082
+ end
1083
+
1084
+ def lispEval( sexp, sourcefile, lineno )
1085
+ begin
1086
+ sourceInfo = SourceInfo.new
1087
+ @lastSourcefile = sourcefile
1088
+ @lastLineno = lineno
1089
+ sourceInfo.setSource( sourcefile, lineno, sexp )
1090
+
1091
+ # macro expand phase
1092
+ sexp = macroexpandPhase( sexp )
1093
+ if @debug
1094
+ printf( "\n expaneded=<<< %s >>>\n", (Printer.new())._print(sexp))
1095
+ end
1096
+
1097
+ # compiling phase written
1098
+ origsym = "%compile-phase"
1099
+ sym = toRubySymbol( origsym )
1100
+ if ( eval( sprintf( "(defined? @%s and Proc == @%s.class)", sym,sym ), @binding ))
1101
+ eval( sprintf( "@___tmp = @%s", sym ), @binding )
1102
+ sexp = trampCall( callProcedure( nil, origsym, @___tmp, [ sexp ]))
1103
+ if @debug
1104
+ printf( "\n compiled= <<< %s >>>\n", (Printer.new())._print(sexp))
1105
+ end
1106
+ end
1107
+ sourceInfo.setExpanded( sexp )
1108
+
1109
+ arr = [ "trampCall( ", translate( sexp, [], sourceInfo ), " )" ]
1110
+ rubyExp = ppRubyExp( 0, arr ).flatten.join
1111
+ sourceInfo.setCompiled( rubyExp )
1112
+ if not @compiled_code.has_key?( sourcefile )
1113
+ @compiled_code[ sourcefile ] = Array.new
1114
+ end
1115
+ @compiled_code[ sourcefile ] << rubyExp
1116
+ if sourceInfo.varname
1117
+ @source_info_hash[ sourceInfo.varname ] = sourceInfo
1118
+ end
1119
+ printf( " rubyExp=<<<\n%s\n>>>\n", rubyExp ) if @debug
1120
+ eval( rubyExp, @binding, @lastSourcefile, @lastLineno )
1121
+ rescue SystemStackError => e
1122
+ displayTopOfCalls( e )
1123
+ raise e
1124
+ rescue => e
1125
+ displayBacktrace( e )
1126
+ raise e
1127
+ end
1128
+ end
1129
+
1130
+ def __PAMARKload( filename )
1131
+ printer = Printer.new( @debug )
1132
+ open( filename, "r:utf-8" ) {|f|
1133
+ reader = Reader.new( f, filename, false )
1134
+ while true
1135
+ lineno = reader.lineno
1136
+ s = reader._read
1137
+ if s[1] # EOF?
1138
+ break
1139
+ elsif Nil != s[0].class
1140
+ printf( "\n readExp=<<< %s >>>\n", printer._print(s[0]) ) if @debug
1141
+ self.lispEval( s[0], reader.sourcefile, lineno )
1142
+ end
1143
+ end
1144
+ }
1145
+ forward_gensym_counter()
1146
+ end
1147
+
1148
+ def _load_MIMARKcompiled_MIMARKcode_MIMARKfrom_MIMARKstring( rubyExp )
1149
+ eval( rubyExp, @binding )
1150
+ forward_gensym_counter()
1151
+ end
1152
+
1153
+ def __PAMARKload_MIMARKcompiled_MIMARKcode( filename )
1154
+ open( filename, "r:utf-8" ) { |f|
1155
+ eval( f.read, @binding )
1156
+ }
1157
+ forward_gensym_counter()
1158
+ end
1159
+
1160
+ def _clean_MIMARKcompiled_MIMARKcode
1161
+ @compiled_code = Hash.new
1162
+ end
1163
+
1164
+ def _get_MIMARKcompiled_MIMARKcode
1165
+ @compiled_code
1166
+ ret = Hash.new
1167
+ @compiled_code.each_key { |key|
1168
+ ret[key] = @compiled_code[key].to_list
1169
+ ret[key]
1170
+ }
1171
+ ret.to_list
1172
+ end
1173
+
1174
+ def _eval( sexp )
1175
+ self.lispEval( sexp, "dynamic S-expression ( no source )", 1 )
1176
+ end
1177
+
1178
+ def _enable_MIMARKidebug()
1179
+ @debug = true
1180
+ end
1181
+ def _disable_MIMARKidebug()
1182
+ @debug = false
1183
+ end
1184
+ def _enable_MIMARKtrace()
1185
+ @trace_debug = true
1186
+ end
1187
+ def _disable_MIMARKtrace()
1188
+ @trace_debug = false
1189
+ end
1190
+ def _set_MIMARKoptimize_MIMARKlevel(level)
1191
+ self.setOptimizeLevel( level )
1192
+ end
1193
+ def _get_MIMARKoptimize_MIMARKlevel()
1194
+ self.getOptimizeLevel
1195
+ end
1196
+
1197
+ def _get_MIMARKsource_MIMARKinfo( varname )
1198
+ info = @source_info_hash[ varname.to_s ]
1199
+ if info
1200
+ [
1201
+ Cell.new( "varname", info.varname ),
1202
+ Cell.new( "sourcefile", info.sourcefile ),
1203
+ Cell.new( "lineno", info.lineno ),
1204
+ Cell.new( "source", info.source_sexp ),
1205
+ Cell.new( "expanded", info.expanded_sexp ),
1206
+ Cell.new( "compiled_str", info.compiled_str ) ].to_list
1207
+ else
1208
+ raise NameError, sprintf( "Error: not found variable [%s]. \n", varname.to_s )
1209
+ end
1210
+ end
1211
+
1212
+ def __PAMARKexport_MIMARKto_MIMARKruby( origname, pred )
1213
+ if toRubySymbol( origname ) != ("_" + origname)
1214
+ raise ArgumentError, "Error: %export-to-ruby requires function name in ruby method naming rule."
1215
+ end
1216
+ if not _procedure_QUMARK( pred )
1217
+ raise ArgumentError, "Error: %export-to-ruby requires 'pred' as a Proc instance."
1218
+ end
1219
+ if 0 > pred.arity
1220
+ raise ArgumentError, "Error: %export-to-ruby requires only a function that have fixed length argument."
1221
+ end
1222
+ if self.methods.include?( origname.intern ) or @core.methods.include?( origname.intern )
1223
+ raise RuntimeError, "Error: %export-to-ruby: Nendo::Core." + origname + " method was already deifned."
1224
+ end
1225
+
1226
+ argsStr = (1..(pred.arity)).map { |n| "arg" + n.to_s }.join( "," )
1227
+ str = [ "def self." + origname + "(" + argsStr + ")",
1228
+ sprintf( " trampCall( callProcedure( nil, '%s', @_%s, [ " + argsStr + " ] )) ",
1229
+ origname, origname ),
1230
+ "end ;",
1231
+ "def @core." + origname + "(" + argsStr + ")",
1232
+ " @evaluator." + origname + "(" + argsStr + ") ",
1233
+ "end"
1234
+ ].join
1235
+ eval( str, @binding )
1236
+ true
1237
+ end
1238
+
1239
+ def __setupLexicalScopeVariables( lexicalVars )
1240
+ @lexicalVars = lexicalVars.clone
1241
+ end
1242
+
1243
+ def _make_MIMARKsyntactic_MIMARKclosure( mac_env, use_env, identifier )
1244
+ if _pair_QUMARK( identifier )
1245
+ if :"syntax-quote" == identifier.car
1246
+ identifier
1247
+ else
1248
+ raise TypeError, "make-syntactic-closure requires symbol or (syntax-quote sexp) only. but got: " + write_to_string( identifier )
1249
+ end
1250
+ elsif _symbol_QUMARK( identifier )
1251
+ # pp [ "identifier: ", identifier, "include?=", mac_env.to_arr.include?( identifier.intern ) ]
1252
+ # pp [ "mac_env: ", mac_env.to_arr ]
1253
+ if mac_env.to_arr.include?( identifier.intern )
1254
+ found = @lexicalVars.find { |x| identifier == x[0] }
1255
+ if found
1256
+ lexvars = @lexicalVars.clone
1257
+ __wrapNestedLet( identifier, lexvars )
1258
+ else
1259
+ identifier
1260
+ end
1261
+ else
1262
+ SyntacticClosure.new( identifier, (toRubySymbol( identifier ) + _gensym( ).to_s).intern )
1263
+ end
1264
+ else
1265
+ raise TypeError, "make-syntactic-closure requires symbol or (syntax-quote sexp) type."
1266
+ end
1267
+ end
1268
+
1269
+ def _strip_MIMARKsyntax_MIMARKquote( sexp )
1270
+ case sexp
1271
+ when Cell
1272
+ if _null_QUMARK( sexp )
1273
+ sexp
1274
+ else
1275
+ car = sexp.car
1276
+ if :"syntax-quote" == car or @core_syntax_hash[ :"syntax-quote" ] == car
1277
+ Cell.new( :quote, sexp.cdr )
1278
+ else
1279
+ Cell.new(
1280
+ _strip_MIMARKsyntax_MIMARKquote( sexp.car ),
1281
+ _strip_MIMARKsyntax_MIMARKquote( sexp.cdr ))
1282
+ end
1283
+ end
1284
+ else
1285
+ sexp
1286
+ end
1287
+ end
1288
+
1289
+ def _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword( sexp )
1290
+ case sexp
1291
+ when Cell
1292
+ if _null_QUMARK( sexp )
1293
+ sexp
1294
+ else
1295
+ car = sexp.car
1296
+ if :"quote" == car or @core_syntax_hash[ :"quote" ] == car
1297
+ sexp
1298
+ elsif :"let-syntax" == car or @core_syntax_hash[ :"let-syntax" ] == car
1299
+ Cell.new( :begin,
1300
+ _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword( sexp.cdr.cdr ))
1301
+ else
1302
+ Cell.new(
1303
+ _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword( sexp.car ),
1304
+ _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword( sexp.cdr ))
1305
+ end
1306
+ end
1307
+ else
1308
+ sexp
1309
+ end
1310
+ end
1311
+
1312
+ def _strip_MIMARKsyntactic_MIMARKclosures( sexp )
1313
+ case sexp
1314
+ when Cell
1315
+ if _null_QUMARK( sexp )
1316
+ sexp
1317
+ else
1318
+ Cell.new(
1319
+ _strip_MIMARKsyntactic_MIMARKclosures( sexp.car ),
1320
+ _strip_MIMARKsyntactic_MIMARKclosures( sexp.cdr ))
1321
+ end
1322
+ else
1323
+ if sexp.is_a? SyntacticClosure
1324
+ sexp.intern
1325
+ else
1326
+ sexp
1327
+ end
1328
+ end
1329
+ end
1330
+
1331
+ def _symbol_MIMARKinclude_QUMARK( sexp, sym )
1332
+ case sexp
1333
+ when Cell
1334
+ if _null_QUMARK( sexp )
1335
+ false
1336
+ else
1337
+ _symbol_MIMARKinclude_QUMARK( sexp.car, sym ) or _symbol_MIMARKinclude_QUMARK( sexp.cdr, sym )
1338
+ end
1339
+ else
1340
+ if _symbol_QUMARK( sexp )
1341
+ sym.intern == sexp.intern
1342
+ else
1343
+ false
1344
+ end
1345
+ end
1346
+ end
1347
+ end
1348
+
1349
+ end