nendo 0.3.1 → 0.3.2

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