nydp 0.3.0 → 0.4.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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.zeiger.yml +28 -0
  3. data/lib/lisp/core-000.nydp +1 -1
  4. data/lib/lisp/core-015-documentation.nydp +6 -9
  5. data/lib/lisp/core-017-builtin-dox.nydp +33 -0
  6. data/lib/lisp/core-025-warnings.nydp +15 -0
  7. data/lib/lisp/core-030-syntax.nydp +38 -2
  8. data/lib/lisp/core-035-flow-control.nydp +2 -2
  9. data/lib/lisp/core-037-list-utils.nydp +7 -5
  10. data/lib/lisp/core-040-utils.nydp +15 -4
  11. data/lib/lisp/core-043-list-utils.nydp +1 -0
  12. data/lib/lisp/core-045-dox-utils.nydp +6 -0
  13. data/lib/lisp/core-050-test-runner.nydp +9 -9
  14. data/lib/lisp/core-070-prefix-list.nydp +2 -2
  15. data/lib/lisp/core-090-hook.nydp +24 -0
  16. data/lib/lisp/core-100-utils.nydp +38 -10
  17. data/lib/lisp/tests/ampersand-syntax-examples.nydp +26 -0
  18. data/lib/lisp/tests/boot-tests.nydp +1 -1
  19. data/lib/lisp/tests/collect-tests.nydp +4 -0
  20. data/lib/lisp/tests/destructuring-examples.nydp +18 -1
  21. data/lib/lisp/tests/fill-bucket-examples.nydp +46 -2
  22. data/lib/lisp/tests/floor-examples.nydp +58 -0
  23. data/lib/lisp/tests/k-examples.nydp +5 -0
  24. data/lib/lisp/tests/power-examples.nydp +16 -0
  25. data/lib/lisp/tests/string-tests.nydp +8 -0
  26. data/lib/lisp/tests/syntax-tests.nydp +6 -0
  27. data/lib/lisp/tests/zip-examples.nydp +16 -0
  28. data/lib/nydp.rb +6 -2
  29. data/lib/nydp/assignment.rb +1 -2
  30. data/lib/nydp/builtin/ensuring.rb +1 -2
  31. data/lib/nydp/builtin/greater_than.rb +2 -2
  32. data/lib/nydp/builtin/handle_error.rb +1 -2
  33. data/lib/nydp/builtin/less_than.rb +2 -2
  34. data/lib/nydp/builtin/math_ceiling.rb +7 -0
  35. data/lib/nydp/builtin/math_floor.rb +7 -0
  36. data/lib/nydp/builtin/math_power.rb +7 -0
  37. data/lib/nydp/builtin/math_round.rb +7 -0
  38. data/lib/nydp/builtin/parse.rb +2 -2
  39. data/lib/nydp/builtin/parse_in_string.rb +3 -3
  40. data/lib/nydp/builtin/pre_compile.rb +0 -1
  41. data/lib/nydp/compiler.rb +1 -1
  42. data/lib/nydp/cond.rb +3 -6
  43. data/lib/nydp/context_symbol.rb +40 -32
  44. data/lib/nydp/core.rb +8 -2
  45. data/lib/nydp/function_invocation.rb +3 -5
  46. data/lib/nydp/image_store.rb +21 -0
  47. data/lib/nydp/interpreted_function.rb +8 -12
  48. data/lib/nydp/lexical_context_builder.rb +19 -35
  49. data/lib/nydp/pair.rb +2 -1
  50. data/lib/nydp/parser.rb +4 -0
  51. data/lib/nydp/plugin.rb +15 -8
  52. data/lib/nydp/runner.rb +3 -3
  53. data/lib/nydp/symbol.rb +3 -1
  54. data/lib/nydp/symbol_lookup.rb +2 -2
  55. data/lib/nydp/truth.rb +2 -2
  56. data/lib/nydp/version.rb +1 -1
  57. data/lib/nydp/vm.rb +47 -27
  58. data/spec/date_spec.rb +2 -2
  59. data/spec/embedded_spec.rb +16 -16
  60. data/spec/error_spec.rb +1 -1
  61. data/spec/nydp_spec.rb +13 -4
  62. data/spec/parser_spec.rb +63 -16
  63. data/spec/spec_helper.rb +1 -2
  64. data/spec/string_atom_spec.rb +2 -2
  65. data/spec/symbol_spec.rb +2 -2
  66. data/spec/tokeniser_spec.rb +101 -0
  67. metadata +16 -2
@@ -40,7 +40,7 @@ module Nydp
40
40
  def self.compile_pair expression, bindings
41
41
  key = expression.car
42
42
  if sym?(key, :cond)
43
- Cond.build expression.cdr, bindings
43
+ Cond.build expression.cdr, bindings # todo: replace with function? (cond x (fn () iftrue) (fn () iffalse)) -->> performance issues, creating two closures for every cond invocation
44
44
  elsif sym?(key, :quote)
45
45
  Literal.build expression.cadr, bindings
46
46
  elsif sym?(key, :assign)
@@ -28,8 +28,7 @@ module Nydp
28
28
  end
29
29
 
30
30
  def execute vm
31
- vm.instructions.push conditional
32
- vm.contexts.push vm.current_context
31
+ vm.push_ctx_instructions conditional
33
32
  condition.execute vm
34
33
  end
35
34
 
@@ -78,8 +77,7 @@ module Nydp
78
77
  class Cond_LEX < CondBase
79
78
  def execute vm
80
79
  truth = !Nydp::NIL.is?(@condition.value vm.current_context)
81
- vm.instructions.push (truth ? @when_true : @when_false)
82
- vm.contexts.push vm.current_context
80
+ vm.push_ctx_instructions (truth ? @when_true : @when_false)
83
81
  end
84
82
 
85
83
  def self.build cond, when_true, when_false
@@ -171,8 +169,7 @@ module Nydp
171
169
 
172
170
  class Cond_SYM < CondBase
173
171
  def execute vm
174
- vm.instructions.push (Nydp::NIL.is?(@condition.value) ? @when_false : @when_true)
175
- vm.contexts.push vm.current_context
172
+ vm.push_ctx_instructions (Nydp::NIL.is?(@condition.value) ? @when_false : @when_true)
176
173
  end
177
174
  end
178
175
  end
@@ -1,11 +1,16 @@
1
1
  module Nydp
2
2
  class ContextSymbol
3
- def self.build depth, name, binding_index
4
- cname = "ContextSymbol_#{depth}_#{binding_index}"
5
-
6
- existing = const_get(cname) rescue nil
7
- return existing.new(name) if existing
3
+ def self.const_missing const
4
+ if const.to_s =~ /^ContextSymbol_\d+_\d+$/
5
+ name = const.to_s.split(/_/)
6
+ define_klass(const, name[1].to_i, name[2].to_i)
7
+ const_get const
8
+ else
9
+ super(const)
10
+ end
11
+ end
8
12
 
13
+ def self.define_klass name, depth, binding_index
9
14
  getctx = ([".parent"] * depth).join
10
15
  at_index = if binding_index < 10
11
16
  "at_#{binding_index}"
@@ -19,34 +24,37 @@ module Nydp
19
24
  "set_index(#{binding_index}, value)"
20
25
  end
21
26
 
22
- klass = <<KLASS
23
- class #{cname} < Nydp::ContextSymbol
24
- def initialize name
25
- @name = name
26
- end
27
-
28
- def value ctx
29
- ctx#{getctx}.#{at_index} || Nydp::NIL
30
- end
31
-
32
- def assign value, ctx
33
- ctx#{getctx}.#{set_index}
34
- rescue StandardError => e
35
- raise "problem in \#{self.class.name}#assign, name is \#{@name}, depth is \#{depth}, index is #{binding_index}"
36
- end
37
-
38
- def execute vm
39
- vm.push_arg value vm.current_context
40
- end
41
-
42
- def depth ; #{depth} ; end
43
- def inspect ; to_s ; end
44
- def to_s ; "[#{depth}##{binding_index}]\#{@name}" ; end
45
- end
46
- KLASS
27
+ code = <<-KLASS
28
+ def initialize name
29
+ @name = name
30
+ end
31
+
32
+ def value ctx
33
+ ctx#{getctx}.#{at_index} || Nydp::NIL
34
+ end
35
+
36
+ def assign value, ctx
37
+ ctx#{getctx}.#{set_index}
38
+ rescue StandardError => e
39
+ raise "problem in \#{self.class.name}#assign, name is \#{@name}, depth is \#{depth}, index is #{binding_index}"
40
+ end
41
+
42
+ def execute vm
43
+ vm.push_arg value vm.current_context
44
+ end
45
+
46
+ def depth ; #{depth} ; end
47
+ def inspect ; to_s ; end
48
+ def to_s ; "[#{depth}##{binding_index}]\#{@name}" ; end
49
+ KLASS
50
+
51
+ const_set name, Class.new(Nydp::ContextSymbol) {
52
+ eval code
53
+ }
54
+ end
47
55
 
48
- eval klass
49
- const_get(cname).new(name)
56
+ def self.build depth, name, binding_index
57
+ const_get(:"ContextSymbol_#{depth}_#{binding_index}").new(name)
50
58
  end
51
59
  end
52
60
  end
@@ -71,8 +71,14 @@ module Nydp
71
71
  Symbol.mk(:"hash-key?", ns).assign(Nydp::Builtin::HashKeyPresent.instance)
72
72
  Symbol.mk(:"hash-merge", ns).assign(Nydp::Builtin::HashMerge.instance)
73
73
  Symbol.mk(:"vm-info", ns).assign Nydp::Builtin::VmInfo.instance
74
- Symbol.mk(:"pre-compile", ns).assign Nydp::Builtin::PreCompile.instance
75
- Symbol.mk(:"script-run" , ns).assign Nydp::Builtin::ScriptRun.instance
74
+ Symbol.mk(:"pre-compile" , ns).assign Nydp::Builtin::PreCompile.instance
75
+ Symbol.mk(:"script-run" , ns).assign Nydp::Builtin::ScriptRun.instance
76
+ Symbol.mk(:"**" , ns).assign Nydp::Builtin::MathPower.instance
77
+ Symbol.mk(:"⌊" , ns).assign Nydp::Builtin::MathFloor.instance
78
+ Symbol.mk(:"math-floor" , ns).assign Nydp::Builtin::MathFloor.instance
79
+ Symbol.mk(:"⌈" , ns).assign Nydp::Builtin::MathCeiling.instance
80
+ Symbol.mk(:"math-ceiling", ns).assign Nydp::Builtin::MathCeiling.instance
81
+ Symbol.mk(:"math-round" , ns).assign Nydp::Builtin::MathRound.instance
76
82
  end
77
83
  end
78
84
  end
@@ -24,7 +24,7 @@ module Nydp
24
24
  raise
25
25
  else
26
26
  if e.is_a?(NoMethodError) && !f.respond_to?(invoker)
27
- raise InvocationFailed.new("#{f} is not a function")
27
+ raise InvocationFailed.new("#{f.inspect} is not a function: args were #{args.inspect}")
28
28
  else
29
29
  msg = args.map { |a| " #{a.inspect}"}.join("\n")
30
30
  msg = "failed to execute invocation #{f.inspect}\n#{msg}"
@@ -323,10 +323,8 @@ module Nydp
323
323
 
324
324
  def execute vm
325
325
  ## Invocation.sig @sig
326
- vm.instructions.push function_instruction
327
- vm.contexts .push vm.current_context
328
- vm.instructions.push argument_instructions
329
- vm.contexts .push vm.current_context
326
+ vm.push_ctx_instructions function_instruction
327
+ vm.push_ctx_instructions argument_instructions
330
328
  end
331
329
 
332
330
  def inspect ; @source.inspect ; end
@@ -0,0 +1,21 @@
1
+ require 'digest'
2
+
3
+ module Nydp
4
+ class ImageStore
5
+ attr_accessor :store
6
+
7
+ def initialize store=nil
8
+ @store = store
9
+ FileUtils.mkdir_p(store, mode: 0775) if store
10
+ end
11
+
12
+ def digest ; Digest::MD5.hexdigest(Nydp.all_files.map { |f| File.read f }.join) ; end
13
+ def file_name id ; File.join @store, "#{id}.nydp_image" ; end
14
+ def load? fname ; File.binread(fname) if File.exists?(fname) ; end
15
+ def load id ; load?(file_name id) if @store ; end
16
+ def store id, image ; File.open(file_name(id), "wb") { |f| f.write(image) } if @store ; end
17
+ def generate id ; Marshal.dump(::Nydp.build_nydp).tap { |im| store id, im } ; end
18
+ def resurrect id ; load(id) || generate(id) ; end
19
+ def get ; Marshal.load(@image ||= resurrect(digest)) ; end
20
+ end
21
+ end
@@ -10,41 +10,37 @@ module Nydp
10
10
  end
11
11
 
12
12
  class InterpretedFunction
13
+ NIL = Nydp::NIL
13
14
  include Helper
14
15
  extend Helper
15
16
 
16
17
  attr_accessor :arg_names, :body, :context_builder
17
18
 
18
19
  def invoke_1 vm, parent_context
19
- vm.instructions.push self.body
20
- vm.contexts.push set_args_0 parent_context
20
+ vm.push_instructions self.body, set_args_0(parent_context)
21
21
  end
22
22
 
23
23
  def invoke_2 vm, parent_context, arg
24
- vm.instructions.push self.body
25
- vm.contexts.push set_args_1(parent_context, arg)
24
+ vm.push_instructions self.body, set_args_1(parent_context, arg)
26
25
  end
27
26
 
28
27
  def invoke_3 vm, parent_context, arg_0, arg_1
29
- vm.instructions.push self.body
30
- vm.contexts.push set_args_2(parent_context, arg_0, arg_1)
28
+ vm.push_instructions self.body, set_args_2(parent_context, arg_0, arg_1)
31
29
  end
32
30
 
33
31
  def invoke_4 vm, parent_context, arg_0, arg_1, arg_2
34
- vm.instructions.push self.body
35
- vm.contexts.push set_args_3(parent_context, arg_0, arg_1, arg_2)
32
+ vm.push_instructions self.body, set_args_3(parent_context, arg_0, arg_1, arg_2)
36
33
  end
37
34
 
38
35
  def invoke vm, parent_context, arg_values
39
- vm.instructions.push self.body
40
- vm.contexts.push set_args(parent_context, arg_values)
36
+ vm.push_instructions self.body, set_args(parent_context, arg_values)
41
37
  end
42
38
 
43
39
  def setup_context context, names, values
44
40
  if pair? names
45
41
  context.set names.car, values.car
46
42
  setup_context context, names.cdr, values.cdr
47
- elsif Nydp::NIL.isnt? names
43
+ elsif NIL != names
48
44
  context.set names, values
49
45
  end
50
46
  end
@@ -75,7 +71,7 @@ module Nydp
75
71
  if pair? arg_list
76
72
  index_parameters arg_list.car, hsh
77
73
  index_parameters arg_list.cdr, hsh
78
- elsif Nydp::NIL.isnt? arg_list
74
+ elsif NIL != arg_list
79
75
  hsh[arg_list] = hsh.size
80
76
  end
81
77
  end
@@ -1,6 +1,17 @@
1
1
  module Nydp::LexicalContextBuilder
2
2
  extend Nydp::Helper
3
3
 
4
+ def self.const_missing(const)
5
+ if const.to_s =~ /^B_\d+(_Rest)?$/
6
+ name = const.to_s.split(/_/)
7
+ size = name[1].to_i
8
+ name[2] ? build_builder_rest_class(const, size) : build_builder_class(const, size)
9
+ const_get const
10
+ else
11
+ super(const)
12
+ end
13
+ end
14
+
4
15
  def self.mklc nexpected
5
16
  (nexpected > 0) ? "lc = Nydp::LexicalContext.new lc\n " : ""
6
17
  end
@@ -70,40 +81,20 @@ module Nydp::LexicalContextBuilder
70
81
  "
71
82
  end
72
83
 
73
- def self.get_builder_class expected_arg_count
74
- name = "B_#{expected_arg_count}"
75
- existing = const_get(name) rescue nil
76
- return name if existing
84
+ def self.define_module name, code
85
+ const_set name.to_sym, Module.new { eval code }
86
+ end
77
87
 
88
+ def self.build_builder_class name, expected_arg_count
78
89
  n_methods = (0..3).map { |given| build_set_args_n_method given, expected_arg_count }
79
90
  x_method = build_set_args_method expected_arg_count
80
- klass = <<KLASS
81
- module #{name}
82
- #{n_methods.join "\n"}
83
- #{x_method}
84
- end
85
- KLASS
86
-
87
- eval klass
88
- name
91
+ define_module name, "#{n_methods.join "\n"}\n#{x_method}"
89
92
  end
90
93
 
91
- def self.get_builder_rest_class proper_arg_count
92
- name = "B_#{proper_arg_count}_Rest"
93
- existing = const_get(name) rescue nil
94
- return name if existing
95
-
94
+ def self.build_builder_rest_class name, proper_arg_count
96
95
  n_methods = (0..3).map { |given| build_set_args_n_rest_method given, proper_arg_count }
97
96
  x_method = build_set_args_rest_method proper_arg_count
98
- klass = <<KLASS
99
- module #{name}
100
- #{n_methods.join "\n"}
101
- #{x_method}
102
- end
103
- KLASS
104
-
105
- eval klass
106
- name
97
+ define_module name, "#{n_methods.join "\n"}\n#{x_method}"
107
98
  end
108
99
 
109
100
  def self.select arg_names
@@ -114,13 +105,6 @@ KLASS
114
105
  size = 0
115
106
  proper = Nydp::NIL.is? arg_names
116
107
  end
117
-
118
- if proper
119
- class_name = get_builder_class size
120
- else
121
- class_name = get_builder_rest_class size
122
- end
123
-
124
- self.const_get(class_name.to_sym)
108
+ const_get(proper ? :"B_#{size}" : :"B_#{size}_Rest")
125
109
  end
126
110
  end
@@ -1,4 +1,5 @@
1
1
  class Nydp::Pair
2
+ NIL = Nydp::NIL
2
3
  include Nydp::Helper, Enumerable
3
4
  extend Nydp::Helper
4
5
 
@@ -51,7 +52,7 @@ class Nydp::Pair
51
52
  end
52
53
 
53
54
  def == other
54
- Nydp::NIL.isnt?(other) && (other.respond_to? :car) && (self.car == other.car) && (self.cdr == other.cdr)
55
+ (NIL != other) && (other.respond_to? :car) && (self.car == other.car) && (self.cdr == other.cdr)
55
56
  end
56
57
 
57
58
  def proper?
@@ -121,6 +121,10 @@ module Nydp
121
121
  INTERPOLATION_SIGN = /~/
122
122
  INTERPOLATION_ESCAPES = { /~\s/ => true, /~~/ => "~" }
123
123
 
124
+ def embedded token_stream
125
+ string token_stream, "", :eof
126
+ end
127
+
124
128
  def string token_stream, open_delimiter, close_delimiter
125
129
  fragments = [sym(:"string-pieces")]
126
130
  string_token = token_stream.next_string_fragment(open_delimiter, close_delimiter, INTERPOLATION_SIGN, INTERPOLATION_ESCAPES)
@@ -1,12 +1,15 @@
1
+ require 'nydp/image_store'
2
+
1
3
  module Nydp
2
4
  PLUGINS = []
5
+ @@image_store = Nydp::ImageStore.new
3
6
 
4
- def self.plug_in plugin ; PLUGINS << plugin ; end
5
- def self.load_rake_tasks; PLUGINS.each &:load_rake_tasks ; end
6
- def self.setup ns; PLUGINS.each { |plg| plg.setup ns } ; end
7
- def self.loadfiles; PLUGINS.map(&:loadfiles).flatten ; end
8
- def self.testfiles; PLUGINS.map(&:testfiles).flatten ; end
9
- def self.plugin_names ; PLUGINS.map(&:name) ; end
7
+ def self.plug_in plugin ; PLUGINS << plugin ; end
8
+ def self.load_rake_tasks ; PLUGINS.each &:load_rake_tasks ; end
9
+ def self.setup ns ; PLUGINS.each { |plg| plg.setup ns } ; end
10
+ def self.loadfiles ; PLUGINS.map(&:loadfiles).flatten ; end
11
+ def self.testfiles ; PLUGINS.map(&:testfiles).flatten ; end
12
+ def self.plugin_names ; PLUGINS.map(&:name) ; end
10
13
  def self.loadall ns, plugin, files
11
14
  vm = VM.new(ns)
12
15
  apply_function ns, :"script-run", :"plugin-start", plugin.name if plugin
@@ -20,14 +23,18 @@ module Nydp
20
23
  apply_function ns, :"script-run", :"plugin-end", plugin.name if plugin
21
24
  end
22
25
 
23
- def self.build_nydp extra_files=nil, &block
26
+ def self.all_files ; PLUGINS.each_with_object([]) { |plg, list| plg.loadfiles.each { |f| list << f } } ; end
27
+ def self.set_image_store store ; @@image_store = store ; end
28
+
29
+ def self.get_nydp ; @@image_store.get ; end
30
+
31
+ def self.build_nydp &block
24
32
  ns = Namespace.new
25
33
  setup(ns)
26
34
  PLUGINS.each { |plg|
27
35
  loadall ns, plg, plg.loadfiles, &block
28
36
  loadall ns, plg, plg.testfiles, &block
29
37
  }
30
- loadall ns, nil, extra_files, &block if extra_files
31
38
  ns
32
39
  end
33
40
  end
@@ -49,7 +49,7 @@ module Nydp
49
49
 
50
50
  def compile_and_eval expr
51
51
  begin
52
- vm.thread Pair.new(Compiler.compile(expr, Nydp::NIL), Nydp::NIL)
52
+ vm.thread_with_expr Pair.new(Compiler.compile(expr, Nydp::NIL), Nydp::NIL)
53
53
  rescue StandardError => e
54
54
  raise Nydp::Error, "failed to eval #{expr.inspect}"
55
55
  end
@@ -68,8 +68,8 @@ module Nydp
68
68
  def initialize vm, ns, stream, printer=nil, name=nil
69
69
  super vm, ns, name
70
70
  @printer = printer
71
- @parser = Nydp::Parser.new(ns)
72
- @tokens = Nydp::Tokeniser.new stream
71
+ @parser = Nydp.new_parser(ns)
72
+ @tokens = Nydp.new_tokeniser stream
73
73
  end
74
74
 
75
75
  def print val
@@ -1,4 +1,6 @@
1
1
  class Nydp::Symbol
2
+ class Unbound < StandardError ; end
3
+
2
4
  EMPTY = :""
3
5
  attr_accessor :name
4
6
  attr_reader :hash
@@ -15,7 +17,7 @@ class Nydp::Symbol
15
17
  end
16
18
 
17
19
  def value context=nil
18
- raise Nydp::Error.new("unbound symbol: #{self.inspect}") if @value == nil
20
+ raise Unbound.new("unbound symbol: #{self.inspect}") if @value == nil
19
21
  @value
20
22
  end
21
23
 
@@ -5,7 +5,7 @@ module Nydp
5
5
  extend Helper
6
6
 
7
7
  def self.skip_empty bindings
8
- while Nydp::NIL.isnt?(bindings) && bindings.car.empty?
8
+ while (NIL != bindings) && bindings.car.empty?
9
9
  bindings = bindings.cdr
10
10
  end
11
11
  bindings
@@ -14,7 +14,7 @@ module Nydp
14
14
  def self.build name, bindings
15
15
  bindings = skip_empty bindings
16
16
  depth = 0
17
- while Nydp::NIL.isnt? bindings
17
+ while NIL != bindings
18
18
  here = bindings.car
19
19
  if here.key? name
20
20
  binding_index = here[name]