nendo 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|