nendo 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/nendo.rb CHANGED
@@ -34,13 +34,11 @@
34
34
  #
35
35
  # $Id:
36
36
  #
37
-
38
- require 'pp'
39
-
40
37
  module Nendo
41
38
  require 'stringio'
42
39
  require 'digest/sha1'
43
-
40
+ require 'pp'
41
+
44
42
  class Nil
45
43
  include Enumerable
46
44
  def each() end
@@ -83,10 +81,10 @@ module Nendo
83
81
  end
84
82
  attr_reader :syntaxName
85
83
  end
86
-
84
+
87
85
  class Cell
88
86
  include Enumerable
89
-
87
+
90
88
  def initialize( car = Nil.new, cdr = Nil.new )
91
89
  @car = car
92
90
  @cdr = cdr
@@ -151,6 +149,21 @@ module Nendo
151
149
  self.map {|x| x.car}
152
150
  end
153
151
  end
152
+
153
+ def first
154
+ self.car
155
+ end
156
+
157
+ def second
158
+ self.cdr.car
159
+ end
160
+
161
+ def third
162
+ self.cdr.cdr.car
163
+ end
164
+
165
+ alias :cdar :second
166
+ alias :cddar :third
154
167
  end
155
168
 
156
169
  class LispValues
@@ -202,6 +215,34 @@ module Nendo
202
215
  attr_reader :key
203
216
  end
204
217
 
218
+ class SyntacticClosure
219
+ def initialize( originalSymbol, renamedSymbol )
220
+ @originalSymbol = originalSymbol
221
+ @renamedSymbol = renamedSymbol
222
+ end
223
+
224
+ def to_s
225
+ @renamedSymbol.to_s
226
+ end
227
+
228
+ def intern
229
+ @renamedSymbol
230
+ end
231
+
232
+ # def ==(other_sc)
233
+ # if other_sc.is_a? SyntacticClosure
234
+ # @renamedSymbol == other_sc.renamedSymbol
235
+ # else
236
+ # false
237
+ # end
238
+ # end
239
+
240
+ def sourcefile() "dynamic S-expression ( no source )" end
241
+ def lineno() 1 end
242
+
243
+ attr_reader :originalSymbol, :renamedSymbol
244
+ end
245
+
205
246
  class SourceInfo
206
247
  def initialize
207
248
  @varname = nil
@@ -330,6 +371,7 @@ module Nendo
330
371
  T_LINEFEED = :t_linefeed
331
372
  T_COMMENT = :t_comment
332
373
  T_DEBUG_PRINT = :t_debug_print
374
+ T_MACRO_DEBUG_PRINT = :t_macro_debug_print
333
375
  T_REGEXP = :t_regexp
334
376
 
335
377
  # inport is IO class
@@ -498,10 +540,13 @@ module Nendo
498
540
  if peekchar( /[=]/ )
499
541
  str = ""
500
542
  T_DEBUG_PRINT
543
+ elsif peekchar( /[.]/ )
544
+ str = ""
545
+ T_MACRO_DEBUG_PRINT
501
546
  else
502
547
  str += readwhile( /[^ \t\r\n]/ )
503
548
  raise NameError, sprintf( "Error: unknown #xxxx syntax for Nendo %s", str )
504
- end
549
+ end
505
550
  when "!"
506
551
  readwhile( /[^\r\n]/ )
507
552
  str = ""
@@ -638,6 +683,8 @@ module Nendo
638
683
  :feedto
639
684
  when T_DEBUG_PRINT
640
685
  "debug-print".intern
686
+ when T_MACRO_DEBUG_PRINT
687
+ LispString.new( sprintf( "%s:%d", cur.sourcefile, cur.lineno ))
641
688
  when T_KEYWORD
642
689
  LispKeyword.new( cur.str )
643
690
  else
@@ -833,12 +880,14 @@ module Nendo
833
880
  def _equal_QUMARK( a, b )
834
881
  if a.is_a? String and b.is_a? String
835
882
  a === b
836
- elsif _null_QUMARK( a ) and _null_QUMARK( b )
837
- true
838
883
  elsif a.class != b.class
839
884
  false
840
- elsif a.class == Cell
885
+ elsif a.is_a? Cell
841
886
  _equal_QUMARK( a.car, b.car ) and _equal_QUMARK( a.cdr, b.cdr )
887
+ elsif _null_QUMARK( a ) and _null_QUMARK( b )
888
+ true
889
+ elsif a.is_a? Proc
890
+ a == b
842
891
  else
843
892
  (a === b)
844
893
  end
@@ -1045,15 +1094,22 @@ module Nendo
1045
1094
  def _le_QUMARK( a,b ) a <= b end
1046
1095
  def _eqv_QUMARK( a,b ) a === b end
1047
1096
  def _car( cell ) cell.car end
1048
- def _cdr( cell ) cell.cdr end
1097
+ def _cdr( cell )
1098
+ if cell.cdr.is_a? Nil
1099
+ Cell.new
1100
+ else
1101
+ cell.cdr
1102
+ end
1103
+ end
1049
1104
  def _write( arg ) printer = Printer.new ; print printer._write( arg ) ; arg end
1050
1105
  def _write_MIMARKto_MIMARKstring( arg ) printer = Printer.new ; printer._write( arg ) end
1106
+ alias write_to_string _write_MIMARKto_MIMARKstring
1051
1107
  def _display( arg ) printer = Printer.new ; print printer._print( arg ) ; arg end
1052
1108
  def _print( arg ) self._display( arg ) ; self._newline() ; arg end
1053
1109
  def _newline( ) print "\n" end
1054
1110
  def _procedure_QUMARK( arg ) ((Proc == arg.class) or (Method == arg.class)) end
1055
1111
  def _macro_QUMARK( arg ) (LispMacro == arg.class) end
1056
- def _symbol_QUMARK( arg ) (Symbol == arg.class) end
1112
+ def _symbol_QUMARK( arg ) (arg.is_a? Symbol or arg.is_a? SyntacticClosure) end
1057
1113
  def _keyword_QUMARK( arg ) (arg.is_a? LispKeyword) end
1058
1114
  def _syntax_QUMARK( arg ) (arg.is_a? LispSyntax) end
1059
1115
  def _core_MIMARKsyntax_QUMARK( arg )
@@ -1083,7 +1139,7 @@ module Nendo
1083
1139
  def _macroexpand_MIMARK1( arg )
1084
1140
  if _pair_QUMARK( arg )
1085
1141
  macroexpandInit( 1 )
1086
- macroexpandEngine( arg )
1142
+ macroexpandEngine( arg, [], [] )
1087
1143
  else
1088
1144
  arg
1089
1145
  end
@@ -1273,6 +1329,8 @@ module Nendo
1273
1329
  @binding = binding
1274
1330
  @debug = debug
1275
1331
  @trace_debug = false
1332
+ @lexicalVars = []
1333
+ @syntaxHash = {}
1276
1334
  @char_table_lisp_to_ruby = {
1277
1335
  # list (! $ % & * + - . / : < = > ? @ ^ _ ~ ...)
1278
1336
  '!' => '_EXMARK',
@@ -1297,7 +1355,7 @@ module Nendo
1297
1355
  }
1298
1356
  @char_table_ruby_to_lisp = @char_table_lisp_to_ruby.invert
1299
1357
 
1300
- @core_syntax_list = [ :quote, :"syntax-quote", :if , :begin , :lambda , :macro , :"&block" , :let , :letrec , :define, :set!, :error, :"%syntax", :"define-syntax" ]
1358
+ @core_syntax_list = [ :quote, :"syntax-quote", :if , :begin , :lambda , :macro , :"&block" , :"%let" , :letrec , :define, :set!, :error, :"%syntax", :"define-syntax", :"let-syntax" ]
1301
1359
  @core_syntax_hash = Hash.new
1302
1360
  @core_syntax_list.each { |x|
1303
1361
  renamed = ("/nendo/core/" + x.to_s).intern
@@ -1419,29 +1477,33 @@ module Nendo
1419
1477
  end
1420
1478
 
1421
1479
  def toRubySymbol( name )
1422
- name = name.to_s if Symbol == name.class
1423
- if 0 == name.length
1424
- ""
1425
- else
1426
- name.gsub!( Regexp.new( Regexp.escape( '...' )), @char_table_lisp_to_ruby[ '...' ] )
1427
- arr = name.gsub( /["]/, '' ).split( /[.]/ )
1428
- tmp = arr[0]
1429
- tmp.gsub!( /[:][:]/, " " ) # save '::'
1430
- @char_table_lisp_to_ruby.each_pair { |key,val|
1431
- tmp.gsub!( Regexp.new( Regexp.escape( key )), val )
1432
- }
1433
- arr[0] = tmp.gsub( /[ ][ ]/, "::" )
1434
- if arr[0].match( /^[A-Z]/ )
1435
- # nothing to do
1436
- elsif arr[0] == ""
1437
- arr[0] = 'Kernel'
1480
+ if SyntacticClosure == name.class
1481
+ "_" + name.to_s
1482
+ else
1483
+ name = name.to_s if Symbol == name.class
1484
+ if 0 == name.length
1485
+ ""
1438
1486
  else
1439
- arr[0] = '_' + arr[0]
1487
+ name.gsub!( Regexp.new( Regexp.escape( '...' )), @char_table_lisp_to_ruby[ '...' ] )
1488
+ arr = name.gsub( /["]/, '' ).split( /[.]/ )
1489
+ tmp = arr[0]
1490
+ tmp.gsub!( /[:][:]/, " " ) # save '::'
1491
+ @char_table_lisp_to_ruby.each_pair { |key,val|
1492
+ tmp.gsub!( Regexp.new( Regexp.escape( key )), val )
1493
+ }
1494
+ arr[0] = tmp.gsub( /[ ][ ]/, "::" )
1495
+ if arr[0].match( /^[A-Z]/ )
1496
+ # nothing to do
1497
+ elsif arr[0] == ""
1498
+ arr[0] = 'Kernel'
1499
+ else
1500
+ arr[0] = '_' + arr[0]
1501
+ end
1502
+ arr.join( "." )
1440
1503
  end
1441
- arr.join( "." )
1442
1504
  end
1443
1505
  end
1444
-
1506
+
1445
1507
  def isRubyInterface( name )
1446
1508
  name.to_s.match( /[.]/ )
1447
1509
  end
@@ -1550,9 +1612,12 @@ module Nendo
1550
1612
  }
1551
1613
  end
1552
1614
 
1615
+ def isDefines( sym )
1616
+ [ :define, :set!, :"define-syntax", @core_syntax_hash[ :define ], @core_syntax_hash[ :set! ], @core_syntax_hash[ :"define-syntax" ] ].include?( sym )
1617
+ end
1618
+
1553
1619
  def execFunc( funcname, args, sourcefile, lineno, locals, sourceInfo, execType )
1554
- case funcname
1555
- when :define, :set!, :"define-syntax", @core_syntax_hash[ :define ], @core_syntax_hash[ :set! ], @core_syntax_hash[ :"define-syntax" ] # `define' special form
1620
+ if isDefines( funcname )
1556
1621
  ar = args.cdr.map { |x| x.car }
1557
1622
  variable_sym = toRubySymbol( args.car.to_s.sub( /^:/, "" ))
1558
1623
  global_cap = locals.flatten.include?( variable_sym.split( /[.]/ )[0] ) ? nil : "@"
@@ -1573,7 +1638,7 @@ module Nendo
1573
1638
  "trampCall(", [ ar ], ")"],
1574
1639
  "end"
1575
1640
  ]
1576
- when :error, @core_syntax_hash[ :error ]
1641
+ elsif :error == funcname or @core_syntax_hash[ :error ] == funcname
1577
1642
  arr = if args.length < 2
1578
1643
  args.car
1579
1644
  else
@@ -1626,20 +1691,29 @@ module Nendo
1626
1691
  end
1627
1692
  end
1628
1693
  end
1629
-
1694
+
1695
+ def makeSetVariable( car, cdr, locals, sourceInfo )
1696
+ cdr.cdr.each { |x|
1697
+ if Cell == x.class
1698
+ x.car = translate( x.car, locals, sourceInfo )
1699
+ end
1700
+ }
1701
+ execFunc( car, cdr, car.sourcefile, car.lineno, locals, sourceInfo, EXEC_TYPE_ANONYMOUS )
1702
+ end
1703
+
1630
1704
  def makeBegin( args, locals )
1631
1705
  ar = args.map { |e|
1632
1706
  translate( e.car, locals )
1633
1707
  }
1634
1708
  ["begin", ar, "end"]
1635
1709
  end
1636
-
1710
+
1637
1711
  # returns [ argsyms[], string ]
1638
1712
  def toRubyParameter( argform )
1639
1713
  argsyms = []
1640
1714
  locals = []
1641
1715
  rest = false
1642
- if Symbol == argform.class
1716
+ if _symbol_QUMARK( argform )
1643
1717
  rest = argform
1644
1718
  else
1645
1719
  argsyms = argform.map { |x| toRubySymbol( x.car ) }
@@ -1649,7 +1723,7 @@ module Nendo
1649
1723
  end
1650
1724
  end
1651
1725
  if rest
1652
- rest = toRubySymbol( rest )
1726
+ rest = toRubySymbol( rest )
1653
1727
  locals << rest
1654
1728
  argsyms << "*__rest__"
1655
1729
  [ locals, sprintf( "|%s| %s = __rest__[0] ; ", argsyms.join( "," ), rest ) ]
@@ -1657,13 +1731,10 @@ module Nendo
1657
1731
  [ locals, sprintf( "|%s|", argsyms.join( "," )) ]
1658
1732
  end
1659
1733
  end
1660
-
1734
+
1661
1735
  def makeClosure( sym, args, locals )
1662
1736
  first = args.car
1663
- if args.car.car == :quote
1664
- first = args.car.cdr.car
1665
- end
1666
- rest = args.cdr
1737
+ rest = args.cdr
1667
1738
  ( _locals, argStr ) = toRubyParameter( first )
1668
1739
  str = case sym
1669
1740
  when :macro
@@ -1707,12 +1778,12 @@ module Nendo
1707
1778
  _name = "___lambda"
1708
1779
  argvals = []
1709
1780
  rest = args.cdr
1710
- if args.car.is_a? Nil
1781
+ if _null_QUMARK( args.car )
1711
1782
  # nothing to do
1712
1783
  lambda_head = sprintf( "%s = lambda { || ", _name )
1713
1784
  else
1714
1785
  argsyms = args.car.map { |x|
1715
- toRubySymbol( x.car.car.cdr.car.to_s )
1786
+ toRubySymbol( x.car.car.to_s )
1716
1787
  }
1717
1788
  argvals = args.car.map.with_index { |x,i|
1718
1789
  translate( x.car.cdr.car, locals )
@@ -1733,12 +1804,12 @@ module Nendo
1733
1804
  argvals = []
1734
1805
  argsyms = []
1735
1806
  rest = args.cdr
1736
- if args.car.is_a? Nil
1807
+ if _null_QUMARK( args.car )
1737
1808
  # nothing to do
1738
1809
  lambda_head = sprintf( "%s = lambda { || ", _name )
1739
1810
  else
1740
1811
  argsyms = args.car.map { |x|
1741
- toRubySymbol( x.car.car.cdr.car.to_s )
1812
+ toRubySymbol( x.car.car.to_s )
1742
1813
  }
1743
1814
  argvals = args.car.map { |x|
1744
1815
  translate( x.car.cdr.car, locals.clone + [argsyms] )
@@ -1754,7 +1825,7 @@ module Nendo
1754
1825
  sprintf( " )")],
1755
1826
  "end"]
1756
1827
  end
1757
-
1828
+
1758
1829
  def apply( car, cdr, sourcefile, lineno, locals, sourceInfo, execType )
1759
1830
  cdr.each { |x|
1760
1831
  if Cell == x.class
@@ -1763,7 +1834,7 @@ module Nendo
1763
1834
  }
1764
1835
  execFunc( car, cdr, sourcefile, lineno, locals, sourceInfo, execType )
1765
1836
  end
1766
-
1837
+
1767
1838
  def genQuote( sexp, str = "" )
1768
1839
  origStr = str
1769
1840
  case sexp
@@ -1788,6 +1859,8 @@ module Nendo
1788
1859
  str += sprintf( "LispKeyword.new( \"%s\" )", sexp.key.to_s )
1789
1860
  when TrueClass, FalseClass, NilClass # reserved symbols
1790
1861
  str += toRubyValue( sexp )
1862
+ when SyntacticClosure
1863
+ str += sprintf( ":\"%s\"", sexp.originalSymbol.to_s )
1791
1864
  when Nil
1792
1865
  str += "Cell.new()"
1793
1866
  else
@@ -1852,14 +1925,16 @@ module Nendo
1852
1925
  else
1853
1926
  sexp.car
1854
1927
  end
1855
- if :quote == car or :"syntax-quote" == car
1856
- genQuote( sexp.cdr.car )
1928
+ if :quote == car
1929
+ genQuote( sexp.second )
1930
+ elsif :"syntax-quote" == car
1931
+ [ "Cell.new(:\"syntax-quote\", ", genQuote( sexp.cdr ), ")" ]
1857
1932
  elsif sexp.isDotted
1858
1933
  raise NameError, "Error: can't eval dotted pair."
1859
1934
  elsif sexp.isNull
1860
1935
  [ "Cell.new()" ]
1861
- elsif Cell == sexp.car.class
1862
- self.apply( translate( sexp.car, locals, sourceInfo ), sexp.cdr, sexp.car.car.sourcefile, sexp.car.car.lineno, locals, sourceInfo, EXEC_TYPE_ANONYMOUS )
1936
+ elsif isDefines( car )
1937
+ self.makeSetVariable( car, sexp.cdr, locals, sourceInfo )
1863
1938
  elsif :begin == car
1864
1939
  self.makeBegin( sexp.cdr, locals )
1865
1940
  elsif :lambda == car
@@ -1872,17 +1947,27 @@ module Nendo
1872
1947
  self.makeClosure( :"&block", sexp.cdr, locals )
1873
1948
  elsif :if == car
1874
1949
  self.makeIf( sexp.cdr, locals )
1875
- elsif :let == car
1950
+ elsif :"%let" == car
1876
1951
  self.makeLet( sexp.cdr, locals )
1877
1952
  elsif :letrec == car
1878
1953
  self.makeLetrec( sexp.cdr, locals )
1879
1954
  elsif :"%tailcall" == car
1880
1955
  if sexp.cdr.car.is_a? Cell
1881
1956
  sexp = sexp.cdr.car
1882
- self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals, sourceInfo, EXEC_TYPE_TAILCALL )
1957
+ if isDefines( sexp.car )
1958
+ translate( sexp, locals, sourceInfo )
1959
+ else
1960
+ if sexp.car.is_a? Cell
1961
+ self.apply( translate( sexp.car, locals, sourceInfo ), sexp.cdr, sexp.car.car.sourcefile, sexp.car.car.lineno, locals, sourceInfo, EXEC_TYPE_ANONYMOUS )
1962
+ else
1963
+ self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals, sourceInfo, EXEC_TYPE_TAILCALL )
1964
+ end
1965
+ end
1883
1966
  else
1884
1967
  raise RuntimeError, "Error: special form tailcall expects function call expression."
1885
1968
  end
1969
+ elsif Cell == sexp.car.class
1970
+ self.apply( translate( sexp.car, locals, sourceInfo ), sexp.cdr, sexp.car.car.sourcefile, sexp.car.car.lineno, locals, sourceInfo, EXEC_TYPE_ANONYMOUS )
1886
1971
  else
1887
1972
  self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals, sourceInfo, EXEC_TYPE_NORMAL )
1888
1973
  end
@@ -1910,139 +1995,233 @@ module Nendo
1910
1995
  "Nil.new"
1911
1996
  when TrueClass, FalseClass, NilClass # reserved symbols
1912
1997
  toRubyValue( sexp )
1998
+ when SyntacticClosure
1999
+ toRubySymbol( sexp )
1913
2000
  else
1914
2001
  sexp.to_s
1915
2002
  end
1916
2003
  end
1917
2004
  end
1918
-
1919
- # insert quote in let argument list
1920
- # ((sym1 list1)
1921
- # (sym2 list2)
1922
- # (sym3 list3))
1923
- # will be transformed
1924
- # (((quote sym1) list1)
1925
- # ((quote sym2) list2)
1926
- # ((quote sym3) list3))
1927
- def letArgumentList( sexp )
1928
- sexp.each { |arg|
1929
- arg.car.car = Cell.new( :quote, Cell.new( arg.car.car ))
1930
- arg.car.cdr = quotingPhase( arg.car.cdr )
2005
+
2006
+
2007
+ # warp sexp by lexicalVars
2008
+ def __wrapNestedLet( sexp, lexicalVars )
2009
+ if 0 == lexicalVars.size
2010
+ sexp
2011
+ else
2012
+ elem = lexicalVars.shift
2013
+ Cell.new( :"%let",
2014
+ Cell.new(
2015
+ Cell.new(
2016
+ Cell.new( elem[0], elem[1] )),
2017
+ Cell.new( __wrapNestedLet( sexp, lexicalVars ) )))
2018
+ end
2019
+ end
2020
+
2021
+ def __removeSameLexicalScopeVariables( frame )
2022
+ frame.select {|x|
2023
+ # search same varname and different value
2024
+ found = frame.any? {|y|
2025
+ x[0] == y[0] and (not _equal_QUMARK( x[1], y[1] ))
2026
+ }
2027
+ if found
2028
+ x
2029
+ else
2030
+ false
2031
+ end
1931
2032
  }
2033
+ end
2034
+
2035
+ def macroexpandInit( initVal )
2036
+ @macroExpandCount = initVal
2037
+ end
2038
+
2039
+ def macroexpandEngineLoop( sexp, syntaxArray, lexicalVars )
2040
+ converge = true
2041
+ begin
2042
+ newSexp = macroexpandEngine( sexp, syntaxArray, lexicalVars )
2043
+ converge = _equal_QUMARK( newSexp, sexp )
2044
+ sexp = newSexp
2045
+ end until converge or (@macroExpandCount <= 0)
1932
2046
  sexp
1933
2047
  end
1934
-
1935
- def quotingPhase( sexp )
1936
- case sexp
1937
- when Cell
1938
- car = sexp.car
1939
- if :quote == car or :quasiquote == car or :"syntax-quote" == car or
1940
- @core_syntax_hash[ :quote ] == car or
1941
- @core_syntax_hash[ :quasiquote ] == car or
1942
- @core_syntax_hash[ :"syntax-quote" ] == car
1943
- sexp
1944
- elsif :define == car or :set! == car or :lambda == car or :macro == car or :"&block" == car or :"%syntax" == car or :"define-syntax" == car or
1945
- @core_syntax_hash[ :define ] == car or
1946
- @core_syntax_hash[ :set! ] == car or
1947
- @core_syntax_hash[ :lambda ] == car or
1948
- @core_syntax_hash[ :macro ] == car or
1949
- @core_syntax_hash[ :"&block" ] == car or
1950
- @core_syntax_hash[ :"%syntax" ] == car or
1951
- @core_syntax_hash[ :"define-syntax" ] == car
1952
- if @debug
1953
- if 2 >= sexp.length
1954
- printf( "\n quotingPhase-1 label=%s, sexp.length=%d \n", sexp.car, sexp.length )
1955
- else
1956
- 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 )
1957
- end
1958
- end
1959
- if 1 == sexp.length
1960
- nil
1961
- # do nothing
1962
- elsif 3 <= sexp.length
1963
- # argument
1964
- sexp.cdr.car = Cell.new( :quote, Cell.new( sexp.cdr.car ))
1965
- # body
1966
- sexp.cdr.cdr = quotingPhase( sexp.cdr.cdr )
1967
- else
1968
- raise RuntimeError, sprintf( "Error: %s is not a illegal form got: %s", sexp.car, _write_MIMARKto_MIMARKstring( sexp ))
1969
- end
1970
- sexp
1971
- elsif :let == car or @core_syntax_hash[ :let ] == car
1972
- if _null_QUMARK( sexp.cdr )
1973
- # do nothing
1974
- else
1975
- case sexp.cdr.car
1976
- when Cell # let
1977
- sexp.cdr = Cell.new( letArgumentList( sexp.cdr.car ),
1978
- quotingPhase( sexp.cdr.cdr ))
1979
- when Symbol # named let
1980
- sexp.cdr.car = Cell.new( :quote, Cell.new( sexp.cdr.car ))
1981
- sexp.cdr.cdr = Cell.new( letArgumentList( sexp.cdr.cdr.car ),
1982
- quotingPhase( sexp.cdr.cdr.cdr ))
1983
- end
1984
- end
1985
- sexp
1986
- elsif :letrec == car or @core_syntax_hash[ :letrec ] == car
1987
- if _null_QUMARK( sexp.cdr )
1988
- # do nothing
2048
+
2049
+ def macroexpandEngine( sexp, syntaxArray, lexicalVars )
2050
+ if @macroExpandCount <= 0
2051
+ sexp
2052
+ else
2053
+ __macroexpandEngine( sexp, syntaxArray, lexicalVars )
2054
+ end
2055
+ end
2056
+
2057
+ #
2058
+ # expand (syntax-rules ...) => (%syntax-rules ...)
2059
+ #
2060
+ def __expandSyntaxRules( rules, syntaxArray, lexicalVars )
2061
+ if :"%syntax-rules" == rules.car
2062
+ rules
2063
+ else
2064
+ ellipse = rules.second
2065
+ pattern_body_list = rules.cdr.cdr
2066
+
2067
+ lst = []
2068
+ lst << :"syntax-rules"
2069
+ lst << ellipse
2070
+ pattern_body_list.each {|xx|
2071
+ pattern_body = xx.car
2072
+ pattern = pattern_body.first
2073
+ body = pattern_body.second
2074
+ new_pattern_body = [ pattern, macroexpandEngine( body, syntaxArray, lexicalVars ) ].to_list
2075
+ lst << new_pattern_body
2076
+ }
2077
+ lst.to_list
2078
+ end
2079
+ end
2080
+
2081
+ # eval (syntax-rules ...) sexp
2082
+ #
2083
+ # return:
2084
+ # (%syntax-rules
2085
+ # ((v1 <<@syntaxHash's key1>>)
2086
+ # (v2 <<@syntaxHash's key2>>)
2087
+ # body))
2088
+ #
2089
+ # example:
2090
+ # (%syntax-rules
2091
+ # ((v1 "x = 10 // (+ x v1)")
2092
+ # (v2 "y = 20 // (+ y v2)"))
2093
+ # (+ v1 v2))
2094
+ #
2095
+ def __evalSyntaxRules( rules, lexicalVars )
2096
+ if :"%syntax-rules" == rules.car
2097
+ rules.second
2098
+ else
2099
+ lexvars = lexicalVars.select { |x|
2100
+ if _symbol_MIMARKinclude_QUMARK( rules, x[0].intern )
2101
+ x
2102
+ elsif lexicalVars.find {|y| _symbol_MIMARKinclude_QUMARK( y[1], x[0].intern ) }
2103
+ x
1989
2104
  else
1990
- case sexp.cdr.car
1991
- when Cell # letrec
1992
- sexp.cdr = Cell.new( letArgumentList( sexp.cdr.car ),
1993
- quotingPhase( sexp.cdr.cdr ))
1994
- when Symbol # named letrec is illegal
1995
- raise RuntimeError, "Error: named letrec is not a illegal form"
1996
- end
2105
+ false
1997
2106
  end
1998
- sexp
2107
+ }
2108
+
2109
+ __setupLexicalScopeVariables( lexvars )
2110
+ keyStr = lexvars.map {|z|
2111
+ z[0].to_s + " / " + write_to_string( z[1] )
2112
+ }.join( " / " )
2113
+ keyStr += " // " + write_to_string( rules )
2114
+ if @syntaxHash.has_key?( keyStr )
2115
+ true
1999
2116
  else
2000
- Cell.new( quotingPhase( sexp.car ), quotingPhase( sexp.cdr ))
2117
+ @syntaxHash[ keyStr ] = [ lexvars,
2118
+ self.lispEval( rules, "dynamic syntax-rules sexp (no source) ", 1 ) ]
2001
2119
  end
2002
- else
2003
- sexp
2120
+ __setupLexicalScopeVariables( [] )
2121
+ keyStr
2004
2122
  end
2005
2123
  end
2006
-
2007
- def macroexpandInit( initVal )
2008
- @macroExpandCount = initVal
2009
- end
2010
2124
 
2011
- def macroexpandEngine( sexp )
2125
+ # args:
2126
+ #
2127
+ # syntaxArray ... let-syntax's identifiers
2128
+ # [
2129
+ # [ identifier-name, key of @syntaxHash, sexp of (syntax-rules ...), frame_of_let-syntax ],
2130
+ # .
2131
+ # .
2132
+ # ]
2133
+ # lexicalVars ... let's identifiers
2134
+ # [
2135
+ # [ identifier-name, macroexpandEngine( let's body ) ],
2136
+ # ]
2137
+ #
2138
+ #
2139
+ def __macroexpandEngine( sexp, syntaxArray, lexicalVars )
2012
2140
  case sexp
2013
2141
  when Cell
2014
2142
  car = sexp.car
2015
2143
  if :quote == car or :"syntax-quote" == car or @core_syntax_hash[ :quote ] == car or @core_syntax_hash[ :"syntax-quote" ] == car
2016
2144
  sexp
2145
+ elsif :"%let" == car or :letrec == car or @core_syntax_hash[ :"%let" ] == car or @core_syntax_hash[ :letrec ] == car
2146
+ # catch lexical identifiers of `let' and `letrec'.
2147
+ arr = sexp.second.map { |x|
2148
+ [ x.car.car, macroexpandEngine( x.car.cdr, syntaxArray, lexicalVars ) ]
2149
+ }
2150
+ lst = arr.map {|x| Cell.new( x[0], x[1] ) }.to_list
2151
+ ret = Cell.new( car,
2152
+ Cell.new( lst,
2153
+ macroexpandEngine( sexp.cdr.cdr, syntaxArray, lexicalVars + arr )))
2154
+ ret
2155
+ elsif :"let-syntax" == car
2156
+ sexp.second.each {|x|
2157
+ if not x.car.second.is_a? Cell
2158
+ raise SyntaxError, "Error: let-syntax get only '((name (syntax-rules ...)))' form but got: " + write_to_string( x )
2159
+ elsif not ( x.car.second.first == :"syntax-rules" or x.car.second.first == :"%syntax-rules")
2160
+ raise SyntaxError, "Error: let-syntax get only '((name (syntax-rules ...)))' form but got: " + write_to_string( x )
2161
+ end
2162
+ }
2163
+ arr_tmp = sexp.second.map { |x|
2164
+ [ x.car.first, __expandSyntaxRules( x.car.second, syntaxArray, lexicalVars ) ]
2165
+ }
2166
+ arr = arr_tmp.map {|x|
2167
+ [ x[0], __evalSyntaxRules( x[1], lexicalVars ), x[1], lexicalVars ]
2168
+ }
2169
+
2170
+ # trial (expand recursively)
2171
+ arr_tmp = arr.map { |x|
2172
+ [ x[0], __expandSyntaxRules( x[2], syntaxArray + arr, lexicalVars ) ]
2173
+ }
2174
+ arr = arr_tmp.map {|x|
2175
+ [ x[0], __evalSyntaxRules( x[1], lexicalVars ), x[1], lexicalVars ]
2176
+ }
2177
+
2178
+ # keywords = ((let-syntax-keyword ( let-syntax-body ))
2179
+ # (let-syntax-keyword ( let-syntax-body ))
2180
+ # ..)
2181
+ newKeywords = arr.map { |e|
2182
+ [ e[0], [ :"%syntax-rules", e[1]].to_list ].to_list
2183
+ }.to_list
2184
+
2185
+ ret = Cell.new( :"let-syntax",
2186
+ Cell.new( newKeywords, macroexpandEngine( sexp.cdr.cdr, syntaxArray + arr, lexicalVars )))
2187
+
2188
+ ret
2017
2189
  else
2018
- sym = sexp.car.to_s
2019
- p 'macroexpandEngine' if @debug
2020
- p sexp.car.class if @debug
2021
- p sym if @debug
2022
- sym = toRubySymbol( sym )
2190
+ sym = toRubySymbol( car.to_s )
2023
2191
  newSexp = sexp
2024
2192
  if isRubyInterface( sym )
2025
2193
  # do nothing
2026
2194
  sexp
2027
- elsif sexp.car.class == Symbol and eval( sprintf( "(defined? @%s and LispMacro == @%s.class)", sym,sym ), @binding )
2195
+ elsif _symbol_QUMARK( car ) and eval( sprintf( "(defined? @%s and LispMacro == @%s.class)", sym,sym ), @binding )
2028
2196
  eval( sprintf( "@__macro = @%s", sym ), @binding )
2029
2197
  newSexp = trampCall( callProcedure( sym, @__macro, sexp.cdr.to_arr ))
2030
- elsif sexp.car.class == Symbol and eval( sprintf( "(defined? @%s and LispSyntax == @%s.class)", sym,sym ), @binding )
2198
+ elsif _symbol_QUMARK( car ) and eval( sprintf( "(defined? @%s and LispSyntax == @%s.class)", sym,sym ), @binding )
2031
2199
  # expected input is
2032
2200
  # (syntaxName arg1 arg2 ...)
2033
2201
  # will be transformed
2034
2202
  # (syntaxName (syntaxName arg1 arg2 ...) () (global-variables))
2035
2203
  eval( sprintf( "@__syntax = @%s", sym ), @binding )
2036
2204
  newSexp = trampCall( callProcedure( sym, @__syntax, [ sexp, Cell.new(), _global_MIMARKvariables( ) ] ))
2205
+ elsif _symbol_QUMARK( car ) and syntaxArray.map {|arr| arr[0].intern}.include?( car.intern )
2206
+ # lexical macro expandeding
2207
+ symbol_and_syntaxObj = syntaxArray.reverse.find {|arr| car == arr[0]}
2208
+ keys = syntaxArray.reverse.map { |arr| arr[0] }
2209
+ if not symbol_and_syntaxObj
2210
+ raise "can't find valid syntaxObject"
2211
+ end
2212
+ vars = symbol_and_syntaxObj[3].map { |arr| arr[0] }
2213
+ lexvars = @syntaxHash[ symbol_and_syntaxObj[1] ][0]
2214
+ lispSyntax = @syntaxHash[ symbol_and_syntaxObj[1] ][1]
2215
+ newSexp = trampCall( callProcedure( symbol_and_syntaxObj[0], lispSyntax, [
2216
+ sexp,
2217
+ Cell.new(),
2218
+ (_global_MIMARKvariables( ).to_arr + keys + vars).to_list ] ))
2219
+ newSexp = __wrapNestedLet( newSexp, __removeSameLexicalScopeVariables( lexicalVars + lexvars ))
2037
2220
  end
2038
2221
  if _equal_QUMARK( newSexp, sexp )
2039
2222
  sexp.map { |x|
2040
2223
  if x.car.is_a? Cell
2041
- if 0 <= @macroExpandCount
2042
- macroexpandEngine( x.car )
2043
- else
2044
- x.car
2045
- end
2224
+ macroexpandEngine( x.car, syntaxArray, lexicalVars )
2046
2225
  else
2047
2226
  x.car
2048
2227
  end
@@ -2056,18 +2235,14 @@ module Nendo
2056
2235
  sexp
2057
2236
  end
2058
2237
  end
2059
-
2060
- def macroExpandPhase( sexp )
2061
- converge = true
2062
- begin
2063
- macroexpandInit( 100000 )
2064
- newSexp = macroexpandEngine( sexp )
2065
- converge = _equal_QUMARK( newSexp, sexp )
2066
- sexp = newSexp
2067
- end until converge
2068
- sexp
2238
+
2239
+ def macroexpandPhase( sexp )
2240
+ macroexpandInit( 100000 )
2241
+ _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword(
2242
+ _strip_MIMARKsyntax_MIMARKquote(
2243
+ macroexpandEngineLoop( sexp, [], [] )))
2069
2244
  end
2070
-
2245
+
2071
2246
  def ppRubyExp( level, exp )
2072
2247
  indent = @indent * level
2073
2248
  exp.map { |x|
@@ -2083,7 +2258,7 @@ module Nendo
2083
2258
  end
2084
2259
  }
2085
2260
  end
2086
-
2261
+
2087
2262
  def displayTopOfCalls( exception )
2088
2263
  STDERR.puts( "\n <<< Top of calls >>>" )
2089
2264
  strs = []
@@ -2096,29 +2271,31 @@ module Nendo
2096
2271
  STDERR.puts( str )
2097
2272
  }
2098
2273
  end
2099
-
2274
+
2100
2275
  def lispEval( sexp, sourcefile, lineno )
2101
2276
  begin
2102
2277
  sourceInfo = SourceInfo.new
2103
2278
  @lastSourcefile = sourcefile
2104
2279
  @lastLineno = lineno
2105
2280
  sourceInfo.setSource( sourcefile, lineno, sexp )
2106
- sexp = macroExpandPhase( sexp )
2107
- sexp = quotingPhase( sexp )
2281
+
2282
+ # macro expand phase
2283
+ sexp = macroexpandPhase( sexp )
2108
2284
  if @debug
2109
- printf( "\n quoting=<<< %s >>>\n", (Printer.new())._print(sexp))
2285
+ printf( "\n expaneded=<<< %s >>>\n", (Printer.new())._print(sexp))
2110
2286
  end
2111
- # compiling phase written in Nendo
2287
+
2288
+ # compiling phase written
2112
2289
  sym = toRubySymbol( "%compile-phase" )
2113
2290
  if ( eval( sprintf( "(defined? @%s and Proc == @%s.class)", sym,sym ), @binding ))
2114
2291
  eval( sprintf( "@___tmp = @%s", sym ), @binding )
2115
2292
  sexp = trampCall( callProcedure( sym, @___tmp, [ sexp ]))
2116
2293
  if @debug
2117
- printf( "\n compiled=<<< %s >>>\n", (Printer.new())._print(sexp))
2294
+ printf( "\n compiled= <<< %s >>>\n", (Printer.new())._print(sexp))
2118
2295
  end
2119
2296
  end
2120
2297
  sourceInfo.setExpanded( sexp )
2121
-
2298
+
2122
2299
  arr = [ "trampCall( ", translate( sexp, [], sourceInfo ), " )" ]
2123
2300
  rubyExp = ppRubyExp( 0, arr ).flatten.join
2124
2301
  sourceInfo.setCompiled( rubyExp )
@@ -2154,23 +2331,23 @@ module Nendo
2154
2331
  }
2155
2332
  forward_gensym_counter()
2156
2333
  end
2157
-
2334
+
2158
2335
  def _load_MIMARKcompiled_MIMARKcode_MIMARKfrom_MIMARKstring( rubyExp )
2159
2336
  eval( rubyExp, @binding )
2160
2337
  forward_gensym_counter()
2161
2338
  end
2162
-
2339
+
2163
2340
  def __PAMARKload_MIMARKcompiled_MIMARKcode( filename )
2164
2341
  open( filename, "r:utf-8" ) { |f|
2165
2342
  eval( f.read, @binding )
2166
2343
  }
2167
2344
  forward_gensym_counter()
2168
2345
  end
2169
-
2346
+
2170
2347
  def _clean_MIMARKcompiled_MIMARKcode
2171
2348
  @compiled_code = Hash.new
2172
2349
  end
2173
-
2350
+
2174
2351
  def _get_MIMARKcompiled_MIMARKcode
2175
2352
  @compiled_code
2176
2353
  ret = Hash.new
@@ -2180,11 +2357,11 @@ module Nendo
2180
2357
  }
2181
2358
  ret.to_list
2182
2359
  end
2183
-
2360
+
2184
2361
  def _eval( sexp )
2185
2362
  self.lispEval( sexp, "dynamic S-expression ( no source )", 1 )
2186
2363
  end
2187
-
2364
+
2188
2365
  def _enable_MIMARKidebug()
2189
2366
  @debug = true
2190
2367
  end
@@ -2246,21 +2423,116 @@ module Nendo
2246
2423
  true
2247
2424
  end
2248
2425
 
2426
+ def __setupLexicalScopeVariables( lexicalVars )
2427
+ @lexicalVars = lexicalVars.clone
2428
+ end
2429
+
2249
2430
  def _make_MIMARKsyntactic_MIMARKclosure( mac_env, use_env, identifier )
2250
2431
  if _pair_QUMARK( identifier )
2251
- raise RuntimeError, "Error: make-syntactic-closure requires symbol only..."
2252
- else
2253
- if mac_env.to_arr.include?( identifier )
2432
+ if :"syntax-quote" == identifier.car
2254
2433
  identifier
2255
2434
  else
2256
- sym = toRubySymbol( identifier ) + _gensym( ).to_s
2257
- sym.intern
2435
+ raise TypeError, "make-syntactic-closure requires symbol or (syntax-quote sexp) only. but got: " + write_to_string( identifier )
2258
2436
  end
2437
+ elsif _symbol_QUMARK( identifier )
2438
+ # pp [ "identifier: ", identifier, "include?=", mac_env.to_arr.include?( identifier.intern ) ]
2439
+ # pp [ "mac_env: ", mac_env.to_arr ]
2440
+ if mac_env.to_arr.include?( identifier.intern )
2441
+ found = @lexicalVars.find { |x| identifier == x[0] }
2442
+ if found
2443
+ lexvars = @lexicalVars.clone
2444
+ __wrapNestedLet( identifier, lexvars )
2445
+ else
2446
+ identifier
2447
+ end
2448
+ else
2449
+ SyntacticClosure.new( identifier, (toRubySymbol( identifier ) + _gensym( ).to_s).intern )
2450
+ end
2451
+ else
2452
+ raise TypeError, "make-syntactic-closure requires symbol or (syntax-quote sexp) type."
2453
+ end
2454
+ end
2455
+
2456
+ def _strip_MIMARKsyntax_MIMARKquote( sexp )
2457
+ case sexp
2458
+ when Cell
2459
+ if _null_QUMARK( sexp )
2460
+ sexp
2461
+ else
2462
+ car = sexp.car
2463
+ if :"syntax-quote" == car or @core_syntax_hash[ :"syntax-quote" ] == car
2464
+ Cell.new( :quote, sexp.cdr )
2465
+ else
2466
+ Cell.new(
2467
+ _strip_MIMARKsyntax_MIMARKquote( sexp.car ),
2468
+ _strip_MIMARKsyntax_MIMARKquote( sexp.cdr ))
2469
+ end
2470
+ end
2471
+ else
2472
+ sexp
2473
+ end
2474
+ end
2475
+
2476
+ def _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword( sexp )
2477
+ case sexp
2478
+ when Cell
2479
+ if _null_QUMARK( sexp )
2480
+ sexp
2481
+ else
2482
+ car = sexp.car
2483
+ if :"quote" == car or @core_syntax_hash[ :"quote" ] == car
2484
+ sexp
2485
+ elsif :"let-syntax" == car or @core_syntax_hash[ :"let-syntax" ] == car
2486
+ Cell.new( :begin,
2487
+ _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword( sexp.cdr.cdr ))
2488
+ else
2489
+ Cell.new(
2490
+ _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword( sexp.car ),
2491
+ _strip_MIMARKlet_MIMARKsyntax_MIMARKkeyword( sexp.cdr ))
2492
+ end
2493
+ end
2494
+ else
2495
+ sexp
2259
2496
  end
2260
2497
  end
2261
2498
 
2499
+ def _strip_MIMARKsyntactic_MIMARKclosures( sexp )
2500
+ case sexp
2501
+ when Cell
2502
+ if _null_QUMARK( sexp )
2503
+ sexp
2504
+ else
2505
+ Cell.new(
2506
+ _strip_MIMARKsyntactic_MIMARKclosures( sexp.car ),
2507
+ _strip_MIMARKsyntactic_MIMARKclosures( sexp.cdr ))
2508
+ end
2509
+ else
2510
+ if sexp.is_a? SyntacticClosure
2511
+ sexp.intern
2512
+ else
2513
+ sexp
2514
+ end
2515
+ end
2516
+ end
2517
+
2518
+ def _symbol_MIMARKinclude_QUMARK( sexp, sym )
2519
+ case sexp
2520
+ when Cell
2521
+ if _null_QUMARK( sexp )
2522
+ false
2523
+ else
2524
+ _symbol_MIMARKinclude_QUMARK( sexp.car, sym ) or _symbol_MIMARKinclude_QUMARK( sexp.cdr, sym )
2525
+ end
2526
+ else
2527
+ if _symbol_QUMARK( sexp )
2528
+ sym.intern == sexp.intern
2529
+ else
2530
+ false
2531
+ end
2532
+ end
2533
+ end
2262
2534
  end
2263
-
2535
+
2264
2536
  class Printer
2265
2537
  def initialize( debug = false )
2266
2538
  @debug = debug
@@ -2269,14 +2541,6 @@ module Nendo
2269
2541
  def __write( sexp, readable )
2270
2542
  getQuoteKeyword = lambda { |x|
2271
2543
  case x
2272
- when :quote
2273
- "'"
2274
- when :quasiquote
2275
- "`"
2276
- when :unquote
2277
- ","
2278
- when :"unquote-splicing"
2279
- ",@"
2280
2544
  when :"dot-operator"
2281
2545
  "."
2282
2546
  else
@@ -2314,6 +2578,8 @@ module Nendo
2314
2578
  else
2315
2579
  sexp.to_s
2316
2580
  end
2581
+ when SyntacticClosure
2582
+ sprintf( "#<SyntacticClosure[%s:%s]>", sexp.originalSymbol, sexp.renamedSymbol )
2317
2583
  when Regexp
2318
2584
  "#/" + sexp.source + "/" + (sexp.casefold? ? "i" : "")
2319
2585
  when LispKeyword
@@ -2344,9 +2610,11 @@ module Nendo
2344
2610
  end
2345
2611
 
2346
2612
  def self.version
2347
- "0.5.0" ##NENDO-VERSION
2613
+ "0.5.1" ##NENDO-VERSION
2348
2614
  end
2349
-
2615
+
2616
+ attr_reader :evaluator
2617
+
2350
2618
  def loadInitFile( use_compiled = true )
2351
2619
  done = false
2352
2620
  if use_compiled
@@ -2477,3 +2745,4 @@ class Hash
2477
2745
  arr.to_list
2478
2746
  end
2479
2747
  end
2748
+