nendo 0.1.0 → 0.2.0
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/emacs/nendo-mode.el +84 -0
- data/lib/init.nnd +339 -228
- data/lib/init.nndc +8676 -0
- data/lib/nendo.rb +372 -110
- data/sample/exit.nnd +2 -0
- data/sample/fact.nnd +15 -0
- data/sample/fizzbuzz1.nnd +23 -0
- data/sample/scratch.nnd +11 -0
- data/sample/tak.nnd +13 -0
- metadata +11 -6
data/lib/nendo.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# -*- encoding: utf-8 -*-
|
3
3
|
#
|
4
|
-
# Nendo: "
|
4
|
+
# Nendo: "Nendo is a diarect of Lisp."
|
5
5
|
#
|
6
6
|
#
|
7
7
|
#
|
@@ -26,6 +26,13 @@ class Nil
|
|
26
26
|
end
|
27
27
|
|
28
28
|
class LispString < String
|
29
|
+
def LispString.escape( str )
|
30
|
+
if str.is_a? String
|
31
|
+
str.gsub( /["]/, "\\\"" )
|
32
|
+
else
|
33
|
+
raise TypeError
|
34
|
+
end
|
35
|
+
end
|
29
36
|
end
|
30
37
|
|
31
38
|
class LispMacro < Proc
|
@@ -192,6 +199,7 @@ class Reader
|
|
192
199
|
T_DOT = :t_dot
|
193
200
|
T_LINEFEED = :t_linefeed
|
194
201
|
T_COMMENT = :t_comment
|
202
|
+
T_DEBUG_PRINT = :t_debug_print
|
195
203
|
|
196
204
|
# inport is IO class
|
197
205
|
def initialize( inport, sourcefile, debug = false )
|
@@ -239,6 +247,32 @@ class Reader
|
|
239
247
|
ret
|
240
248
|
end
|
241
249
|
|
250
|
+
def readstring()
|
251
|
+
ret = ""
|
252
|
+
while true
|
253
|
+
ch = @chReader.getc
|
254
|
+
#printf( " readstring: [%s]\n", ch )
|
255
|
+
if !ch # eof?
|
256
|
+
break
|
257
|
+
end
|
258
|
+
if ch.chr.match( /[\\]/ )
|
259
|
+
ch2 = @chReader.getc
|
260
|
+
if ch2.chr == "\"" # \" reduce to "
|
261
|
+
ret += "\""
|
262
|
+
else
|
263
|
+
ret += ch.chr
|
264
|
+
ret += ch2.chr
|
265
|
+
end
|
266
|
+
elsif ch.chr.match( /[^"]/ )
|
267
|
+
ret += ch.chr
|
268
|
+
else
|
269
|
+
@chReader.ungetc( ch )
|
270
|
+
break
|
271
|
+
end
|
272
|
+
end
|
273
|
+
ret
|
274
|
+
end
|
275
|
+
|
242
276
|
def tokenWithComment
|
243
277
|
skipspace
|
244
278
|
ch = @chReader.getc
|
@@ -276,12 +310,28 @@ class Reader
|
|
276
310
|
readwhile( /[^\r\n]/ )
|
277
311
|
str = ""
|
278
312
|
T_COMMENT
|
279
|
-
when /[
|
280
|
-
readwhile( /[
|
281
|
-
|
282
|
-
|
313
|
+
when /[#]/
|
314
|
+
keyword = readwhile( /[?=!tf]/ )
|
315
|
+
case keyword
|
316
|
+
when /[?=]/
|
317
|
+
str = ""
|
318
|
+
T_DEBUG_PRINT
|
319
|
+
when /[!]/
|
320
|
+
readwhile( /[^\r\n]/ )
|
321
|
+
str = ""
|
322
|
+
T_COMMENT
|
323
|
+
when "t"
|
324
|
+
str = "true"
|
325
|
+
T_SYMBOL
|
326
|
+
when "f"
|
327
|
+
str = "false"
|
328
|
+
T_SYMBOL
|
329
|
+
else
|
330
|
+
str += readwhile( /[^ \t\r\n]/ )
|
331
|
+
raise NameError, sprintf( "Error: unknown #xxxx syntax for Nendo %s", str )
|
332
|
+
end
|
283
333
|
when /[_a-zA-Z]/ # symbol
|
284
|
-
str += readwhile( /[_a-zA-Z0-9
|
334
|
+
str += readwhile( /[_a-zA-Z0-9!?*.:-]/ ).gsub( /[-]/, '_' )
|
285
335
|
T_SYMBOL
|
286
336
|
when /[*\/=!<>&|%]/ # symbol
|
287
337
|
str += readwhile( /[+*\/=!<>&|?%-]/ )
|
@@ -301,11 +351,12 @@ class Reader
|
|
301
351
|
str += readwhile( /[0-9.]/ )
|
302
352
|
T_NUM
|
303
353
|
when /["]/ # String
|
304
|
-
str =
|
354
|
+
str = LispString.new( readstring() )
|
355
|
+
readwhile( /["]/ )
|
305
356
|
T_STRING
|
306
357
|
else
|
307
358
|
str += readwhile( /[^ \t\r\n]/ )
|
308
|
-
raise NameError, sprintf( "unknown token for Nendo [%s]", str )
|
359
|
+
raise NameError, sprintf( "Error: unknown token for Nendo [%s]", str )
|
309
360
|
end
|
310
361
|
printf( " token: [%s] : %s (%s:L%d:C%d)\n", str, kind.to_s, @chReader.sourcefile, @chReader.lineno, @chReader.column ) if @debug
|
311
362
|
@curtoken = Token.new( kind, str, @chReader.sourcefile, @chReader.lineno, @chReader.column )
|
@@ -364,6 +415,8 @@ class Reader
|
|
364
415
|
:dot_operator
|
365
416
|
when T_FEEDTO
|
366
417
|
:feedto
|
418
|
+
when T_DEBUG_PRINT
|
419
|
+
"debug-print".intern
|
367
420
|
else
|
368
421
|
raise "Error: Unknown token in atom()"
|
369
422
|
end
|
@@ -396,7 +449,7 @@ class Reader
|
|
396
449
|
token
|
397
450
|
lastAtom = sexp()
|
398
451
|
end
|
399
|
-
when T_QUOTE , T_QUASIQUOTE , T_UNQUOTE , T_UNQUOTE_SPLICING
|
452
|
+
when T_QUOTE , T_QUASIQUOTE , T_UNQUOTE , T_UNQUOTE_SPLICING, T_DEBUG_PRINT
|
400
453
|
cells << Cell.new( sexp() )
|
401
454
|
else
|
402
455
|
if lastAtom
|
@@ -454,6 +507,12 @@ class Reader
|
|
454
507
|
when T_QUOTE , T_QUASIQUOTE , T_UNQUOTE , T_UNQUOTE_SPLICING
|
455
508
|
_atom = atom() ## "quote" symbol
|
456
509
|
Cell.new( _atom, Cell.new( sexp() ))
|
510
|
+
when T_DEBUG_PRINT
|
511
|
+
file = curtoken.sourcefile
|
512
|
+
lineno = curtoken.lineno
|
513
|
+
_atom = atom() ## "debug-print" symbol
|
514
|
+
child = sexp()
|
515
|
+
[_atom, child, LispString.new( file ), lineno, Cell.new( :quote, Cell.new( child )) ].to_list
|
457
516
|
else
|
458
517
|
atom()
|
459
518
|
end
|
@@ -651,6 +710,8 @@ module BuiltinFunctions
|
|
651
710
|
end
|
652
711
|
end
|
653
712
|
def _to_s( arg ) arg.to_s end
|
713
|
+
def _to_i( arg ) arg.to_i end
|
714
|
+
def _nil_QMARK( arg ) arg.nil? end
|
654
715
|
def _to_list( arg )
|
655
716
|
case arg
|
656
717
|
when Array
|
@@ -665,7 +726,10 @@ module BuiltinFunctions
|
|
665
726
|
def _string_join( lst, delim )
|
666
727
|
lst.to_a.map{ |x| x.car }.join( delim )
|
667
728
|
end
|
668
|
-
def _require( arg )
|
729
|
+
def _require( arg )
|
730
|
+
Kernel::require( arg )
|
731
|
+
false
|
732
|
+
end
|
669
733
|
def _read( *args )
|
670
734
|
lst = args[0].to_arr
|
671
735
|
io = if 0 == lst.length
|
@@ -685,6 +749,18 @@ module BuiltinFunctions
|
|
685
749
|
end until s[2]
|
686
750
|
ret
|
687
751
|
end
|
752
|
+
|
753
|
+
def _apply1( first, arg )
|
754
|
+
callProcedure( "(apply1 genereate func)", first, arg )
|
755
|
+
end
|
756
|
+
|
757
|
+
def _global_variables
|
758
|
+
self.instance_variables.select { |x|
|
759
|
+
x.match( /^[@]_[a-zA-Z]/ )
|
760
|
+
}.map{ |name|
|
761
|
+
self.toLispSymbol( name[1..-1] ).intern
|
762
|
+
}.to_list
|
763
|
+
end
|
688
764
|
end
|
689
765
|
|
690
766
|
|
@@ -692,6 +768,7 @@ end
|
|
692
768
|
class Evaluator
|
693
769
|
include BuiltinFunctions
|
694
770
|
def initialize( debug = false )
|
771
|
+
@indent = " "
|
695
772
|
@binding = binding
|
696
773
|
@debug = debug
|
697
774
|
@alias = {'+' => 'plus',
|
@@ -715,7 +792,7 @@ class Evaluator
|
|
715
792
|
|
716
793
|
# initialize global symbols
|
717
794
|
rubyExp = @sym.keys.map { |name|
|
718
|
-
sprintf( "
|
795
|
+
sprintf( "@%s = @sym[ '%s' ] ", name, name )
|
719
796
|
}.join( " ; " )
|
720
797
|
eval( rubyExp, @binding )
|
721
798
|
|
@@ -723,12 +800,15 @@ class Evaluator
|
|
723
800
|
rubyExp = self.methods.select { |x|
|
724
801
|
x.to_s.match( /^_/ )
|
725
802
|
}.map { |name|
|
726
|
-
sprintf( "
|
803
|
+
sprintf( "@%s = self.method( :%s ).to_proc", name, name )
|
727
804
|
}.join( " ; " )
|
728
805
|
eval( rubyExp, @binding )
|
729
806
|
|
730
807
|
# reset gensym counter
|
731
808
|
@gensym_counter = 0
|
809
|
+
|
810
|
+
# compiled ruby code
|
811
|
+
@compiled_code = []
|
732
812
|
end
|
733
813
|
|
734
814
|
def _gensym( )
|
@@ -753,8 +833,8 @@ class Evaluator
|
|
753
833
|
if 0 == name.length
|
754
834
|
""
|
755
835
|
else
|
756
|
-
arr = name.split( /[.]/ )
|
757
|
-
arr[0] = arr[0].gsub( /[*]/, '_AMARK' ).gsub( /[?]/, '_QMARK' ).gsub( /[!]/, '_EMARK' ).gsub( /[-]/, '_' )
|
836
|
+
arr = name.gsub( /["]/, '' ).split( /[.]/ )
|
837
|
+
arr[0] = arr[0].gsub( /[*]/, '_AMARK' ).gsub( /[?]/, '_QMARK' ).gsub( /[!]/, '_EMARK' ).gsub( /[-]/, '_' )
|
758
838
|
if arr[0].match( /^[A-Z]/ )
|
759
839
|
# nothing to do
|
760
840
|
elsif arr[0] == ""
|
@@ -772,26 +852,27 @@ class Evaluator
|
|
772
852
|
|
773
853
|
def toLispSymbol( name )
|
774
854
|
name = name.to_s if Symbol == name.class
|
775
|
-
raise ArgumentError if not ('_' == name[0])
|
855
|
+
raise ArgumentError, sprintf( "Error: `%s' is not a lisp symbol", name ) if not ('_' == name[0])
|
776
856
|
name = name[1..-1]
|
777
857
|
name.gsub( /_AMARK/, '*' ).gsub( /_QMARK/, '?' ).gsub( /_EMARK/, '!' )
|
778
858
|
end
|
779
859
|
|
780
860
|
def toRubyArgument( origname, pred, args )
|
861
|
+
argument_error_message = sprintf( "Error: wrong number of arguments for closure `%s'", origname )
|
781
862
|
num = pred.arity
|
782
863
|
if 0 == num
|
783
|
-
raise ArgumentError,
|
864
|
+
raise ArgumentError, argument_error_message if 0 != args.length
|
784
865
|
[]
|
785
866
|
elsif 0 < num
|
786
867
|
if args.isNull
|
787
868
|
[ Nil.new ]
|
788
869
|
else
|
789
|
-
raise ArgumentError,
|
870
|
+
raise ArgumentError, argument_error_message if num != args.length
|
790
871
|
args.map { |x| x.car }
|
791
872
|
end
|
792
873
|
else
|
793
874
|
num = num.abs( )-1
|
794
|
-
raise ArgumentError,
|
875
|
+
raise ArgumentError, argument_error_message if num > args.length
|
795
876
|
params = []
|
796
877
|
rest = []
|
797
878
|
args.each_with_index { |x,i|
|
@@ -819,130 +900,193 @@ class Evaluator
|
|
819
900
|
pred.call( *rubyArgument )
|
820
901
|
end
|
821
902
|
|
822
|
-
|
903
|
+
# for code generation of Ruby's argument values
|
904
|
+
# in case: str = ","
|
905
|
+
# [1,"2",3] => [
|
906
|
+
# [ 1, ","]
|
907
|
+
# ["2", ","]
|
908
|
+
# [ 3 ]
|
909
|
+
# ]
|
910
|
+
def separateWith( arr, str )
|
911
|
+
seps = []
|
912
|
+
(arr.length-1).times {|n| seps << str }
|
913
|
+
arr.zip( seps ).map{ |x|
|
914
|
+
x.select { |elem| elem }
|
915
|
+
}
|
916
|
+
end
|
917
|
+
|
918
|
+
def execFunc( funcname, args, sourcefile, lineno, locals, lambda_flag )
|
823
919
|
case funcname
|
824
|
-
when :set! # `
|
825
|
-
|
920
|
+
when :define, :set! # `define' special form
|
921
|
+
ar = args.cdr.map { |x| x.car }
|
922
|
+
variable_sym = toRubySymbol( args.car.to_s.sub( /^:/, "" ))
|
923
|
+
global_cap = locals.flatten.include?( variable_sym ) ? nil : "@"
|
924
|
+
[ sprintf( "%s%s = ", global_cap, variable_sym ), ar ]
|
826
925
|
when :error
|
827
926
|
sprintf( 'begin raise RuntimeError, %s ; rescue => __e ; __e.set_backtrace( ["%s:%d"] + __e.backtrace ) ; raise __e ; end ', toRubyValue( args.car ), sourcefile, lineno )
|
828
927
|
else
|
829
928
|
if (not lambda_flag) and isRubyInterface( funcname )
|
830
929
|
# Ruby method
|
831
930
|
# 1) convert arguments
|
832
|
-
|
931
|
+
translatedArr = args.map { |x| x.car }
|
833
932
|
# 2) generate caller code part
|
834
|
-
|
933
|
+
lispSymbolReference( toRubySymbol( funcname ), locals, translatedArr, sourcefile, lineno )
|
835
934
|
else
|
836
935
|
# Nendo function
|
837
|
-
|
838
|
-
|
936
|
+
if 0 == args.length
|
937
|
+
arr = [ "Cell.new(" ]
|
938
|
+
else
|
939
|
+
arr = separateWith( args.map.with_index { |x,i| x.car }, ",Cell.new(" )
|
940
|
+
arr[0].unshift( "Cell.new(" )
|
941
|
+
end
|
839
942
|
if lambda_flag
|
840
|
-
"anonymouse"
|
841
|
-
|
943
|
+
[sprintf( "callProcedure( 'anonymouse', " ),
|
944
|
+
[ funcname ] + [ "," ],
|
945
|
+
arr,
|
946
|
+
sprintf( " )" ) + arr.map { |n| ")" }.join]
|
842
947
|
else
|
843
948
|
origname = funcname.to_s
|
844
949
|
funcname = funcname.to_s
|
845
950
|
funcname = @alias[ funcname ] if @alias[ funcname ]
|
846
|
-
|
951
|
+
sym = toRubySymbol( funcname )
|
952
|
+
[sprintf( "callProcedure( '%s',", origname ),
|
953
|
+
[lispSymbolReference( sym, locals, nil, sourcefile, lineno )] + [","],
|
954
|
+
arr,
|
955
|
+
sprintf( " )" ) + arr.map { |n| ")" }.join]
|
847
956
|
end
|
848
957
|
end
|
849
958
|
end
|
850
959
|
end
|
851
960
|
|
852
|
-
def makeBegin( args )
|
961
|
+
def makeBegin( args, locals )
|
853
962
|
ar = args.map { |e|
|
854
|
-
translate( e.car )
|
963
|
+
translate( e.car, locals )
|
855
964
|
}
|
856
|
-
"begin
|
965
|
+
["begin", ar, "end"]
|
857
966
|
end
|
858
967
|
|
968
|
+
# returns [ argsyms[], string ]
|
859
969
|
def toRubyParameter( argform )
|
860
970
|
argsyms = []
|
971
|
+
locals = []
|
861
972
|
rest = nil
|
862
973
|
if Symbol == argform.class
|
863
974
|
rest = argform
|
864
975
|
else
|
865
976
|
argsyms = argform.map { |x| toRubySymbol( x.car ) }
|
977
|
+
locals = argsyms.clone
|
866
978
|
rest = argform.lastAtom
|
867
979
|
end
|
868
980
|
if rest
|
869
981
|
rest = toRubySymbol( rest )
|
982
|
+
locals << rest
|
870
983
|
argsyms << "*__rest__"
|
871
|
-
sprintf( "|%s| %s = __rest__[0] ; ", argsyms.join( "," ), rest )
|
984
|
+
[ locals, sprintf( "|%s| %s = __rest__[0] ; ", argsyms.join( "," ), rest ) ]
|
872
985
|
else
|
873
|
-
sprintf( "|%s|", argsyms.join( "," ))
|
986
|
+
[ locals, sprintf( "|%s|", argsyms.join( "," )) ]
|
874
987
|
end
|
875
988
|
end
|
876
989
|
|
877
|
-
def makeClosure( sym, args )
|
990
|
+
def makeClosure( sym, args, locals )
|
878
991
|
first = args.car
|
879
992
|
if args.car.car == :quote
|
880
993
|
first = args.car.cdr.car
|
881
994
|
end
|
882
995
|
rest = args.cdr
|
883
|
-
argStr
|
996
|
+
( _locals, argStr ) = toRubyParameter( first )
|
884
997
|
str = case sym
|
885
998
|
when :macro
|
886
999
|
sprintf( "LispMacro.new { %s ", argStr )
|
887
1000
|
when :lambda
|
888
|
-
sprintf( "
|
1001
|
+
sprintf( "Proc.new { %s ", argStr )
|
889
1002
|
else
|
890
1003
|
raise "Error: makeClosure: unknown symbol type " + sym
|
891
1004
|
end
|
892
1005
|
ar = rest.map { |e|
|
893
|
-
translate( e.car )
|
1006
|
+
translate( e.car, locals.clone + [_locals])
|
894
1007
|
}
|
895
|
-
str
|
1008
|
+
[ str, ar, "}" ]
|
896
1009
|
end
|
897
1010
|
|
898
|
-
def makeIf( args )
|
899
|
-
_condition = translate( args.car )
|
900
|
-
_then = translate( args.cdr.car )
|
1011
|
+
def makeIf( args, locals )
|
1012
|
+
_condition = translate( args.car, locals )
|
1013
|
+
_then = translate( args.cdr.car, locals )
|
901
1014
|
_else = nil
|
902
1015
|
if 2 < args.length
|
903
|
-
_else = translate( args.cdr.cdr.car )
|
1016
|
+
_else = translate( args.cdr.cdr.car, locals )
|
904
1017
|
end
|
905
1018
|
if _else
|
906
|
-
|
1019
|
+
["if ( ", _condition, " ) then",
|
1020
|
+
[ _then ],
|
1021
|
+
"else",
|
1022
|
+
[ _else ],
|
1023
|
+
"end"]
|
907
1024
|
else
|
908
|
-
|
1025
|
+
["if ( ", _condition, " ) then",
|
1026
|
+
[ _then ],
|
1027
|
+
"end"]
|
909
1028
|
end
|
910
1029
|
end
|
911
1030
|
|
912
|
-
def makeLet( args )
|
1031
|
+
def makeLet( args, locals )
|
913
1032
|
_name = "___lambda"
|
914
|
-
str = ""
|
915
1033
|
argvals = []
|
1034
|
+
rest = args.cdr
|
916
1035
|
if args.car.is_a? Nil
|
917
1036
|
# nothing to do
|
918
|
-
|
919
|
-
|
1037
|
+
lambda_head = sprintf( "%s = lambda { || ", _name )
|
1038
|
+
else
|
1039
|
+
argsyms = args.car.map { |x|
|
1040
|
+
toRubySymbol( x.car.car.cdr.car.to_s )
|
1041
|
+
}
|
1042
|
+
argvals = args.car.map.with_index { |x,i|
|
1043
|
+
translate( x.car.cdr.car, locals )
|
1044
|
+
}
|
1045
|
+
lambda_head = sprintf( "%s = lambda { |%s| ", _name, argsyms.join( "," ))
|
1046
|
+
end
|
1047
|
+
["begin",
|
1048
|
+
[lambda_head,
|
1049
|
+
rest.map { |e| translate( e.car, locals.clone + [argsyms] ) },
|
1050
|
+
sprintf( "} ; %s.call(", _name ),
|
1051
|
+
separateWith( argvals, "," ),
|
1052
|
+
sprintf( " )")],
|
1053
|
+
"end"]
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
def makeLetrec( args, locals )
|
1057
|
+
_name = "___lambda"
|
1058
|
+
argvals = []
|
1059
|
+
argsyms = []
|
1060
|
+
rest = args.cdr
|
1061
|
+
if args.car.is_a? Nil
|
1062
|
+
# nothing to do
|
1063
|
+
lambda_head = sprintf( "%s = lambda { || ", _name )
|
920
1064
|
else
|
921
|
-
if :quote == args.car.car
|
922
|
-
_name = args.car.cdr.car.to_s
|
923
|
-
args = args.cdr
|
924
|
-
end
|
925
|
-
rest = args.cdr
|
926
1065
|
argsyms = args.car.map { |x|
|
927
1066
|
toRubySymbol( x.car.car.cdr.car.to_s )
|
928
1067
|
}
|
929
1068
|
argvals = args.car.map { |x|
|
930
|
-
translate( x.car.cdr.car )
|
1069
|
+
translate( x.car.cdr.car, locals.clone + [argsyms] )
|
931
1070
|
}
|
932
|
-
|
1071
|
+
lambda_head = sprintf( "%s = lambda { |%s| ", _name, argsyms.join( "," ))
|
933
1072
|
end
|
934
|
-
|
935
|
-
|
936
|
-
|
1073
|
+
["begin",
|
1074
|
+
[lambda_head,
|
1075
|
+
argsyms.zip( argvals ).map { |x| [ x[0], " = ", x[1] ] },
|
1076
|
+
rest.map { |e| translate( e.car, locals.clone + [argsyms] ) },
|
1077
|
+
sprintf( "} ; %s.call(", _name ),
|
1078
|
+
argsyms.map { |x| "nil" }.join( "," ),
|
1079
|
+
sprintf( " )")],
|
1080
|
+
"end"]
|
937
1081
|
end
|
938
1082
|
|
939
|
-
def apply( car, cdr, sourcefile, lineno, lambda_flag = false )
|
1083
|
+
def apply( car, cdr, sourcefile, lineno, locals, lambda_flag = false )
|
940
1084
|
cdr.each { |x|
|
941
1085
|
if Cell == x.class
|
942
|
-
x.car = translate( x.car )
|
1086
|
+
x.car = translate( x.car, locals )
|
943
1087
|
end
|
944
1088
|
}
|
945
|
-
execFunc( car, cdr, sourcefile, lineno, lambda_flag )
|
1089
|
+
execFunc( car, cdr, sourcefile, lineno, locals, lambda_flag )
|
946
1090
|
end
|
947
1091
|
|
948
1092
|
def genQuote( sexp, str = "" )
|
@@ -954,7 +1098,7 @@ class Evaluator
|
|
954
1098
|
else
|
955
1099
|
arr = sexp.map { |x| genQuote( x.car ) }
|
956
1100
|
str += "Cell.new("
|
957
|
-
str += arr.join( "
|
1101
|
+
str += arr.join( ",Cell.new(" )
|
958
1102
|
lastAtom = sexp.lastAtom
|
959
1103
|
str += "," + genQuote( lastAtom ) if lastAtom
|
960
1104
|
str += arr.map{ |e| ")" }.join
|
@@ -962,7 +1106,7 @@ class Evaluator
|
|
962
1106
|
when Symbol
|
963
1107
|
str += sprintf( ":\"%s\"", sexp.to_s )
|
964
1108
|
when String
|
965
|
-
str += sprintf( "\"%s\"", sexp )
|
1109
|
+
str += sprintf( "\"%s\"", LispString.escape( sexp ))
|
966
1110
|
when TrueClass, FalseClass, NilClass # reserved symbols
|
967
1111
|
str += toRubyValue( sexp )
|
968
1112
|
else
|
@@ -971,35 +1115,72 @@ class Evaluator
|
|
971
1115
|
str
|
972
1116
|
end
|
973
1117
|
|
974
|
-
def
|
975
|
-
|
1118
|
+
def lispSymbolReference( sym, locals, translatedArr, sourcefile, lineno )
|
1119
|
+
variable_sym = sym.split( /[.]/ )[0]
|
1120
|
+
global_cap = if variable_sym.match( /^[A-Z]/ )
|
1121
|
+
nil
|
1122
|
+
else
|
1123
|
+
locals.flatten.include?( variable_sym ) ? nil : "@"
|
1124
|
+
end
|
1125
|
+
expression = if translatedArr
|
1126
|
+
[sprintf( "%s%s(", global_cap, sym ),
|
1127
|
+
separateWith( translatedArr, "," ),
|
1128
|
+
sprintf( " )" )]
|
1129
|
+
else
|
1130
|
+
[sprintf( "%s%s", global_cap, sym )]
|
1131
|
+
end
|
1132
|
+
if global_cap
|
1133
|
+
["begin",
|
1134
|
+
[sprintf( 'if (self.instance_variables.include?(:@%s)) then', variable_sym ),
|
1135
|
+
expression,
|
1136
|
+
sprintf( 'else raise NameError.new( "Error: undefined variable %s", "%s" ) end', variable_sym, variable_sym ),
|
1137
|
+
sprintf( 'rescue => __e ; __e.set_backtrace( ["%s:%d"] + __e.backtrace ) ; raise __e', sourcefile, lineno )],
|
1138
|
+
"end"]
|
1139
|
+
else
|
1140
|
+
["begin",
|
1141
|
+
[expression,
|
1142
|
+
sprintf( 'rescue => __e ; __e.set_backtrace( ["%s:%d"] + __e.backtrace ) ; raise __e', sourcefile, lineno )],
|
1143
|
+
"end"]
|
1144
|
+
end
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
# Lisp->Ruby translater
|
1148
|
+
# - locals is array of closure's local variable list
|
1149
|
+
# when S-expression is
|
1150
|
+
# (let ((a 1)
|
1151
|
+
# (b 2))
|
1152
|
+
# (let ((c 3))
|
1153
|
+
# (print (+ a b c))))
|
1154
|
+
# => locals must be [["_a" "_b"]["_c"]] value.
|
1155
|
+
def translate( sexp, locals )
|
976
1156
|
case sexp
|
977
1157
|
when Cell
|
978
1158
|
if :quote == sexp.car
|
979
1159
|
genQuote( sexp.cdr.car )
|
980
1160
|
elsif sexp.isDotted
|
981
|
-
|
982
|
-
raise NameError
|
1161
|
+
raise NameError, "Error: can't eval dotted pair."
|
983
1162
|
elsif sexp.isNull
|
984
|
-
|
1163
|
+
[ "Cell.new()" ]
|
985
1164
|
elsif Cell == sexp.car.class
|
986
1165
|
if :lambda == sexp.car.car
|
987
|
-
|
1166
|
+
self.apply( translate( sexp.car, locals ), sexp.cdr, sexp.car.car.sourcefile, sexp.car.car.lineno, locals, true )
|
988
1167
|
else
|
989
|
-
|
1168
|
+
translate( sexp.car, locals )
|
990
1169
|
end
|
991
1170
|
elsif :begin == sexp.car
|
992
|
-
|
1171
|
+
self.makeBegin( sexp.cdr, locals )
|
993
1172
|
elsif :lambda == sexp.car
|
994
|
-
|
1173
|
+
self.makeClosure( :lambda, sexp.cdr, locals )
|
995
1174
|
elsif :macro == sexp.car
|
996
|
-
|
1175
|
+
self.makeClosure( :macro, sexp.cdr, locals )
|
997
1176
|
elsif :if == sexp.car
|
998
|
-
|
1177
|
+
self.makeIf( sexp.cdr, locals )
|
999
1178
|
elsif :let == sexp.car
|
1000
|
-
|
1179
|
+
self.makeLet( sexp.cdr, locals )
|
1180
|
+
elsif :letrec == sexp.car
|
1181
|
+
self.makeLetrec( sexp.cdr, locals )
|
1001
1182
|
else
|
1002
|
-
|
1183
|
+
self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals )
|
1003
1184
|
end
|
1004
1185
|
else
|
1005
1186
|
case sexp
|
@@ -1007,17 +1188,17 @@ class Evaluator
|
|
1007
1188
|
sym = sexp.to_s
|
1008
1189
|
sym = @alias[ sym ] if @alias[ sym ]
|
1009
1190
|
sym = toRubySymbol( sym )
|
1010
|
-
|
1191
|
+
lispSymbolReference( sym, locals, nil, sexp.sourcefile, sexp.lineno )
|
1011
1192
|
when Fixnum
|
1012
|
-
|
1013
|
-
when
|
1014
|
-
|
1193
|
+
sexp.to_s
|
1194
|
+
when String
|
1195
|
+
sprintf( "\"%s\"", LispString.escape( sexp ))
|
1015
1196
|
when Nil
|
1016
|
-
|
1197
|
+
"Nil.new"
|
1017
1198
|
when TrueClass, FalseClass, NilClass # reserved symbols
|
1018
|
-
|
1199
|
+
toRubyValue( sexp )
|
1019
1200
|
else
|
1020
|
-
|
1201
|
+
sexp.to_s
|
1021
1202
|
end
|
1022
1203
|
end
|
1023
1204
|
end
|
@@ -1043,19 +1224,33 @@ class Evaluator
|
|
1043
1224
|
when Cell
|
1044
1225
|
if :quote == sexp.car or :quasiquote == sexp.car
|
1045
1226
|
sexp
|
1046
|
-
elsif :set! == sexp.car or :lambda == sexp.car or :macro == sexp.car
|
1227
|
+
elsif :define == sexp.car or :set! == sexp.car or :lambda == sexp.car or :macro == sexp.car
|
1047
1228
|
sexp.cdr.car = Cell.new( :quote, Cell.new( sexp.cdr.car ))
|
1048
1229
|
sexp.cdr.cdr = quoting( sexp.cdr.cdr )
|
1049
1230
|
sexp
|
1050
1231
|
elsif :let == sexp.car
|
1232
|
+
if _null_QMARK( sexp.cdr )
|
1233
|
+
# do nothing
|
1234
|
+
p "kiyoka1"
|
1235
|
+
else
|
1236
|
+
case sexp.cdr.car
|
1237
|
+
when Cell # let
|
1238
|
+
sexp.cdr = Cell.new( letArgumentList( sexp.cdr.car ),
|
1239
|
+
quoting( sexp.cdr.cdr ))
|
1240
|
+
when Symbol # named let
|
1241
|
+
sexp.cdr.car = Cell.new( :quote, Cell.new( sexp.cdr.car ))
|
1242
|
+
sexp.cdr.cdr = Cell.new( letArgumentList( sexp.cdr.cdr.car ),
|
1243
|
+
quoting( sexp.cdr.cdr.cdr ))
|
1244
|
+
end
|
1245
|
+
end
|
1246
|
+
sexp
|
1247
|
+
elsif :letrec == sexp.car
|
1051
1248
|
case sexp.cdr.car
|
1052
|
-
when Cell #
|
1249
|
+
when Cell # letrec
|
1053
1250
|
sexp.cdr = Cell.new( letArgumentList( sexp.cdr.car ),
|
1054
|
-
|
1055
|
-
when Symbol # named
|
1056
|
-
|
1057
|
-
sexp.cdr.cdr = Cell.new( letArgumentList( sexp.cdr.cdr.car ),
|
1058
|
-
quoting( sexp.cdr.cdr.cdr ))
|
1251
|
+
quoting( sexp.cdr.cdr ))
|
1252
|
+
when Symbol # named letrec is illegal
|
1253
|
+
raise SyntaxError, "Error: named letrec is not a illegal form"
|
1059
1254
|
end
|
1060
1255
|
sexp
|
1061
1256
|
else
|
@@ -1066,7 +1261,19 @@ class Evaluator
|
|
1066
1261
|
end
|
1067
1262
|
end
|
1068
1263
|
|
1069
|
-
def
|
1264
|
+
def macroexpand_1_check( sexp )
|
1265
|
+
if not @expand_flag
|
1266
|
+
sexp
|
1267
|
+
else
|
1268
|
+
newSexp = macroexpand_1_sub( sexp )
|
1269
|
+
if not _equal_QMARK( newSexp, sexp )
|
1270
|
+
@expand_flag = false
|
1271
|
+
end
|
1272
|
+
newSexp
|
1273
|
+
end
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
def macroexpand_1_sub( sexp )
|
1070
1277
|
case sexp
|
1071
1278
|
when Cell
|
1072
1279
|
if :quote == sexp.car
|
@@ -1075,22 +1282,35 @@ class Evaluator
|
|
1075
1282
|
sym = sexp.car.to_s
|
1076
1283
|
sym = @alias[ sym ] if @alias[ sym ]
|
1077
1284
|
sym = toRubySymbol( sym )
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
elsif sexp.car.class == Symbol and eval( sprintf( "(defined?
|
1082
|
-
eval( sprintf( "@
|
1083
|
-
callProcedure( sym, @
|
1285
|
+
newSexp = sexp
|
1286
|
+
if isRubyInterface( sym )
|
1287
|
+
# do nothing
|
1288
|
+
elsif sexp.car.class == Symbol and eval( sprintf( "(defined? @%s and LispMacro == @%s.class)", sym,sym ), @binding )
|
1289
|
+
eval( sprintf( "@__macro = @%s", sym ), @binding )
|
1290
|
+
newSexp = callProcedure( sym, @__macro, sexp.cdr )
|
1291
|
+
end
|
1292
|
+
if _equal_QMARK( newSexp, sexp )
|
1293
|
+
sexp.map { |x|
|
1294
|
+
if x.car.is_a? Cell
|
1295
|
+
macroexpand_1_check( x.car )
|
1296
|
+
else
|
1297
|
+
x.car
|
1298
|
+
end
|
1299
|
+
}.to_list( sexp.lastAtom )
|
1084
1300
|
else
|
1085
|
-
|
1086
|
-
arr.to_list( sexp.lastAtom )
|
1301
|
+
newSexp
|
1087
1302
|
end
|
1088
1303
|
end
|
1089
1304
|
else
|
1090
1305
|
sexp
|
1091
1306
|
end
|
1092
1307
|
end
|
1093
|
-
|
1308
|
+
|
1309
|
+
def macroexpand_1( sexp )
|
1310
|
+
@expand_flag = true
|
1311
|
+
macroexpand_1_check( sexp )
|
1312
|
+
end
|
1313
|
+
|
1094
1314
|
def lispCompile( sexp )
|
1095
1315
|
converge = true
|
1096
1316
|
begin
|
@@ -1100,6 +1320,22 @@ class Evaluator
|
|
1100
1320
|
end until converge
|
1101
1321
|
sexp
|
1102
1322
|
end
|
1323
|
+
|
1324
|
+
def ppRubyExp( level, exp )
|
1325
|
+
indent = @indent * level
|
1326
|
+
exp.map { |x|
|
1327
|
+
if Array == x.class
|
1328
|
+
ppRubyExp( level+1, x )
|
1329
|
+
else
|
1330
|
+
str = sprintf( "%s", x )
|
1331
|
+
if str.match( /^[,]/ ) or str.match( /^ = / )
|
1332
|
+
sprintf( "%s%s", indent, str )
|
1333
|
+
else
|
1334
|
+
sprintf( "\n%s%s", indent, str )
|
1335
|
+
end
|
1336
|
+
end
|
1337
|
+
}
|
1338
|
+
end
|
1103
1339
|
|
1104
1340
|
def lispEval( sexp, sourcefile, lineno )
|
1105
1341
|
sexp = lispCompile( sexp )
|
@@ -1107,8 +1343,10 @@ class Evaluator
|
|
1107
1343
|
if @debug
|
1108
1344
|
printf( "\n quoting=<<< %s >>>\n", (Printer.new())._print(sexp))
|
1109
1345
|
end
|
1110
|
-
|
1111
|
-
|
1346
|
+
arr = [ translate( sexp, [] ) ]
|
1347
|
+
rubyExp = ppRubyExp( 0, arr ).flatten.join
|
1348
|
+
@compiled_code << rubyExp
|
1349
|
+
printf( " rubyExp=<<<\n%s\n>>>\n", rubyExp ) if @debug
|
1112
1350
|
eval( rubyExp, @binding, sourcefile, lineno );
|
1113
1351
|
end
|
1114
1352
|
|
@@ -1129,13 +1367,27 @@ class Evaluator
|
|
1129
1367
|
}
|
1130
1368
|
end
|
1131
1369
|
|
1370
|
+
def _loadCompiledCode( filename )
|
1371
|
+
open( filename ) { |f|
|
1372
|
+
rubyExp = f.read
|
1373
|
+
eval( rubyExp, @binding )
|
1374
|
+
}
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
def _get_compiled_code()
|
1378
|
+
@compiled_code.to_list
|
1379
|
+
end
|
1380
|
+
|
1132
1381
|
def _eval( sexp )
|
1133
1382
|
self.lispEval( sexp, "dynamic S-expression ( no source )", 1 )
|
1134
1383
|
end
|
1135
1384
|
|
1136
|
-
def
|
1385
|
+
def _enable_idebug()
|
1137
1386
|
@debug = true
|
1138
1387
|
end
|
1388
|
+
def _disable_idebug()
|
1389
|
+
@debug = false
|
1390
|
+
end
|
1139
1391
|
end
|
1140
1392
|
|
1141
1393
|
class Printer
|
@@ -1180,7 +1432,7 @@ class Printer
|
|
1180
1432
|
end
|
1181
1433
|
when String
|
1182
1434
|
if readable
|
1183
|
-
sprintf( "\"%s\"", sexp.to_s )
|
1435
|
+
sprintf( "\"%s\"", LispString.escape( sexp.to_s ))
|
1184
1436
|
else
|
1185
1437
|
sexp.to_s
|
1186
1438
|
end
|
@@ -1209,8 +1461,18 @@ class Nendo
|
|
1209
1461
|
@debug_printer = debug_printer
|
1210
1462
|
end
|
1211
1463
|
|
1212
|
-
def loadInitFile
|
1213
|
-
|
1464
|
+
def loadInitFile( use_compiled = true )
|
1465
|
+
done = false
|
1466
|
+
if use_compiled
|
1467
|
+
compiled_file = File.dirname(__FILE__) + "/init.nndc"
|
1468
|
+
if File.exist?( compiled_file )
|
1469
|
+
@evaluator._loadCompiledCode( compiled_file )
|
1470
|
+
done = true
|
1471
|
+
end
|
1472
|
+
end
|
1473
|
+
unless done
|
1474
|
+
@evaluator._load( File.dirname(__FILE__) + "/init.nnd" )
|
1475
|
+
end
|
1214
1476
|
end
|
1215
1477
|
|
1216
1478
|
def load( path )
|
@@ -1238,8 +1500,8 @@ class Nendo
|
|
1238
1500
|
if s[1] # EOF?
|
1239
1501
|
break
|
1240
1502
|
elsif Nil != s[0].class
|
1241
|
-
printf( "\n readExp=<<< %s >>>\n", printer.
|
1242
|
-
print printer.
|
1503
|
+
printf( "\n readExp=<<< %s >>>\n", printer._write(s[0]) ) if @debug_evaluator
|
1504
|
+
print printer._write( @evaluator.lispEval( s[0], reader.sourcefile, lineno ))
|
1243
1505
|
print "\n" + "nendo> "
|
1244
1506
|
end
|
1245
1507
|
rescue => e
|
@@ -1261,8 +1523,8 @@ class Nendo
|
|
1261
1523
|
if s[1] # EOF?
|
1262
1524
|
break
|
1263
1525
|
elsif Nil != s[0].class
|
1264
|
-
printf( "\n readExp=<<< %s >>>\n", printer.
|
1265
|
-
result = printer.
|
1526
|
+
printf( "\n readExp=<<< %s >>>\n", printer._write(s[0]) ) if @debug_evaluator
|
1527
|
+
result = printer._write( @evaluator.lispEval( s[0], reader.sourcefile, lineno ))
|
1266
1528
|
end
|
1267
1529
|
end
|
1268
1530
|
result
|