nydp 0.3.0 → 0.4.0

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