nydp 0.4.0 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +44 -0
  3. data/lib/lisp/core-010-precompile.nydp +13 -16
  4. data/lib/lisp/core-012-utils.nydp +21 -6
  5. data/lib/lisp/core-015-documentation.nydp +60 -19
  6. data/lib/lisp/core-017-builtin-dox.nydp +50 -39
  7. data/lib/lisp/core-020-utils.nydp +5 -5
  8. data/lib/lisp/core-030-syntax.nydp +103 -61
  9. data/lib/lisp/core-035-flow-control.nydp +18 -9
  10. data/lib/lisp/core-037-list-utils.nydp +36 -14
  11. data/lib/lisp/core-039-module.nydp +24 -0
  12. data/lib/lisp/core-040-utils.nydp +41 -23
  13. data/lib/lisp/core-041-string-utils.nydp +37 -9
  14. data/lib/lisp/core-042-date-utils.nydp +21 -1
  15. data/lib/lisp/core-043-list-utils.nydp +93 -67
  16. data/lib/lisp/core-045-dox-utils.nydp +5 -0
  17. data/lib/lisp/core-080-pretty-print.nydp +55 -17
  18. data/lib/lisp/core-090-hook.nydp +35 -1
  19. data/lib/lisp/core-100-utils.nydp +130 -28
  20. data/lib/lisp/core-110-hash-utils.nydp +61 -0
  21. data/lib/lisp/core-120-settings.nydp +46 -0
  22. data/lib/lisp/core-130-validations.nydp +51 -0
  23. data/lib/lisp/{core-060-benchmarking.nydp → core-900-benchmarking.nydp} +108 -5
  24. data/lib/lisp/tests/accum-examples.nydp +28 -1
  25. data/lib/lisp/tests/aif-examples.nydp +8 -3
  26. data/lib/lisp/tests/andify-examples.nydp +7 -0
  27. data/lib/lisp/tests/at-syntax-examples.nydp +17 -0
  28. data/lib/lisp/tests/best-examples.nydp +9 -0
  29. data/lib/lisp/tests/builtin-tests.nydp +19 -0
  30. data/lib/lisp/tests/case-examples.nydp +14 -0
  31. data/lib/lisp/tests/cdr-set-examples.nydp +6 -0
  32. data/lib/lisp/tests/date-examples.nydp +56 -1
  33. data/lib/lisp/tests/destructuring-examples.nydp +5 -5
  34. data/lib/lisp/tests/detect-examples.nydp +12 -0
  35. data/lib/lisp/tests/dp-examples.nydp +24 -0
  36. data/lib/lisp/tests/empty-examples.nydp +1 -1
  37. data/lib/lisp/tests/error-tests.nydp +4 -4
  38. data/lib/lisp/tests/filter-forms-examples.nydp +30 -0
  39. data/lib/lisp/tests/foundation-test.nydp +12 -0
  40. data/lib/lisp/tests/hash-examples.nydp +26 -2
  41. data/lib/lisp/tests/list-grep-examples.nydp +40 -0
  42. data/lib/lisp/tests/list-tests.nydp +58 -1
  43. data/lib/lisp/tests/map-hash-examples.nydp +11 -0
  44. data/lib/lisp/tests/mapreduce-examples.nydp +10 -0
  45. data/lib/lisp/tests/module-examples.nydp +10 -0
  46. data/lib/lisp/tests/multi-assign-examples.nydp +6 -0
  47. data/lib/lisp/tests/parser-tests.nydp +21 -0
  48. data/lib/lisp/tests/pretty-print-tests.nydp +16 -13
  49. data/lib/lisp/tests/set-difference-examples.nydp +8 -0
  50. data/lib/lisp/tests/set-intersection-examples.nydp +32 -0
  51. data/lib/lisp/tests/set-union-examples.nydp +24 -0
  52. data/lib/lisp/tests/settings-examples.nydp +40 -0
  53. data/lib/lisp/tests/sort-examples.nydp +8 -0
  54. data/lib/lisp/tests/string-tests.nydp +61 -1
  55. data/lib/lisp/tests/syntax-tests.nydp +5 -1
  56. data/lib/lisp/tests/to-integer-examples.nydp +16 -0
  57. data/lib/lisp/tests/validation-examples.nydp +15 -0
  58. data/lib/lisp/tests/zap-examples.nydp +12 -0
  59. data/lib/nydp.rb +13 -7
  60. data/lib/nydp/assignment.rb +10 -3
  61. data/lib/nydp/builtin.rb +1 -1
  62. data/lib/nydp/builtin/abs.rb +8 -0
  63. data/lib/nydp/builtin/cdr_set.rb +1 -6
  64. data/lib/nydp/builtin/date.rb +15 -1
  65. data/lib/nydp/builtin/error.rb +1 -1
  66. data/lib/nydp/builtin/handle_error.rb +1 -1
  67. data/lib/nydp/builtin/hash.rb +27 -45
  68. data/lib/nydp/builtin/inspect.rb +1 -1
  69. data/lib/nydp/builtin/plus.rb +10 -2
  70. data/lib/nydp/builtin/rand.rb +18 -0
  71. data/lib/nydp/builtin/random_string.rb +2 -2
  72. data/lib/nydp/builtin/ruby_wrap.rb +72 -0
  73. data/lib/nydp/builtin/set_intersection.rb +8 -0
  74. data/lib/nydp/builtin/set_union.rb +8 -0
  75. data/lib/nydp/builtin/string_match.rb +2 -2
  76. data/lib/nydp/builtin/string_pad_left.rb +7 -0
  77. data/lib/nydp/builtin/string_pad_right.rb +7 -0
  78. data/lib/nydp/builtin/string_replace.rb +1 -1
  79. data/lib/nydp/builtin/string_split.rb +1 -2
  80. data/lib/nydp/builtin/to_integer.rb +23 -0
  81. data/lib/nydp/builtin/to_string.rb +2 -9
  82. data/lib/nydp/builtin/type_of.rb +9 -6
  83. data/lib/nydp/closure.rb +0 -3
  84. data/lib/nydp/cond.rb +23 -1
  85. data/lib/nydp/context_symbol.rb +14 -6
  86. data/lib/nydp/core.rb +45 -33
  87. data/lib/nydp/core_ext.rb +54 -0
  88. data/lib/nydp/date.rb +37 -31
  89. data/lib/nydp/function_invocation.rb +34 -26
  90. data/lib/nydp/hash.rb +5 -6
  91. data/lib/nydp/helper.rb +41 -25
  92. data/lib/nydp/interpreted_function.rb +68 -40
  93. data/lib/nydp/literal.rb +1 -1
  94. data/lib/nydp/pair.rb +25 -9
  95. data/lib/nydp/parser.rb +8 -6
  96. data/lib/nydp/string_atom.rb +16 -22
  97. data/lib/nydp/symbol.rb +40 -27
  98. data/lib/nydp/symbol_lookup.rb +7 -7
  99. data/lib/nydp/tokeniser.rb +2 -2
  100. data/lib/nydp/truth.rb +17 -10
  101. data/lib/nydp/version.rb +1 -1
  102. data/lib/nydp/vm.rb +7 -2
  103. data/nydp.gemspec +2 -4
  104. data/spec/date_spec.rb +115 -22
  105. data/spec/embedded_spec.rb +12 -12
  106. data/spec/foreign_hash_spec.rb +14 -2
  107. data/spec/hash_non_hash_behaviour_spec.rb +7 -7
  108. data/spec/hash_spec.rb +24 -2
  109. data/spec/nydp_spec.rb +14 -2
  110. data/spec/parser_spec.rb +27 -16
  111. data/spec/rand_spec.rb +45 -0
  112. data/spec/spec_helper.rb +13 -1
  113. data/spec/symbol_spec.rb +31 -0
  114. data/spec/time_spec.rb +1 -1
  115. metadata +38 -37
  116. data/lib/nydp/builtin/car.rb +0 -7
  117. data/lib/nydp/builtin/cdr.rb +0 -7
  118. data/lib/nydp/builtin/cons.rb +0 -9
@@ -28,3 +28,11 @@
28
28
  (sort-by len
29
29
  '("short" "very long" "sport" "very song" "min" "max"))
30
30
  ("max" "min" "sport" "short" "very song" "very long")))
31
+
32
+ (examples-for safe-sort-by
33
+ ("sorts a list of hashes by a specified key"
34
+ (let hh (list { a 1 b 2 } { b 9 } { a 3 b 1 } { a nil b 8 })
35
+ (pp (safe-sort-by &a 99 hh)))
36
+ "({ a 1 b 2 } { a 3 b 1 }
37
+ { a nil b 8 }
38
+ { b 9 })"))
@@ -1,3 +1,51 @@
1
+ (examples-for string-eval-fn
2
+ ("returns a function to eval a user-supplied string"
3
+ (let s "hello \~|u|, \~x + \~y is \~(+ x y), thank you!"
4
+ (let f (string-eval-fn s '(u x y))
5
+ (f "world" 37 5)))
6
+ "hello world, 37 + 5 is 42, thank you!"))
7
+
8
+ (examples-for string/eval-with-args
9
+ ("evals a user-supplied string"
10
+ (let s "hello \~|u|, \~x + \~y is \~(+ x y), thank heavens!"
11
+ (string/eval-with-args s '(u x y) "world" 36 6))
12
+ "hello world, 36 + 6 is 42, thank heavens!")
13
+
14
+ ("reports errors"
15
+ (on-err errors
16
+ (let s "hello \~|u|, \~x + \~y is \~(+ x y), thank heavens!"
17
+ (string/eval-with-args s '(a b c) "world" 36 6)))
18
+ ("error evaluating \"hello \~|u|, \~x + \~y is \~(+ x y), thank heavens!\"
19
+ with arg names (a b c)
20
+ and args (\"world\" 36 6)"
21
+ "unbound symbol: y")))
22
+
23
+ (examples-for string/pad-left
24
+ ("does not change a string whose length is greater than the given length"
25
+ (string/pad-left "Toronto" 3 "X")
26
+ "Toronto")
27
+
28
+ ("adds left padding to a string such that the result is the given length"
29
+ (string/pad-left "toto" 8 "X")
30
+ "XXXXtoto")
31
+
32
+ ("accepts multi-character padding"
33
+ (string/pad-left "toto" 12 "XYZ")
34
+ "XYZXYZXYtoto"))
35
+
36
+ (examples-for string/pad-right
37
+ ("does not change a string whose length is greater than the given length"
38
+ (string/pad-right "Toronto" 3 "X")
39
+ "Toronto")
40
+
41
+ ("adds right padding to a string such that the result is the given length"
42
+ (string/pad-right "toto" 8 "X")
43
+ "totoXXXX")
44
+
45
+ ("accepts multi-character padding"
46
+ (string/pad-right "toto" 12 "XYZ")
47
+ "totoXYZXYZXY"))
48
+
1
49
  (examples-for string-split
2
50
  ("splits a string using given expression"
3
51
  (string-split "a and b and c and d" " and ")
@@ -24,6 +72,15 @@
24
72
  (string-replace "and|or" "x" "a and b or c and d")
25
73
  "a x b x c x d"))
26
74
 
75
+ (examples-for string-truncate
76
+ ("truncates a string to the given length"
77
+ (string-truncate "a and b and c and d" 8)
78
+ "a and b ")
79
+
80
+ ("truncate to zero"
81
+ (string-truncate "a and b and long and complex" 0)
82
+ ""))
83
+
27
84
  (examples-for string-match
28
85
  ("no match returns nil"
29
86
  (string-match "this that another" "XXXX")
@@ -81,4 +138,7 @@
81
138
  (examples-for string-strip
82
139
  ("removes leading whitespace" (string-strip " hello!") "hello!" )
83
140
  ("removes trailing whitespace" (string-strip "(world) ") "(world)" )
84
- ("removes leading and trailing whitespace" (string-strip "\n\nme\n\n") "me" ))
141
+ ("removes leading and trailing whitespace" (string-strip "\n\nme\n\n") "me" )
142
+ ("ignores leading and trailing whitespace for intenal lines"
143
+ (string-strip "\n\n me \n\n you \n\n\t them \t\n\n")
144
+ "me \n\n you \n\n\t them" ))
@@ -10,7 +10,11 @@
10
10
  ("dislikes no-prefix"
11
11
  (on-err (joinstr "\n" errors)
12
12
  (pre-compile '(:foo 1 2 3)))
13
- "\"Irregular ': syntax: got (|| foo) : not prefix-syntax : in :foo\""))
13
+ "expanding
14
+ (colon-syntax || foo)
15
+ with
16
+ (fn names ((orf (hash-get colon-syntax-overrides car [0#0#0]names) default-colon-syntax) [0#0#0]names))
17
+ Irregular ': syntax: got (|| foo) : not prefix-syntax : in :foo"))
14
18
 
15
19
  (examples-for prefix-list
16
20
  ("one argument"
@@ -0,0 +1,16 @@
1
+ (examples-for to-integer
2
+ ("converts a string"
3
+ (to-integer "1234")
4
+ 1234)
5
+
6
+ ("converts a date"
7
+ (to-integer (date 2004 3 12))
8
+ 1079046000)
9
+
10
+ ("converts a time"
11
+ (to-integer (time 2004 3 12 18 45))
12
+ 1079113500)
13
+
14
+ ("returns nonsense for non-integer"
15
+ (to-integer { foo 'bar })
16
+ 0))
@@ -0,0 +1,15 @@
1
+ (validate/def string test-0 (if (< (len string) 6) (mf "length" "should be more than 6")))
2
+ (validate/def string test-0 (if (> (len string) 10) (mf "length" "should be less than 10")))
3
+
4
+ (examples-for validate
5
+ ("returns a message about a string being too short"
6
+ (to-string:validate "foo" 'test-0)
7
+ "{\"length\"=>(\"should be more than 6\")}")
8
+
9
+ ("returns a message about a string being too long"
10
+ (to-string:validate "foo bar toto titi" 'test-0)
11
+ "{\"length\"=>(\"should be less than 10\")}")
12
+
13
+ ("returns an empty hash"
14
+ (to-string:validate "foo bar" 'test-0)
15
+ "{}"))
@@ -0,0 +1,12 @@
1
+ (examples-for zap
2
+ ("it adds a value to place"
3
+ (let a 10
4
+ (zap + a 2)
5
+ a)
6
+ 12)
7
+
8
+ ("it multiplies the value in a place"
9
+ (let a 10
10
+ (zap * a 2)
11
+ a)
12
+ 20))
@@ -2,17 +2,22 @@ require 'date'
2
2
  require 'set'
3
3
 
4
4
  module Nydp
5
+ class << self
6
+ attr_accessor :logger # not used by this gem but very useful in your app
7
+ end
8
+
5
9
  class Namespace < Hash
6
10
  end
7
11
 
8
12
  # TODO: write VM #apply_function so we have fewer calls to VM.new
9
13
  def self.apply_function ns, function_name, *args
10
- function = r2n(function_name.to_sym, ns).value
11
- args = r2n args, ns
12
14
  vm = VM.new(ns)
13
-
14
- function.invoke vm, args
15
+ function = Symbol.mk(function_name.to_sym, ns).value
16
+ function.invoke vm, r2n(args)
15
17
  vm.thread
18
+ rescue StandardError => e
19
+ friendly_args = args.map { |a| a.respond_to?(:_nydp_compact_inspect) ? a._nydp_compact_inspect : a }
20
+ raise Nydp::Error.new("Invoking #{function_name}\nwith args #{friendly_args.inspect}")
16
21
  end
17
22
 
18
23
  def self.reader txt ; Nydp::StringReader.new txt ; end
@@ -50,9 +55,9 @@ module Nydp
50
55
 
51
56
  def self.repl options={ }
52
57
  toplevel do
53
- silent = options.delete :silent
54
- ns = options.delete :ns
55
- launch_time = Time.now
58
+ launch_time = Time.now
59
+ silent = options.delete :silent
60
+ ns = options.delete :ns
56
61
  last_script_time = Time.now
57
62
  puts "welcome to nydp #{options.inspect}" unless silent
58
63
  reader = Nydp::ReadlineReader.new $stdin, "nydp > "
@@ -89,6 +94,7 @@ require "nydp/error"
89
94
  require "nydp/truth"
90
95
  require "nydp/version"
91
96
  require "nydp/helper"
97
+ require 'nydp/core_ext'
92
98
  require "nydp/symbol"
93
99
  require "nydp/symbol_lookup"
94
100
  require "nydp/pair"
@@ -8,6 +8,8 @@ module Nydp
8
8
 
9
9
  def execute vm
10
10
  @name.assign vm.peek_arg, vm.current_context
11
+ rescue
12
+ raise "assigning #{@name.inspect}"
11
13
  end
12
14
 
13
15
  def to_s
@@ -26,9 +28,12 @@ module Nydp
26
28
  end
27
29
 
28
30
  def initialize name, value, value_src
29
- @value_src = value_src
30
- n = AssignmentInstruction.new name
31
- @instructions = cons(value, cons(n))
31
+ @name, @value, @value_src = name, value, value_src
32
+ @instructions = cons(value, cons(AssignmentInstruction.new(name)))
33
+ end
34
+
35
+ def lexical_reach n
36
+ [@name.lexical_reach(n), @value.lexical_reach(n)].max
32
37
  end
33
38
 
34
39
  def to_s
@@ -39,6 +44,8 @@ module Nydp
39
44
 
40
45
  def execute vm
41
46
  vm.push_ctx_instructions @instructions
47
+ rescue
48
+ raise "assigning #{@value.inspect} to #{@name.inspect}"
42
49
  end
43
50
  end
44
51
  end
@@ -32,13 +32,13 @@ module Nydp::Builtin
32
32
  handle_error e, arg_0, arg_1, arg_2
33
33
  end
34
34
 
35
+ # called from 'apply (among others)
35
36
  def invoke vm, args
36
37
  builtin_invoke vm, args
37
38
  rescue StandardError => e
38
39
  handle_error e, *(args.to_a)
39
40
  end
40
41
 
41
-
42
42
  def handle_error e, *args
43
43
  case e
44
44
  when Nydp::Error
@@ -0,0 +1,8 @@
1
+ class Nydp::Builtin::Abs
2
+ include Nydp::Builtin::Base, Singleton
3
+
4
+ def invoke_2 vm, a0 ; vm.push_arg(a0.abs) ; end
5
+ def builtin_invoke vm, args ; invoke_2 vm, args.car ; end
6
+
7
+ def name ; "mod" ; end
8
+ end
@@ -1,10 +1,5 @@
1
1
  class Nydp::Builtin::CdrSet
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
- def builtin_invoke vm, args
5
- pair = args.car
6
- arg = args.cdr.car
7
- pair.cdr = arg
8
- vm.push_arg pair
9
- end
4
+ def builtin_invoke vm, args ; vm.push_arg(args.car.cdr = args.cdr.car) ; end
10
5
  end
@@ -1,13 +1,27 @@
1
1
  class Nydp::Builtin::Date
2
2
  include Nydp::Helper, Nydp::Builtin::Base, Singleton
3
3
 
4
+ def builtin_invoke vm, args
5
+ case args.size
6
+ when 0 ; builtin_invoke_1 vm
7
+ when 1 ; builtin_invoke_2 vm, args.car
8
+ when 2 ; builtin_invoke_3 vm, args.car, args.cdr.car
9
+ when 3 ; builtin_invoke_4 vm, args.car, args.cdr.car, args.cdr.cdr.car
10
+ end
11
+ end
12
+
4
13
  def builtin_invoke_1 vm
5
14
  vm.push_arg(Nydp::Date.new Date.today)
6
15
  end
7
16
 
8
17
  # it's a Time object (or any object that responds to #to_date)
9
18
  def builtin_invoke_2 vm, arg
10
- vm.push_arg(Nydp::Date.new arg.to_date)
19
+ arg = if arg.respond_to?(:to_date)
20
+ arg.to_date
21
+ elsif arg.is_a?(String)
22
+ ::Date.parse(arg)
23
+ end
24
+ vm.push_arg(Nydp::Date.new arg)
11
25
  end
12
26
 
13
27
  def builtin_invoke_3 vm, a0, a1
@@ -4,6 +4,6 @@ class Nydp::Builtin::Error
4
4
  # override #invoke on nydp/builtin/base because
5
5
  # we don't want to inherit error handling
6
6
  def builtin_invoke vm, args
7
- raise Nydp::Error.new(args.to_a.map(&:inspect).join("\n"), vm.last_error)
7
+ raise Nydp::Error.new(args.to_a.map(&:to_s).join("\n"), vm.last_error)
8
8
  end
9
9
  end
@@ -25,7 +25,7 @@ class Nydp::Builtin::HandleError
25
25
  e = e.cause
26
26
  end
27
27
 
28
- handler.invoke_2 vm, vm.r2n(msgs)
28
+ handler.invoke_2 vm, r2n(msgs)
29
29
  end
30
30
 
31
31
  def to_s
@@ -2,57 +2,33 @@ require "nydp/hash"
2
2
 
3
3
  class Nydp::Builtin::Hash
4
4
  include Nydp::Helper, Nydp::Builtin::Base, Singleton
5
+
5
6
  def builtin_invoke vm, args
6
- vm.push_arg(Nydp::Hash.new)
7
+ vm.push_arg(build_hash Nydp::Hash.new, args)
8
+ end
9
+
10
+ def build_hash h, args
11
+ return h if Nydp::NIL.is? args
12
+ k = args.car
13
+ rest = args.cdr
14
+ v = rest.car
15
+ h[k] = v
16
+ build_hash h, rest.cdr
7
17
  end
8
18
  end
9
19
 
10
20
  class Nydp::Builtin::HashGet
11
21
  include Nydp::Helper, Nydp::Builtin::Base, Singleton
12
22
  def builtin_invoke vm, args
13
- hsh = args.car
14
- key = args.cdr.car
15
- case hsh
16
- when Nydp::Hash
17
- vm.push_arg(hsh[key] || Nydp::NIL)
18
- when NilClass, Nydp::NIL
19
- vm.push_arg Nydp::NIL
20
- else
21
- v = hsh.respond_to?(:[]) ? hsh[n2r key] : ruby_call(hsh, key)
22
- vm.push_arg(r2n v, vm.ns)
23
- end
24
- end
25
-
26
- def ruby_call obj, method_name
27
- if obj.respond_to? :_nydp_safe_methods
28
- m = n2r(method_name).to_s.to_sym
29
- allowed = obj._nydp_safe_methods
30
-
31
- obj.send n2r(m) if allowed.include?(m)
32
- else
33
- raise "hash-get: Not a hash: #{obj.class.name}"
34
- end
23
+ vm.push_arg(args.car._nydp_get(args.cdr.car)._nydp_wrapper || Nydp::NIL)
35
24
  end
36
25
  end
37
26
 
38
27
  class Nydp::Builtin::HashSet
39
28
  include Nydp::Helper, Nydp::Builtin::Base, Singleton
40
29
  def builtin_invoke vm, args
41
- hash = args.car
42
- key = args.cdr.car
43
30
  value = args.cdr.cdr.car
44
- case hash
45
- when Nydp::Hash
46
- hash[key] = value
47
- when NilClass, Nydp::NIL
48
- nil
49
- else
50
- if hash.respond_to?(:[]=)
51
- hash[n2r key] = n2r value
52
- else
53
- raise "hash-set: Not a hash: #{hash.class.name}"
54
- end
55
- end
31
+ args.car._nydp_set(args.cdr.car, value)
56
32
  vm.push_arg value
57
33
  end
58
34
  end
@@ -60,14 +36,7 @@ end
60
36
  class Nydp::Builtin::HashKeys
61
37
  include Nydp::Helper, Nydp::Builtin::Base, Singleton
62
38
  def builtin_invoke vm, args
63
- hash = args.car
64
- if hash.is_a? Nydp::Hash
65
- vm.push_arg Nydp::Pair.from_list hash.keys
66
- elsif hash.respond_to?(:keys)
67
- vm.push_arg r2n(hash.keys.to_a.sort, vm.ns)
68
- else
69
- vm.push_arg Nydp::NIL
70
- end
39
+ vm.push_arg args.car._nydp_keys._nydp_wrapper
71
40
  end
72
41
  end
73
42
 
@@ -97,3 +66,16 @@ class Nydp::Builtin::HashMerge
97
66
  vm.push_arg hash_0.merge hash_1
98
67
  end
99
68
  end
69
+
70
+ class Nydp::Builtin::HashSlice
71
+ include Nydp::Helper, Nydp::Builtin::Base, Singleton
72
+
73
+ def builtin_invoke vm, args
74
+ old = args.car
75
+ h = old.class.new
76
+ slice = args.cdr.car
77
+ slice = slice.map { |k| n2r k } unless old.is_a? Nydp::Hash
78
+ slice.each { |k| h[k] = old[k] if old.key?(k) }
79
+ vm.push_arg h
80
+ end
81
+ end
@@ -2,6 +2,6 @@ class Nydp::Builtin::Inspect
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- vm.push_arg Nydp::StringAtom.new(args.car.inspect)
5
+ vm.push_arg args.car.inspect
6
6
  end
7
7
  end
@@ -10,13 +10,21 @@ class Nydp::Builtin::Plus
10
10
  vm.push_arg case args.car
11
11
  when Nydp::Pair
12
12
  sum(args, Nydp::NIL)
13
- when String, Nydp::StringAtom
14
- sum(args, Nydp::StringAtom.new(""))
13
+ when String
14
+ string_concat("", args)
15
15
  else
16
16
  sum(args.cdr, args.car)
17
17
  end
18
18
  end
19
19
 
20
+ def string_concat init, others
21
+ while others && !Nydp::NIL.is?(others)
22
+ init << others.car.to_s
23
+ others = others.cdr
24
+ end
25
+ init
26
+ end
27
+
20
28
  def sum args, accum
21
29
  while args && !Nydp::NIL.is?(args)
22
30
  accum += args.car