nendo 0.3.1 → 0.3.2

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
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # nendo.rb - "language core of nendo"
5
5
  #
6
- # Copyright (c) 2000-2010 Kiyoka Nishiyama <kiyoka@sumibi.org>
6
+ # Copyright (c) 2009-2010 Kiyoka Nishiyama <kiyoka@sumibi.org>
7
7
  #
8
8
  # Redistribution and use in source and binary forms, with or without
9
9
  # modification, are permitted provided that the following conditions
@@ -35,6 +35,7 @@
35
35
  # $Id:
36
36
  #
37
37
  require 'stringio'
38
+ require 'digest/sha1'
38
39
  #require 'profile'
39
40
 
40
41
  class Nil
@@ -57,7 +58,7 @@ end
57
58
  class LispString < String
58
59
  def LispString.escape( str )
59
60
  if str.is_a? String
60
- str.gsub( /["]/, "\\\"" )
61
+ str.gsub( /\\/, "\\\\\\\\" ).gsub( /["]/, "\\\"" ).gsub( /[\r]/, "\\r" ).gsub( /[\t]/, "\\t" )
61
62
  else
62
63
  raise TypeError
63
64
  end
@@ -262,6 +263,7 @@ class Reader
262
263
  T_EOF = :t_eof
263
264
  T_LPAREN = :t_lparen
264
265
  T_RPAREN = :t_rparen
266
+ T_LVECTOR = :t_lvector
265
267
  T_SYMBOL = :t_symbol
266
268
  T_KEYWORD = :t_keyword
267
269
  T_NUM = :t_num
@@ -304,7 +306,7 @@ class Reader
304
306
  @chReader.ungetc( ch ) if nil != ch
305
307
  end
306
308
 
307
- def readwhile( exp )
309
+ def readwhile( exp, oneshot = false )
308
310
  ret = ""
309
311
  while true
310
312
  ch = @chReader.getc
@@ -318,10 +320,25 @@ class Reader
318
320
  @chReader.ungetc( ch )
319
321
  break
320
322
  end
323
+ if oneshot then break end
321
324
  end
322
325
  ret
323
326
  end
324
327
 
328
+ def peekchar( exp )
329
+ ch = @chReader.getc
330
+ #printf( " peekchar: [%02x]\n", ch ) if @debug
331
+ if !ch # eof?
332
+ return nil
333
+ end
334
+ if ch.chr.match( exp )
335
+ ch.chr
336
+ else
337
+ @chReader.ungetc( ch )
338
+ nil
339
+ end
340
+ end
341
+
325
342
  def readstring()
326
343
  ret = ""
327
344
  while true
@@ -330,15 +347,23 @@ class Reader
330
347
  if !ch # eof?
331
348
  break
332
349
  end
333
- if ch.chr.match( /[\\]/ )
350
+ if ch.chr == "\\"
334
351
  ch2 = @chReader.getc
335
- if ch2.chr == "\"" # \" reduce to "
336
- ret += "\""
337
- else
338
- ret += ch.chr
339
- ret += ch2.chr
340
- end
341
- elsif ch.chr.match( /[^"]/ )
352
+ ret += case ch2.chr
353
+ when '"' # \" reduce to "
354
+ '"'
355
+ when '\\' # \\ reduce to \
356
+ "\\"
357
+ when 'n'
358
+ "\n"
359
+ when 'r'
360
+ "\r"
361
+ when 't'
362
+ "\t"
363
+ else
364
+ ""
365
+ end
366
+ elsif ch.chr != '"'
342
367
  ret += ch.chr
343
368
  else
344
369
  @chReader.ungetc( ch )
@@ -362,7 +387,7 @@ class Reader
362
387
  when /[\`]/
363
388
  T_QUASIQUOTE
364
389
  when /[,]/
365
- str += readwhile( /[@]/ )
390
+ str += readwhile( /[@]/, true )
366
391
  if 1 == str.length
367
392
  T_UNQUOTE
368
393
  else
@@ -386,28 +411,62 @@ class Reader
386
411
  str = ""
387
412
  T_COMMENT
388
413
  when /[#]/
389
- keyword = readwhile( /[?=!]/ )
390
- case keyword
391
- when /[?=]/
392
- str = ""
393
- T_DEBUG_PRINT
394
- when /[!]/
395
- readwhile( /[^\r\n]/ )
396
- str = ""
397
- T_COMMENT
398
- else
399
- keyword = readwhile( /[a-z]/ )
400
- case keyword
401
- when "t"
402
- str = "true"
403
- T_SYMBOL
404
- when "f"
405
- str = "false"
406
- T_SYMBOL
414
+ nextch = peekchar( /[?!tfbodx(]/ )
415
+ case nextch
416
+ when "?"
417
+ if peekchar( /[=]/ )
418
+ str = ""
419
+ T_DEBUG_PRINT
407
420
  else
408
421
  str += readwhile( /[^ \t\r\n]/ )
409
422
  raise NameError, sprintf( "Error: unknown #xxxx syntax for Nendo %s", str )
423
+ end
424
+ when "!"
425
+ readwhile( /[^\r\n]/ )
426
+ str = ""
427
+ T_COMMENT
428
+ when "("
429
+ str = ""
430
+ T_LVECTOR
431
+ when "t"
432
+ str = "true"
433
+ T_SYMBOL
434
+ when "f"
435
+ str = "false"
436
+ T_SYMBOL
437
+ when "b","o","d","x"
438
+ str = readwhile( /[0-9a-zA-Z]/ )
439
+ case nextch
440
+ when "b"
441
+ if str.match( /^[0-1]+$/ )
442
+ str = "0b" + str
443
+ else
444
+ raise RuntimeError, sprintf( "Error: illegal #b number for Nendo #b%s", str )
445
+ end
446
+ when "o"
447
+ if str.match( /^[0-7]+$/ )
448
+ str = "0o" + str
449
+ else
450
+ raise RuntimeError, sprintf( "Error: illegal #o number for Nendo #o%s", str )
451
+ end
452
+ when "d"
453
+ if str.match( /^[0-9]+$/ )
454
+ str = "0d" + str
455
+ else
456
+ raise RuntimeError, sprintf( "Error: illegal #d number for Nendo #d%s", str )
457
+ end
458
+ when "x"
459
+ if str.match( /^[0-9a-fA-F]+$/ )
460
+ str = "0x" + str
461
+ else
462
+ raise RuntimeError, sprintf( "Error: illegal #x number for Nendo #x%s", str )
463
+ end
410
464
  end
465
+ str = Integer( str ).to_s
466
+ T_NUM
467
+ else
468
+ str += readwhile( /[^ \t\r\n]/ )
469
+ raise NameError, sprintf( "Error: unknown #xxxx syntax for Nendo %s", str )
411
470
  end
412
471
  when /[_a-zA-Z!$%&*+\/:<=>?@^~-]/ # symbol
413
472
  str += readwhile( /[0-9._a-zA-Z!$%&*+\/:<=>?@^~-]/ )
@@ -421,7 +480,7 @@ class Reader
421
480
  else
422
481
  T_SYMBOL
423
482
  end
424
- when /[0-9]/ # number
483
+ when /[0-9]/ # Numeric
425
484
  str += readwhile( /[0-9.]/ )
426
485
  T_NUM
427
486
  when /["]/ # String
@@ -498,6 +557,32 @@ class Reader
498
557
  end
499
558
  end
500
559
 
560
+ # vector := sexp
561
+ # | atom ... atom
562
+ def vector
563
+ printf( " NonT: [%s]\n", "vector" ) if @debug
564
+ arr = []
565
+ while true
566
+ case curtoken.kind
567
+ when T_LINEFEED
568
+ token # skipEnter
569
+ when T_EOF
570
+ raise RuntimeError, "Error: unbalanced vector's paren(4)"
571
+ when T_LPAREN, T_LVECTOR
572
+ arr << sexp()
573
+ when T_RPAREN
574
+ break
575
+ when T_QUOTE , T_QUASIQUOTE , T_UNQUOTE , T_UNQUOTE_SPLICING, T_DEBUG_PRINT
576
+ arr << sexp()
577
+ when T_DOT
578
+ raise RuntimeError, "Error: illegal list."
579
+ else
580
+ arr << atom()
581
+ end
582
+ end
583
+ arr
584
+ end
585
+
501
586
  # list := sexp
502
587
  # | atom ... atom
503
588
  # | atom ... . atom
@@ -511,8 +596,8 @@ class Reader
511
596
  when T_LINEFEED
512
597
  token # skipEnter
513
598
  when T_EOF
514
- raise SyntaxError, "Error: unbalanced paren(1)"
515
- when T_LPAREN
599
+ raise RuntimeError, "Error: unbalanced paren(1)"
600
+ when T_LPAREN, T_LVECTOR
516
601
  cells << Cell.new( sexp() )
517
602
  when T_RPAREN
518
603
  break
@@ -565,7 +650,7 @@ class Reader
565
650
  end
566
651
  end
567
652
 
568
- # sexp := ( list ) | 'sexp | `sexp | atom
653
+ # sexp := ( list ) | | #( vector ) | 'sexp | `sexp | atom
569
654
  def sexp
570
655
  printf( " NonT: [%s]\n", "sexp" ) if @debug
571
656
  case curtoken.kind
@@ -573,7 +658,7 @@ class Reader
573
658
  token
574
659
  sexp()
575
660
  when T_EOF
576
- raise SyntaxError, "Error: unbalanced paren(2)"
661
+ raise RuntimeError, "Error: unbalanced paren(2)"
577
662
  when T_LPAREN
578
663
  skipEnter
579
664
  token # consume '('
@@ -582,7 +667,14 @@ class Reader
582
667
  token # consume ')'
583
668
  ret
584
669
  when T_RPAREN
585
- raise SyntaxError, "Error: unbalanced paren(3)"
670
+ raise RuntimeError, "Error: unbalanced paren(3)"
671
+ when T_LVECTOR
672
+ skipEnter
673
+ token # consume '#('
674
+ ret = vector()
675
+ skipEnter
676
+ token # consume ')'
677
+ ret
586
678
  when T_QUOTE , T_QUASIQUOTE , T_UNQUOTE , T_UNQUOTE_SPLICING
587
679
  _atom = atom() ## "quote" symbol
588
680
  Cell.new( _atom, Cell.new( sexp() ))
@@ -825,7 +917,7 @@ module BuiltinFunctions
825
917
  (Cell == arg.class)
826
918
  end
827
919
  end
828
- def _number_QUMARK( arg ) ((Fixnum == arg.class) or (Float == arg.class)) end
920
+ def _number_QUMARK( arg ) arg.is_a? Numeric end
829
921
  def _string_QUMARK( arg ) String == arg.class end
830
922
  def _macroexpand_MIMARK1( arg )
831
923
  if _pair_QUMARK( arg )
@@ -850,11 +942,31 @@ module BuiltinFunctions
850
942
  raise TypeError
851
943
  end
852
944
  end
945
+ def _to_arr( arg ) _to_MIMARKarr( arg ) end
946
+ def _to_MIMARKarr( arg )
947
+ case arg
948
+ when Cell
949
+ arg.to_arr
950
+ when Array
951
+ arg
952
+ else
953
+ raise TypeError
954
+ end
955
+ end
853
956
  def _intern( arg ) arg.intern end
854
957
  def _string_MIMARK_GTMARKsymbol( arg ) arg.intern end
855
958
  def _symbol_MIMARK_GTMARKstring( arg ) arg.to_s end
856
- def _string_MIMARKjoin( lst, delim )
857
- lst.to_a.map{ |x| x.car }.join( delim )
959
+ def _string_MIMARKjoin( lst, *args )
960
+ arr = args[0].to_arr
961
+ if 0 < arr.length
962
+ if not arr[0].is_a? String
963
+ raise TypeError, "Error string-join's expects delimitter as String."
964
+ else
965
+ lst.to_a.map{ |x| x.car }.join( arr[0] )
966
+ end
967
+ else
968
+ lst.to_a.map{ |x| x.car }.join
969
+ end
858
970
  end
859
971
  def _require( arg )
860
972
  Kernel::require( arg )
@@ -967,8 +1079,17 @@ module BuiltinFunctions
967
1079
  def __ASMARKFILE_ASMARK()
968
1080
  @lastSourcefile
969
1081
  end
970
- end
971
1082
 
1083
+ def _vector_MIMARKset_EXMARK( v, index, value )
1084
+ if !(v.is_a? Array)
1085
+ raise TypeError, "Error: vector-set! requires Array as argument v(Lisp's vector).\n"
1086
+ end
1087
+ if (index < 0) or (v.size <= index)
1088
+ raise ArgumentError, "Error: vector-set! requires index between 0 and (size-1) number.\n"
1089
+ end
1090
+ v[index] = value
1091
+ end
1092
+ end
972
1093
 
973
1094
 
974
1095
  # Translate S expression to Ruby expression and Evaluation
@@ -1006,9 +1127,7 @@ class Evaluator
1006
1127
 
1007
1128
  # built-in functions
1008
1129
  self.methods.grep( /^_/ ) { |rubySymbol|
1009
- @___tmp = self.method( rubySymbol )
1010
- eval( sprintf( "@%s = @___tmp;", rubySymbol ), @binding )
1011
- eval( sprintf( "@global_lisp_binding['%s'] = true;", rubySymbol ), @binding )
1130
+ global_lisp_define( rubySymbol, self.method( rubySymbol ))
1012
1131
  }
1013
1132
 
1014
1133
  # initialize buildin functions as Proc objects
@@ -1028,9 +1147,24 @@ class Evaluator
1028
1147
  @compiled_code = Hash.new
1029
1148
  end
1030
1149
 
1150
+ def global_lisp_define( rubySymbol, val )
1151
+ @___tmp = val
1152
+ eval( sprintf( "@%s = @___tmp;", rubySymbol ), @binding )
1153
+ eval( sprintf( "@global_lisp_binding['%s'] = true;", rubySymbol ), @binding )
1154
+ end
1155
+
1156
+ def setArgv( argv )
1157
+ self.global_lisp_define( toRubySymbol( "*argv*"), argv.to_list )
1158
+ end
1159
+
1031
1160
  def _gensym( )
1032
1161
  @gensym_counter += 1
1033
- sprintf( "__gensym__%d", @gensym_counter ).intern
1162
+ filename = if @lastSourcefile.is_a? String
1163
+ Digest::SHA1.hexdigest( @lastSourcefile )
1164
+ else
1165
+ ""
1166
+ end
1167
+ sprintf( "__gensym__%s_%d", filename, @gensym_counter ).intern
1034
1168
  end
1035
1169
 
1036
1170
  def forward_gensym_counter( )
@@ -1342,9 +1476,12 @@ class Evaluator
1342
1476
  str += "," + genQuote( lastAtom ) if lastAtom
1343
1477
  str += arr.map{ |e| ")" }.join
1344
1478
  end
1479
+ when Array
1480
+ arr = sexp.map { |x| genQuote( x ) }
1481
+ str += "[" + arr.join(",") + "]"
1345
1482
  when Symbol
1346
1483
  str += sprintf( ":\"%s\"", sexp.to_s )
1347
- when String
1484
+ when String, LispString
1348
1485
  str += sprintf( "\"%s\"", LispString.escape( sexp ))
1349
1486
  when LispKeyword
1350
1487
  str += sprintf( "LispKeyword.new( \"%s\" )", sexp.key.to_s )
@@ -1419,6 +1556,8 @@ class Evaluator
1419
1556
  else
1420
1557
  self.apply( sexp.car, sexp.cdr, sexp.car.sourcefile, sexp.car.lineno, locals )
1421
1558
  end
1559
+ when Array
1560
+ raise RuntimeError, "Error: can't eval unquoted vector."
1422
1561
  else
1423
1562
  case sexp
1424
1563
  when Symbol
@@ -1427,7 +1566,7 @@ class Evaluator
1427
1566
  lispSymbolReference( sym, locals, nil, sexp.sourcefile, sexp.lineno )
1428
1567
  when Fixnum
1429
1568
  sexp.to_s
1430
- when String
1569
+ when String, LispString
1431
1570
  sprintf( "\"%s\"", LispString.escape( sexp ))
1432
1571
  when LispKeyword
1433
1572
  sprintf( "LispKeyword.new( \"%s\" )", sexp.key )
@@ -1488,7 +1627,7 @@ class Evaluator
1488
1627
  sexp.cdr = Cell.new( letArgumentList( sexp.cdr.car ),
1489
1628
  quoting( sexp.cdr.cdr ))
1490
1629
  when Symbol # named letrec is illegal
1491
- raise SyntaxError, "Error: named letrec is not a illegal form"
1630
+ raise RuntimeError, "Error: named letrec is not a illegal form"
1492
1631
  end
1493
1632
  sexp
1494
1633
  else
@@ -1642,14 +1781,22 @@ class Evaluator
1642
1781
  forward_gensym_counter()
1643
1782
  end
1644
1783
 
1784
+ def _load_MIMARKcompiled_MIMARKcode_MIMARKfrom_MIMARKstring( rubyExp )
1785
+ eval( rubyExp, @binding )
1786
+ forward_gensym_counter()
1787
+ end
1788
+
1645
1789
  def _load_MIMARKcompiled_MIMARKcode( filename )
1646
1790
  open( filename, "r:utf-8" ) { |f|
1647
- rubyExp = f.read
1648
- eval( rubyExp, @binding )
1791
+ eval( f.read, @binding )
1649
1792
  }
1650
1793
  forward_gensym_counter()
1651
1794
  end
1652
1795
 
1796
+ def _clean_MIMARKcompiled_MIMARKcode
1797
+ @compiled_code = Hash.new
1798
+ end
1799
+
1653
1800
  def _get_MIMARKcompiled_MIMARKcode
1654
1801
  @compiled_code
1655
1802
  ret = Hash.new
@@ -1705,6 +1852,13 @@ class Printer
1705
1852
  else
1706
1853
  "(" + arr.join( " " ) + (lastAtom ? " . " + lastAtom : "") + ")"
1707
1854
  end
1855
+ when Array # is a vector in the Nendo world.
1856
+ arr = sexp.map { |x| __write( x, readable ) }
1857
+ "#(" + arr.join( " " ) + ")"
1858
+ when true
1859
+ "#t"
1860
+ when false
1861
+ "#f"
1708
1862
  when Symbol
1709
1863
  keyword = getQuoteKeyword.call( sexp )
1710
1864
  if keyword
@@ -1712,7 +1866,7 @@ class Printer
1712
1866
  else
1713
1867
  sprintf( "%s", sexp.to_s )
1714
1868
  end
1715
- when String
1869
+ when String, LispString
1716
1870
  if readable
1717
1871
  sprintf( "\"%s\"", LispString.escape( sexp.to_s ))
1718
1872
  else
@@ -1763,6 +1917,22 @@ class Nendo
1763
1917
  @evaluator._load( path )
1764
1918
  end
1765
1919
 
1920
+ def load_compiled_code( path )
1921
+ @evaluator._load_MIMARKcompiled_MIMARKcode( path )
1922
+ end
1923
+
1924
+ def load_compiled_code_from_string( rubyExp )
1925
+ @evaluator._load_MIMARKcompiled_MIMARKcode_MIMARKfrom_MIMARKstring( rubyExp )
1926
+ end
1927
+
1928
+ def setArgv( argv )
1929
+ @evaluator.setArgv( argv )
1930
+ end
1931
+
1932
+ def clean_compiled_code
1933
+ @evaluator._clean_MIMARKcompiled_MIMARKcode()
1934
+ end
1935
+
1766
1936
  def repl
1767
1937
  printer = Printer.new( @debug_printer )
1768
1938
  reader = nil