Class: Nendo::Evaluator
- Inherits:
-
Object
- Object
- Nendo::Evaluator
- Includes:
- BuiltinFunctions
- Defined in:
- lib/nendo.rb
Overview
Translate S expression to Ruby expression and Evaluation
Constant Summary collapse
- EXEC_TYPE_NORMAL =
1
- EXEC_TYPE_ANONYMOUS =
2
- EXEC_TYPE_TAILCALL =
3
Instance Method Summary collapse
- #__PAMARKexport_MIMARKto_MIMARKruby(origname, pred) ⇒ Object
- #__PAMARKload(filename) ⇒ Object
- #__PAMARKload_MIMARKcompiled_MIMARKcode(filename) ⇒ Object
- #_clean_MIMARKcompiled_MIMARKcode ⇒ Object
- #_disable_MIMARKidebug ⇒ Object
- #_disable_MIMARKtrace ⇒ Object
- #_enable_MIMARKidebug ⇒ Object
- #_enable_MIMARKtrace ⇒ Object
- #_eval(sexp) ⇒ Object
- #_gensym ⇒ Object
- #_get_MIMARKcompiled_MIMARKcode ⇒ Object
- #_get_MIMARKoptimize_MIMARKlevel ⇒ Object
- #_get_MIMARKsource_MIMARKinfo(varname) ⇒ Object
- #_load_MIMARKcompiled_MIMARKcode_MIMARKfrom_MIMARKstring(rubyExp) ⇒ Object
- #_make_MIMARKsyntactic_MIMARKclosure(mac_env, use_env, identifier) ⇒ Object
- #_set_MIMARKoptimize_MIMARKlevel(level) ⇒ Object
- #apply(car, cdr, sourcefile, lineno, locals, sourceInfo, execType) ⇒ Object
- #callProcedure(origname, pred, args) ⇒ Object
- #defMethodStr(name, _log) ⇒ Object
- #delayCall(rubysym, origname, pred, args) ⇒ Object
- #displayTopOfCalls(exception) ⇒ Object
- #execFunc(funcname, args, sourcefile, lineno, locals, sourceInfo, execType) ⇒ Object
- #forward_gensym_counter ⇒ Object
- #genQuote(sexp, str = "") ⇒ Object
- #getOptimizeLevel ⇒ Object
- #global_lisp_define(rubySymbol, val) ⇒ Object
-
#initialize(core, debug = false) ⇒ Evaluator
constructor
A new instance of Evaluator.
- #isRubyInterface(name) ⇒ Object
-
#letArgumentList(sexp) ⇒ Object
insert quote in let argument list ((sym1 list1) (sym2 list2) (sym3 list3)) will be transformed (((quote sym1) list1) ((quote sym2) list2) ((quote sym3) list3)).
- #lispEval(sexp, sourcefile, lineno) ⇒ Object
- #lispMethodEntry(name, _log) ⇒ Object
- #lispMethodExit(name, _log) ⇒ Object
- #lispSymbolReference(sym, locals, translatedArr, sourcefile, lineno) ⇒ Object
- #macroexpandEngine(sexp) ⇒ Object
- #macroexpandInit(initVal) ⇒ Object
- #macroExpandPhase(sexp) ⇒ Object
- #makeBegin(args, locals) ⇒ Object
- #makeClosure(sym, args, locals) ⇒ Object
- #makeIf(args, locals) ⇒ Object
- #makeLet(args, locals) ⇒ Object
- #makeLetrec(args, locals) ⇒ Object
- #method_missing(name, *args) ⇒ Object
- #ppRubyExp(level, exp) ⇒ Object
- #quotingPhase(sexp) ⇒ Object
-
#separateWith(arr, str) ⇒ Object
for code generation of Ruby’s argument values in case: str = “,” [1,“2”,3] => [ [ 1, “,”] [“2”, “,”] [ 3 ] ].
- #setArgv(argv) ⇒ Object
- #setOptimizeLevel(level) ⇒ Object
- #toLispSymbol(name) ⇒ Object
- #toRubyArgument(origname, pred, args) ⇒ Object
-
#toRubyParameter(argform) ⇒ Object
returns [ argsyms[], string ].
- #toRubySymbol(name) ⇒ Object
- #toRubyValue(val) ⇒ Object
- #trampCall(result) ⇒ Object
- #trampCallCap(sym) ⇒ Object
-
#translate(sexp, locals, sourceInfo = nil) ⇒ Object
Lisp->Ruby translater - locals is array of closure’s local variable list when S-expression is (let ((a 1) (b 2)) (let ((c 3)) (print (+ a b c)))) => locals must be [[“_a” “_b”]] value.
Methods included from BuiltinFunctions
#__ASMARK, #__ASMARKFILE_ASMARK, #__ASMARKLINE_ASMARK, #__EQMARK, #__GTMARK, #__GTMARK_EQMARK, #__LTMARK, #__LTMARK_EQMARK, #__MIMARK, #__PAMARK, #__PAMARKlist_QUMARK, #__PLMARK, #__SLMARK, #__assertFlat, #__assertList, #_apply1, #_car, #_cdr, #_cons, #_core_MIMARKsyntax_QUMARK, #_display, #_eq_QUMARK, #_equal_QUMARK, #_eqv_QUMARK, #_exit, #_ge_QUMARK, #_global_MIMARKvariables, #_gt_QUMARK, #_hash_MIMARKtable_MIMARKexist_QUMARK, #_hash_MIMARKtable_MIMARKget, #_hash_MIMARKtable_MIMARKput_EXMARK, #_integer_QUMARK, #_intern, #_keyword_MIMARK_GTMARKstring, #_keyword_QUMARK, #_le_QUMARK, #_length, #_list, #_lt_QUMARK, #_macro_QUMARK, #_macroexpand_MIMARK1, #_make_MIMARKkeyword, #_make_MIMARKvalues, #_modulo, #_newline, #_nil_QUMARK, #_not, #_null_QUMARK, #_number_QUMARK, #_pair_QUMARK, #_print, #_printf, #_procedure_QUMARK, #_quotient, #_raise, #_range, #_read, #_read_MIMARKfrom_MIMARKstring, #_remainder, #_require, #_reverse, #_set_MIMARKcar_EXMARK, #_set_MIMARKcdr_EXMARK, #_sprintf, #_string_MIMARK_GTMARKsymbol, #_string_MIMARKjoin, #_string_QUMARK, #_symbol_MIMARK_GTMARKstring, #_symbol_QUMARK, #_syntax_QUMARK, #_to_MIMARKarr, #_to_MIMARKi, #_to_MIMARKlist, #_to_MIMARKs, #_to_arr, #_to_i, #_to_list, #_to_s, #_uniq, #_values_MIMARKvalues, #_values_QUMARK, #_vector_MIMARKset_EXMARK, #_write, #_write_MIMARKto_MIMARKstring
Constructor Details
#initialize(core, debug = false) ⇒ Evaluator
Returns a new instance of Evaluator.
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 |
# File 'lib/nendo.rb', line 1270 def initialize( core, debug = false ) @core = core @indent = " " @binding = binding @debug = debug @trace_debug = false @char_table_lisp_to_ruby = { # list (! $ % & * + - . / : < = > ? @ ^ _ ~ ...) '!' => '_EXMARK', '$' => '_DOMARK', '%' => '_PAMARK', '&' => '_ANMARK', '*' => '_ASMARK', '+' => '_PLMARK', '-' => '_MIMARK', # '.' '/' => '_SLMARK', ':' => '_COMARK', '<' => '_LTMARK', '=' => '_EQMARK', '>' => '_GTMARK', '?' => '_QUMARK', '@' => '_ATMARK', '^' => '_NKMARK', # '_' '~' => '_CHMARK', '...' => '_DOTDOTDOT', } @char_table_ruby_to_lisp = @char_table_lisp_to_ruby.invert @core_syntax_list = [ :quote, :"syntax-quote", :if , :begin , :lambda , :macro , :"&block" , :let , :letrec , :define, :set!, :error, :"%syntax", :"define-syntax" ] @core_syntax_hash = Hash.new @core_syntax_list.each { |x| renamed = ("/nendo/core/" + x.to_s).intern @core_syntax_hash[ x ] = renamed } # toplevel binding @global_lisp_binding = Hash.new # initialize builtin functions as Proc objects rubyExp = self.methods.select { |x| x.to_s.match( /^_/ ) }.map { |name| [ defMethodStr( name, false ), sprintf( "@%s = self.method( :%s ).to_proc", name, name ), sprintf( "@global_lisp_binding['%s'] = self.method( :%s_METHOD ).to_proc", name, name ), ].join( " ; " ) }.join( " ; " ) eval( rubyExp, @binding ) # initialize builtin syntax as LispCoreSyntax rubyExp = @core_syntax_hash.map { |k,v| name1 = toRubySymbol( k ) name2 = toRubySymbol( v ) [ sprintf( "@%s = LispCoreSyntax.new( :\"%s\" ) ", name1, k ), sprintf( "@global_lisp_binding['%s'] = @%s ", name1, name1 ), sprintf( "@%s = @%s ", name2, name1 ), sprintf( "@global_lisp_binding['%s'] = @%s ", name1, name2 ) ].join( " ; " ) }.join( " ; " ) eval( rubyExp, @binding ) # reset gensym counter @gensym_counter = 0 # call depth counter @call_depth = 0 @call_counters = Hash.new # init optimize level @optimize_level = 1 # compiled ruby code # { 'filename1' => [ 'code1' 'code2' ... ], # 'filename2' => [ 'code1' 'code2' ... ], ... } @compiled_code = Hash.new @source_info_hash = Hash.new global_lisp_define( toRubySymbol( "%compile-phase-functions" ), Cell.new()) load_path = $LOAD_PATH + [ File.dirname(__FILE__) ] global_lisp_define( toRubySymbol( "*load-path*" ), load_path.to_list ) global_lisp_define( toRubySymbol( "*nendo-version*" ), Nendo::Core.version ) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
1507 1508 1509 1510 1511 1512 1513 |
# File 'lib/nendo.rb', line 1507 def method_missing( name, *args ) if @global_lisp_binding[name].is_a? Proc @global_lisp_binding[name].call( args[0], args[1], args[2] ) else callProcedure( args[0], args[1], args[2] ) end end |
Instance Method Details
#__PAMARKexport_MIMARKto_MIMARKruby(origname, pred) ⇒ Object
2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 |
# File 'lib/nendo.rb', line 2222 def __PAMARKexport_MIMARKto_MIMARKruby( origname, pred ) if toRubySymbol( origname ) != ("_" + origname) raise ArgumentError, "Error: %export-to-ruby requires function name in ruby method naming rule." end if not _procedure_QUMARK( pred ) raise ArgumentError, "Error: %export-to-ruby requires 'pred' as a Proc instance." end if 0 > pred.arity raise ArgumentError, "Error: %export-to-ruby requires only a function that have fixed length argument." end if self.methods.include?( origname.intern ) or @core.methods.include?( origname.intern ) raise RuntimeError, "Error: %export-to-ruby: Nendo::Core." + origname + " method was already deifned." end argsStr = (1..(pred.arity)).map { |n| "arg" + n.to_s }.join( "," ) str = [ "def self." + origname + "(" + argsStr + ")", sprintf( " trampCall( callProcedure( '%s', @_%s, [ " + argsStr + " ] )) ", origname, origname ), "end ;", "def @core." + origname + "(" + argsStr + ")", " @evaluator." + origname + "(" + argsStr + ") ", "end" ].join eval( str, @binding ) true end |
#__PAMARKload(filename) ⇒ Object
2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 |
# File 'lib/nendo.rb', line 2140 def __PAMARKload( filename ) printer = Printer.new( @debug ) open( filename, "r:utf-8" ) {|f| reader = Reader.new( f, filename, false ) while true lineno = reader.lineno s = reader._read if s[1] # EOF? break elsif Nil != s[0].class printf( "\n readExp=<<< %s >>>\n", printer._print(s[0]) ) if @debug self.lispEval( s[0], reader.sourcefile, lineno ) end end } forward_gensym_counter() end |
#__PAMARKload_MIMARKcompiled_MIMARKcode(filename) ⇒ Object
2163 2164 2165 2166 2167 2168 |
# File 'lib/nendo.rb', line 2163 def __PAMARKload_MIMARKcompiled_MIMARKcode( filename ) open( filename, "r:utf-8" ) { |f| eval( f.read, @binding ) } forward_gensym_counter() end |
#_clean_MIMARKcompiled_MIMARKcode ⇒ Object
2170 2171 2172 |
# File 'lib/nendo.rb', line 2170 def _clean_MIMARKcompiled_MIMARKcode @compiled_code = Hash.new end |
#_disable_MIMARKidebug ⇒ Object
2191 2192 2193 |
# File 'lib/nendo.rb', line 2191 def _disable_MIMARKidebug() @debug = false end |
#_disable_MIMARKtrace ⇒ Object
2197 2198 2199 |
# File 'lib/nendo.rb', line 2197 def _disable_MIMARKtrace() @trace_debug = false end |
#_enable_MIMARKidebug ⇒ Object
2188 2189 2190 |
# File 'lib/nendo.rb', line 2188 def _enable_MIMARKidebug() @debug = true end |
#_enable_MIMARKtrace ⇒ Object
2194 2195 2196 |
# File 'lib/nendo.rb', line 2194 def _enable_MIMARKtrace() @trace_debug = true end |
#_eval(sexp) ⇒ Object
2184 2185 2186 |
# File 'lib/nendo.rb', line 2184 def _eval( sexp ) self.lispEval( sexp, "dynamic S-expression ( no source )", 1 ) end |
#_gensym ⇒ Object
1395 1396 1397 1398 1399 1400 1401 1402 1403 |
# File 'lib/nendo.rb', line 1395 def _gensym( ) @gensym_counter += 1 filename = if @lastSourcefile.is_a? String Digest::SHA1.hexdigest( @lastSourcefile ) else "" end sprintf( "__gensym__%s_%d", filename, @gensym_counter ).intern end |
#_get_MIMARKcompiled_MIMARKcode ⇒ Object
2174 2175 2176 2177 2178 2179 2180 2181 2182 |
# File 'lib/nendo.rb', line 2174 def _get_MIMARKcompiled_MIMARKcode @compiled_code ret = Hash.new @compiled_code.each_key { |key| ret[key] = @compiled_code[key].to_list ret[key] } ret.to_list end |
#_get_MIMARKoptimize_MIMARKlevel ⇒ Object
2203 2204 2205 |
# File 'lib/nendo.rb', line 2203 def _get_MIMARKoptimize_MIMARKlevel() self.getOptimizeLevel end |
#_get_MIMARKsource_MIMARKinfo(varname) ⇒ Object
2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 |
# File 'lib/nendo.rb', line 2207 def _get_MIMARKsource_MIMARKinfo( varname ) info = @source_info_hash[ varname.to_s ] if info [ Cell.new( "varname", info.varname ), Cell.new( "sourcefile", info.sourcefile ), Cell.new( "lineno", info.lineno ), Cell.new( "source", info.source_sexp ), Cell.new( "expanded", info. ), Cell.new( "compiled_str", info.compiled_str ) ].to_list else raise NameError, sprintf( "Error: not found variable [%s]. \n", varname.to_s ) end end |
#_load_MIMARKcompiled_MIMARKcode_MIMARKfrom_MIMARKstring(rubyExp) ⇒ Object
2158 2159 2160 2161 |
# File 'lib/nendo.rb', line 2158 def _load_MIMARKcompiled_MIMARKcode_MIMARKfrom_MIMARKstring( rubyExp ) eval( rubyExp, @binding ) forward_gensym_counter() end |
#_make_MIMARKsyntactic_MIMARKclosure(mac_env, use_env, identifier) ⇒ Object
2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 |
# File 'lib/nendo.rb', line 2249 def _make_MIMARKsyntactic_MIMARKclosure( mac_env, use_env, identifier ) if _pair_QUMARK( identifier ) raise RuntimeError, "Error: make-syntactic-closure requires symbol only..." else if mac_env.to_arr.include?( identifier ) identifier else sym = toRubySymbol( identifier ) + _gensym( ).to_s sym.intern end end end |
#_set_MIMARKoptimize_MIMARKlevel(level) ⇒ Object
2200 2201 2202 |
# File 'lib/nendo.rb', line 2200 def _set_MIMARKoptimize_MIMARKlevel(level) self.setOptimizeLevel( level ) end |
#apply(car, cdr, sourcefile, lineno, locals, sourceInfo, execType) ⇒ Object
1758 1759 1760 1761 1762 1763 1764 1765 |
# File 'lib/nendo.rb', line 1758 def apply( car, cdr, sourcefile, lineno, locals, sourceInfo, execType ) cdr.each { |x| if Cell == x.class x.car = translate( x.car, locals, sourceInfo ) end } execFunc( car, cdr, sourcefile, lineno, locals, sourceInfo, execType ) end |
#callProcedure(origname, pred, args) ⇒ Object
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 |
# File 'lib/nendo.rb', line 1524 def callProcedure( origname, pred, args ) if @call_counters.has_key?( origname ) @call_counters[ origname ] += 1 else @call_counters[ origname ] = 1 end result = pred.call( *toRubyArgument( origname, pred, args )) @call_counters[ origname ] -= 1 result end |
#defMethodStr(name, _log) ⇒ Object
1386 1387 1388 1389 1390 1391 1392 1393 |
# File 'lib/nendo.rb', line 1386 def defMethodStr( name, _log ) [ "def self." + name.to_s + "_METHOD( origname, pred, args ) ", " lispMethodEntry( origname, " + _log.to_s + " ) ; ", " ret = callProcedure( origname, pred, args ) ;", " lispMethodExit( origname, " + _log.to_s + " ) ; ", " return ret ", "end " ].join end |
#delayCall(rubysym, origname, pred, args) ⇒ Object
1515 1516 1517 1518 1519 1520 1521 1522 |
# File 'lib/nendo.rb', line 1515 def delayCall( rubysym, origname, pred, args ) case @optimize_level when 0 # no optimize callProcedure( origname, pred, args ) else # tail call optimization DelayedCallPacket.new( origname, rubysym, pred, args ) end end |
#displayTopOfCalls(exception) ⇒ Object
2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 |
# File 'lib/nendo.rb', line 2087 def displayTopOfCalls( exception ) STDERR.puts( "\n <<< Top of calls >>>" ) strs = [] @call_counters.each_key { |funcname| if 0 < @call_counters[ funcname ] strs << sprintf( " %7d : %-20s", @call_counters[ funcname ], funcname ) end } strs.sort.reverse.each { |str| STDERR.puts( str ) } end |
#execFunc(funcname, args, sourcefile, lineno, locals, sourceInfo, execType) ⇒ Object
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 |
# File 'lib/nendo.rb', line 1553 def execFunc( funcname, args, sourcefile, lineno, locals, sourceInfo, execType ) case funcname when :define, :set!, :"define-syntax", @core_syntax_hash[ :define ], @core_syntax_hash[ :set! ], @core_syntax_hash[ :"define-syntax" ] # `define' special form ar = args.cdr.map { |x| x.car } variable_sym = toRubySymbol( args.car.to_s.sub( /^:/, "" )) global_cap = locals.flatten.include?( variable_sym.split( /[.]/ )[0] ) ? nil : "@" if global_cap and sourceInfo sourceInfo.setVarname( toLispSymbol( variable_sym )) end [ "begin", [ if global_cap [ defMethodStr( variable_sym, true ), sprintf( "@global_lisp_binding['%s'] = self.method( :%s_METHOD )", variable_sym, variable_sym ) ] else "" end, sprintf( "%s%s = ", global_cap, variable_sym ), "trampCall(", [ ar ], ")"], "end" ] when :error, @core_syntax_hash[ :error ] arr = if args.length < 2 args.car else [ args.car + " ' ' + ", "_write_MIMARKto_MIMARKstring(", args.cdr.car, ")" ] end [ 'begin raise RuntimeError, ', arr, "rescue => __e ", sprintf( " __e.set_backtrace( [\"%s:%d\"] + __e.backtrace )", sourcefile, lineno ), " raise __e", "end "] else if (EXEC_TYPE_ANONYMOUS != execType) and isRubyInterface( funcname ) # Ruby method # 1) convert arguments translatedArr = args.map { |x| x.car } # 2) generate caller code part lispSymbolReference( toRubySymbol( funcname ), locals, translatedArr, sourcefile, lineno ) else # Nendo function arr = separateWith( args.map { |x| x.car }, "," ) if EXEC_TYPE_ANONYMOUS == execType [sprintf( "trampCall( callProcedure( 'anonymouse', " ), [ funcname ] + [ "," ], "[", arr, "]", " ))"] else origname = funcname.to_s funcname = funcname.to_s sym = toRubySymbol( funcname ) _call = case execType when EXEC_TYPE_NORMAL if locals.flatten.include?( sym ) [ "trampCall( callProcedure( ", "))" ] # local function else [ sprintf( "trampCall( self.%s_METHOD( ", sym ), "))" ] # toplevel function end when EXEC_TYPE_TAILCALL [ sprintf( "delayCall( '%s', ", sym ), ")" ] end [sprintf( "%s '%s',", _call[0], origname ), [lispSymbolReference( sym, locals, nil, sourcefile, lineno )] + [","], "[", arr, "]", sprintf( " %s", _call[1] )] end end end end |
#forward_gensym_counter ⇒ Object
1405 1406 1407 |
# File 'lib/nendo.rb', line 1405 def forward_gensym_counter( ) @gensym_counter += 10000 end |
#genQuote(sexp, str = "") ⇒ Object
1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 |
# File 'lib/nendo.rb', line 1767 def genQuote( sexp, str = "" ) origStr = str case sexp when Cell if sexp.isNull str += "Cell.new()" else arr = sexp.map { |x| genQuote( x.car ) } str += "Cell.new(" str += arr.join( ",Cell.new(" ) str += "," + genQuote( sexp.getLastAtom ) if sexp.lastAtom str += arr.map{ |e| ")" }.join end when Array arr = sexp.map { |x| genQuote( x ) } str += "[" + arr.join(",") + "]" when Symbol str += sprintf( ":\"%s\"", sexp.to_s ) when String, LispString str += sprintf( "\"%s\"", LispString.escape( sexp )) when LispKeyword str += sprintf( "LispKeyword.new( \"%s\" )", sexp.key.to_s ) when TrueClass, FalseClass, NilClass # reserved symbols str += toRubyValue( sexp ) when Nil str += "Cell.new()" else str += sprintf( "%s", sexp ) end str end |
#getOptimizeLevel ⇒ Object
1369 1370 1371 |
# File 'lib/nendo.rb', line 1369 def getOptimizeLevel @optimize_level end |
#global_lisp_define(rubySymbol, val) ⇒ Object
1355 1356 1357 1358 1359 |
# File 'lib/nendo.rb', line 1355 def global_lisp_define( rubySymbol, val ) @___tmp = val eval( sprintf( "@%s = @___tmp;", rubySymbol ), @binding ) eval( sprintf( "@global_lisp_binding['%s'] = @___tmp;", rubySymbol ), @binding ) end |
#isRubyInterface(name) ⇒ Object
1445 1446 1447 |
# File 'lib/nendo.rb', line 1445 def isRubyInterface( name ) name.to_s.match( /[.]/ ) end |
#letArgumentList(sexp) ⇒ Object
insert quote in let argument list
((sym1 list1)
(sym2 list2)
(sym3 list3))
will be transformed
(((quote sym1) list1)
((quote sym2) list2)
((quote sym3) list3))
1927 1928 1929 1930 1931 1932 1933 |
# File 'lib/nendo.rb', line 1927 def letArgumentList( sexp ) sexp.each { |arg| arg.car.car = Cell.new( :quote, Cell.new( arg.car.car )) arg.car.cdr = quotingPhase( arg.car.cdr ) } sexp end |
#lispEval(sexp, sourcefile, lineno) ⇒ Object
2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 |
# File 'lib/nendo.rb', line 2100 def lispEval( sexp, sourcefile, lineno ) begin sourceInfo = SourceInfo.new @lastSourcefile = sourcefile @lastLineno = lineno sourceInfo.setSource( sourcefile, lineno, sexp ) sexp = macroExpandPhase( sexp ) sexp = quotingPhase( sexp ) if @debug printf( "\n quoting=<<< %s >>>\n", (Printer.new())._print(sexp)) end # compiling phase written in Nendo sym = toRubySymbol( "%compile-phase" ) if ( eval( sprintf( "(defined? @%s and Proc == @%s.class)", sym,sym ), @binding )) eval( sprintf( "@___tmp = @%s", sym ), @binding ) sexp = trampCall( callProcedure( sym, @___tmp, [ sexp ])) if @debug printf( "\n compiled=<<< %s >>>\n", (Printer.new())._print(sexp)) end end sourceInfo.setExpanded( sexp ) arr = [ "trampCall( ", translate( sexp, [], sourceInfo ), " )" ] rubyExp = ppRubyExp( 0, arr ).flatten.join sourceInfo.setCompiled( rubyExp ) if not @compiled_code.has_key?( sourcefile ) @compiled_code[ sourcefile ] = Array.new end @compiled_code[ sourcefile ] << rubyExp if sourceInfo.varname @source_info_hash[ sourceInfo.varname ] = sourceInfo end printf( " rubyExp=<<<\n%s\n>>>\n", rubyExp ) if @debug eval( rubyExp, @binding, @lastSourcefile, @lastLineno ) rescue SystemStackError => e displayTopOfCalls( e ) raise e end end |
#lispMethodEntry(name, _log) ⇒ Object
1373 1374 1375 1376 1377 1378 |
# File 'lib/nendo.rb', line 1373 def lispMethodEntry( name, _log ) @call_depth += 1 if @trace_debug and _log puts " " * @call_depth + "ENTRY: " + name end end |
#lispMethodExit(name, _log) ⇒ Object
1379 1380 1381 1382 1383 1384 |
# File 'lib/nendo.rb', line 1379 def lispMethodExit( name, _log ) if @trace_debug and _log puts " " * @call_depth + "exit: " + name end @call_depth -= 1 end |
#lispSymbolReference(sym, locals, translatedArr, sourcefile, lineno) ⇒ Object
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 |
# File 'lib/nendo.rb', line 1809 def lispSymbolReference( sym, locals, translatedArr, sourcefile, lineno ) variable_sym = sym.split( /[.]/ )[0] global_cap = if variable_sym.match( /^[A-Z]/ ) nil else locals.flatten.include?( variable_sym ) ? nil : "@" end expression = if translatedArr [trampCallCap( sprintf( "%s%s(", global_cap, sym )), separateWith( translatedArr, "," ), sprintf( " )" )] else [trampCallCap( sprintf( "%s%s", global_cap, sym ))] end if global_cap ["begin", [sprintf( "if @global_lisp_binding.has_key?('%s') then", variable_sym ), expression, sprintf( 'else raise NameError.new( "Error: undefined variable %s", "%s" ) end', variable_sym, variable_sym ), sprintf( 'rescue => __e ; __e.set_backtrace( ["%s:%d"] + __e.backtrace ) ; raise __e', sourcefile, lineno )], "end"] else ["begin", [expression, sprintf( 'rescue => __e ; __e.set_backtrace( ["%s:%d"] + __e.backtrace ) ; raise __e', sourcefile, lineno )], "end"] end end |
#macroexpandEngine(sexp) ⇒ Object
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 |
# File 'lib/nendo.rb', line 2011 def ( sexp ) case sexp when Cell car = sexp.car if :quote == car or :"syntax-quote" == car or @core_syntax_hash[ :quote ] == car or @core_syntax_hash[ :"syntax-quote" ] == car sexp else sym = sexp.car.to_s p 'macroexpandEngine' if @debug p sexp.car.class if @debug p sym if @debug sym = toRubySymbol( sym ) newSexp = sexp if isRubyInterface( sym ) # do nothing sexp elsif sexp.car.class == Symbol and eval( sprintf( "(defined? @%s and LispMacro == @%s.class)", sym,sym ), @binding ) eval( sprintf( "@__macro = @%s", sym ), @binding ) newSexp = trampCall( callProcedure( sym, @__macro, sexp.cdr.to_arr )) elsif sexp.car.class == Symbol and eval( sprintf( "(defined? @%s and LispSyntax == @%s.class)", sym,sym ), @binding ) # expected input is # (syntaxName arg1 arg2 ...) # will be transformed # (syntaxName (syntaxName arg1 arg2 ...) () (global-variables)) eval( sprintf( "@__syntax = @%s", sym ), @binding ) newSexp = trampCall( callProcedure( sym, @__syntax, [ sexp, Cell.new(), _global_MIMARKvariables( ) ] )) end if _equal_QUMARK( newSexp, sexp ) sexp.map { |x| if x.car.is_a? Cell if 0 <= @macroExpandCount ( x.car ) else x.car end else x.car end }.to_list( sexp.lastAtom, sexp.getLastAtom ) else @macroExpandCount -= 1 newSexp end end else sexp end end |
#macroexpandInit(initVal) ⇒ Object
2007 2008 2009 |
# File 'lib/nendo.rb', line 2007 def ( initVal ) @macroExpandCount = initVal end |
#macroExpandPhase(sexp) ⇒ Object
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 |
# File 'lib/nendo.rb', line 2060 def macroExpandPhase( sexp ) converge = true begin ( 100000 ) newSexp = ( sexp ) converge = _equal_QUMARK( newSexp, sexp ) sexp = newSexp end until converge sexp end |
#makeBegin(args, locals) ⇒ Object
1630 1631 1632 1633 1634 1635 |
# File 'lib/nendo.rb', line 1630 def makeBegin( args, locals ) ar = args.map { |e| translate( e.car, locals ) } ["begin", ar, "end"] end |
#makeClosure(sym, args, locals) ⇒ Object
1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 |
# File 'lib/nendo.rb', line 1661 def makeClosure( sym, args, locals ) first = args.car if args.car.car == :quote first = args.car.cdr.car end rest = args.cdr ( _locals, argStr ) = toRubyParameter( first ) str = case sym when :macro sprintf( "LispMacro.new { %s ", argStr ) when :lambda sprintf( "Proc.new { %s ", argStr ) when :"%syntax" sprintf( "LispSyntax.new { %s ", argStr ) when :"&block" sprintf( "&Proc.new { %s ", argStr ) else raise "Error: makeClosure: unknown symbol type " + sym end ar = rest.map { |e| translate( e.car, locals.clone + [_locals]) } [ str, ar, "}" ] end |
#makeIf(args, locals) ⇒ Object
1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 |
# File 'lib/nendo.rb', line 1686 def makeIf( args, locals ) _condition = translate( args.car, locals ) _then = translate( args.cdr.car, locals ) _else = nil if 2 < args.length _else = translate( args.cdr.cdr.car, locals ) end if _else ["if ( ", _condition, " ) then", [ _then ], "else", [ _else ], "end"] else ["if ( ", _condition, " ) then", [ _then ], "end"] end end |
#makeLet(args, locals) ⇒ Object
1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 |
# File 'lib/nendo.rb', line 1706 def makeLet( args, locals ) _name = "___lambda" argvals = [] rest = args.cdr if args.car.is_a? Nil # nothing to do lambda_head = sprintf( "%s = lambda { || ", _name ) else argsyms = args.car.map { |x| toRubySymbol( x.car.car.cdr.car.to_s ) } argvals = args.car.map.with_index { |x,i| translate( x.car.cdr.car, locals ) } lambda_head = sprintf( "%s = lambda { |%s| ", _name, argsyms.join( "," )) end ["begin", [lambda_head, rest.map { |e| translate( e.car, locals.clone + [argsyms] ) }, sprintf( "} ; %s.call(", _name ), separateWith( argvals, "," ), sprintf( " )")], "end"] end |
#makeLetrec(args, locals) ⇒ Object
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 |
# File 'lib/nendo.rb', line 1731 def makeLetrec( args, locals ) _name = "___lambda" argvals = [] argsyms = [] rest = args.cdr if args.car.is_a? Nil # nothing to do lambda_head = sprintf( "%s = lambda { || ", _name ) else argsyms = args.car.map { |x| toRubySymbol( x.car.car.cdr.car.to_s ) } argvals = args.car.map { |x| translate( x.car.cdr.car, locals.clone + [argsyms] ) } lambda_head = sprintf( "%s = lambda { |%s| ", _name, argsyms.join( "," )) end ["begin", [lambda_head, argsyms.zip( argvals ).map { |x| [ x[0], " = ", x[1] ] }, rest.map { |e| translate( e.car, locals.clone + [argsyms] ) }, sprintf( "} ; %s.call(", _name ), argsyms.map { |x| "nil" }.join( "," ), sprintf( " )")], "end"] end |
#ppRubyExp(level, exp) ⇒ Object
2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 |
# File 'lib/nendo.rb', line 2071 def ppRubyExp( level, exp ) indent = @indent * level exp.map { |x| if Array == x.class ppRubyExp( level+1, x ) else str = sprintf( "%s", x ) if str.match( /^[,]/ ) or str.match( /^ = / ) sprintf( "%s%s", indent, str ) else sprintf( "\n%s%s", indent, str ) end end } end |
#quotingPhase(sexp) ⇒ Object
1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 |
# File 'lib/nendo.rb', line 1935 def quotingPhase( sexp ) case sexp when Cell car = sexp.car if :quote == car or :quasiquote == car or :"syntax-quote" == car or @core_syntax_hash[ :quote ] == car or @core_syntax_hash[ :quasiquote ] == car or @core_syntax_hash[ :"syntax-quote" ] == car sexp elsif :define == car or :set! == car or :lambda == car or :macro == car or :"&block" == car or :"%syntax" == car or :"define-syntax" == car or @core_syntax_hash[ :define ] == car or @core_syntax_hash[ :set! ] == car or @core_syntax_hash[ :lambda ] == car or @core_syntax_hash[ :macro ] == car or @core_syntax_hash[ :"&block" ] == car or @core_syntax_hash[ :"%syntax" ] == car or @core_syntax_hash[ :"define-syntax" ] == car if @debug if 2 >= sexp.length printf( "\n quotingPhase-1 label=%s, sexp.length=%d \n", sexp.car, sexp.length ) else printf( "\n quotingPhase-1 label=%s, sexp.length=%d, sexp.cdr=%s sexp.cdr.car=%s sexp.cdr.cdr=%s\n", sexp.car, sexp.length, sexp.cdr, sexp.cdr.car, sexp.cdr.cdr ) end end if 1 == sexp.length nil # do nothing elsif 3 <= sexp.length # argument sexp.cdr.car = Cell.new( :quote, Cell.new( sexp.cdr.car )) # body sexp.cdr.cdr = quotingPhase( sexp.cdr.cdr ) else raise RuntimeError, sprintf( "Error: %s is not a illegal form got: %s", sexp.car, _write_MIMARKto_MIMARKstring( sexp )) end sexp elsif :let == car or @core_syntax_hash[ :let ] == car if _null_QUMARK( sexp.cdr ) # do nothing else case sexp.cdr.car when Cell # let sexp.cdr = Cell.new( letArgumentList( sexp.cdr.car ), quotingPhase( sexp.cdr.cdr )) when Symbol # named let sexp.cdr.car = Cell.new( :quote, Cell.new( sexp.cdr.car )) sexp.cdr.cdr = Cell.new( letArgumentList( sexp.cdr.cdr.car ), quotingPhase( sexp.cdr.cdr.cdr )) end end sexp elsif :letrec == car or @core_syntax_hash[ :letrec ] == car if _null_QUMARK( sexp.cdr ) # do nothing else case sexp.cdr.car when Cell # letrec sexp.cdr = Cell.new( letArgumentList( sexp.cdr.car ), quotingPhase( sexp.cdr.cdr )) when Symbol # named letrec is illegal raise RuntimeError, "Error: named letrec is not a illegal form" end end sexp else Cell.new( quotingPhase( sexp.car ), quotingPhase( sexp.cdr )) end else sexp end end |
#separateWith(arr, str) ⇒ Object
for code generation of Ruby’s argument values in case: str = “,”
- 1,“2”,3
-
> [
[ 1, ","] ["2", ","] [ 3 ] ]
1545 1546 1547 1548 1549 1550 1551 |
# File 'lib/nendo.rb', line 1545 def separateWith( arr, str ) seps = [] (arr.length-1).times {|n| seps << str } arr.zip( seps ).map{ |x| x.select { |elem| elem } } end |
#setArgv(argv) ⇒ Object
1361 1362 1363 |
# File 'lib/nendo.rb', line 1361 def setArgv( argv ) self.global_lisp_define( toRubySymbol( "*argv*"), argv.to_list ) end |
#setOptimizeLevel(level) ⇒ Object
1365 1366 1367 |
# File 'lib/nendo.rb', line 1365 def setOptimizeLevel( level ) @optimize_level = level end |
#toLispSymbol(name) ⇒ Object
1449 1450 1451 1452 1453 1454 1455 1456 1457 |
# File 'lib/nendo.rb', line 1449 def toLispSymbol( name ) name = name.to_s if Symbol == name.class raise ArgumentError, sprintf( "Error: `%s' is not a lisp symbol", name ) if not ('_' == name[0]) name = name[1..-1] @char_table_ruby_to_lisp.each_pair { |key,val| name = name.gsub( Regexp.new( key ), val ) } name end |
#toRubyArgument(origname, pred, args) ⇒ Object
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 |
# File 'lib/nendo.rb', line 1459 def toRubyArgument( origname, pred, args ) = sprintf( "Error: wrong number of arguments for closure `%s'", origname ) num = pred.arity if 0 == num raise ArgumentError, if 0 != args.length [] elsif 0 < num if 0 == args.length [ Nil.new ] else raise ArgumentError, if num != args.length args end else num = num.abs( )-1 raise ArgumentError, if num > args.length params = [] rest = [] args.each_with_index { |x,i| if i < num params << x else rest << x end } result = [] if 0 < params.length result = params end if 0 == rest.length result << Cell.new else result << rest.to_list end result end end |
#toRubyParameter(argform) ⇒ Object
returns [ argsyms[], string ]
1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 |
# File 'lib/nendo.rb', line 1638 def toRubyParameter( argform ) argsyms = [] locals = [] rest = false if Symbol == argform.class rest = argform else argsyms = argform.map { |x| toRubySymbol( x.car ) } locals = argsyms.clone if argform.lastAtom rest = argform.getLastAtom end end if rest rest = toRubySymbol( rest ) locals << rest argsyms << "*__rest__" [ locals, sprintf( "|%s| %s = __rest__[0] ; ", argsyms.join( "," ), rest ) ] else [ locals, sprintf( "|%s|", argsyms.join( "," )) ] end end |
#toRubySymbol(name) ⇒ Object
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 |
# File 'lib/nendo.rb', line 1421 def toRubySymbol( name ) name = name.to_s if Symbol == name.class if 0 == name.length "" else name.gsub!( Regexp.new( Regexp.escape( '...' )), @char_table_lisp_to_ruby[ '...' ] ) arr = name.gsub( /["]/, '' ).split( /[.]/ ) tmp = arr[0] tmp.gsub!( /[:][:]/, " " ) # save '::' @char_table_lisp_to_ruby.each_pair { |key,val| tmp.gsub!( Regexp.new( Regexp.escape( key )), val ) } arr[0] = tmp.gsub( /[ ][ ]/, "::" ) if arr[0].match( /^[A-Z]/ ) # nothing to do elsif arr[0] == "" arr[0] = 'Kernel' else arr[0] = '_' + arr[0] end arr.join( "." ) end end |
#toRubyValue(val) ⇒ Object
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 |
# File 'lib/nendo.rb', line 1409 def toRubyValue( val ) if NilClass == val.class "nil" elsif TrueClass == val.class val.to_s elsif FalseClass == val.class val.to_s else val.to_s end end |
#trampCall(result) ⇒ Object
1497 1498 1499 1500 1501 1502 1503 1504 1505 |
# File 'lib/nendo.rb', line 1497 def trampCall( result ) while result.is_a? DelayedCallPacket @tmp_origname = result.origname @tmp_pred = result.pred @tmp_args = result.args result = eval( sprintf( "self.%s( @tmp_origname, @tmp_pred, @tmp_args )", result.rubysym + "_METHOD" ), @binding ) end result end |
#trampCallCap(sym) ⇒ Object
1799 1800 1801 1802 1803 1804 1805 1806 1807 |
# File 'lib/nendo.rb', line 1799 def trampCallCap( sym ) if isRubyInterface( sym ) arr = sym.split( /[.]/ ) arr[0] = sprintf( "trampCall(%s)", arr[0] ) arr.join( "." ) else "trampCall(" + sym + ")" end end |
#translate(sexp, locals, sourceInfo = nil) ⇒ Object
Lisp->Ruby translater
- locals is array of closure's local variable list
when S-expression is
(let ((a 1)
(b 2))
(let ((c 3))
(print (+ a b c))))
=> locals must be [["_a" "_b"]["_c"]] value.
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 |
# File 'lib/nendo.rb', line 1846 def translate( sexp, locals, sourceInfo = nil ) case sexp when Cell inv = @core_syntax_hash.invert car = if inv.has_key?( sexp.car ) inv[ sexp.car ] else sexp.car end if :quote == car or :"syntax-quote" == car genQuote( sexp.cdr.car ) elsif sexp.isDotted raise NameError, "Error: can't eval dotted pair." elsif sexp.isNull [ "Cell.new()" ] elsif Cell == sexp.car.class self.apply( translate( sexp.car, locals, sourceInfo ), sexp.cdr, sexp.car.car.sourcefile, sexp.car.car.lineno, locals, sourceInfo, EXEC_TYPE_ANONYMOUS ) elsif :begin == car self.makeBegin( sexp.cdr, locals ) elsif :lambda == car self.makeClosure( :lambda, sexp.cdr, locals ) elsif :macro == car self.makeClosure( :macro, sexp.cdr, locals ) elsif :"%syntax" == car self.makeClosure( :"%syntax", sexp.cdr, locals ) elsif :"&block" == car self.makeClosure( :"&block", sexp.cdr, locals ) elsif :if == car self.makeIf( sexp.cdr, locals ) elsif :let == car self.makeLet( sexp.cdr, locals ) elsif :letrec == car self.makeLetrec( sexp.cdr, locals ) elsif :"%tailcall" == car if sexp.cdr.car.is_a? Cell sexp = sexp.cdr.car self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals, sourceInfo, EXEC_TYPE_TAILCALL ) else raise RuntimeError, "Error: special form tailcall expects function call expression." end else self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals, sourceInfo, EXEC_TYPE_NORMAL ) end when Array raise RuntimeError, "Error: can't eval unquoted vector." else case sexp when Symbol sym = sexp.to_s sym = toRubySymbol( sym ) lispSymbolReference( sym, locals, nil, sexp.sourcefile, sexp.lineno ) when Fixnum sexp.to_s when String, LispString sprintf( "\"%s\"", LispString.escape( sexp )) when LispRegexp if sexp.ignoreCase sprintf( "Regexp.new( \"%s\", Regexp::IGNORECASE)", sexp.escape ) else sprintf( "Regexp.new( \"%s\")", sexp.escape ) end when LispKeyword sprintf( "LispKeyword.new( \"%s\" )", sexp.key ) when Nil "Nil.new" when TrueClass, FalseClass, NilClass # reserved symbols toRubyValue( sexp ) else sexp.to_s end end end |