nydp 0.0.2 → 0.0.3

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.
@@ -1,4 +1,7 @@
1
1
  module Nydp
2
+ class InvocationFailed < StandardError
3
+ end
4
+
2
5
  class InvokeFunctionInstruction
3
6
  def initialize arg_count, source_expression
4
7
  @source_expression = source_expression
@@ -8,24 +11,22 @@ module Nydp
8
11
  def execute vm
9
12
  args = vm.pop_args @arg_count
10
13
  args.car.invoke vm, args.cdr
14
+ rescue Nydp::Error => ne
15
+ raise ne
16
+ rescue InvocationFailed => i_f
17
+ raise i_f
11
18
  rescue Exception => e
12
- puts "failed to execute fn #{args.inspect}"
13
- puts "source was #{source}"
14
- puts "function was #{args.car.inspect}"
15
- vm.error e
16
- end
17
-
18
- def inspect
19
- "#{self.class.name}:#{source}"
19
+ msg = "failed to execute invocation #{args.inspect}"
20
+ msg += "\nsource was #{source.inspect}"
21
+ msg += "\nfunction name was #{source.car.inspect}"
22
+ i_f = InvocationFailed.new "#{msg}\n#{vm.error}#{e.message}"
23
+ i_f.set_backtrace e.backtrace
24
+ raise i_f
20
25
  end
21
26
 
22
- def source
23
- @source_expression
24
- end
25
-
26
- def to_s
27
- source
28
- end
27
+ def inspect ; source.inspect ; end
28
+ def source ; @source_expression ; end
29
+ def to_s ; source.to_s ; end
29
30
  end
30
31
 
31
32
  class FunctionInvocation
@@ -44,9 +45,7 @@ module Nydp
44
45
  vm.push_instructions @argument_instructions, vm.peek_context
45
46
  end
46
47
 
47
- def inspect; "#function_invocation:#{to_s}"; end
48
- def to_s
49
- @source.to_s
50
- end
48
+ def inspect ; @source.inspect ; end
49
+ def to_s ; @source.to_s ; end
51
50
  end
52
51
  end
@@ -73,7 +73,7 @@ module Nydp
73
73
 
74
74
  def inspect; to_s; end
75
75
  def to_s
76
- "(fn #{arg_names.to_s} #{body.map { |b| b.to_s}.join(' ')})"
76
+ "(fn #{arg_names.to_s} #{body.map { |b| b.inspect}.join(' ')})"
77
77
  end
78
78
  end
79
79
  end
@@ -12,10 +12,11 @@ class Nydp::Pair
12
12
  new a, b
13
13
  end
14
14
 
15
- def caar; car.car; end
16
- def cadr; cdr.car; end
17
- def cdar; car.cdr; end
18
- def cddr; cdr.cdr; end
15
+ def nydp_type ; :pair ; end
16
+ def caar ; car.car ; end
17
+ def cadr ; cdr.car ; end
18
+ def cdar ; car.cdr ; end
19
+ def cddr ; cdr.cdr ; end
19
20
 
20
21
  def self.parse_list list
21
22
  if sym? list.slice(-2), "."
@@ -10,8 +10,7 @@ module Nydp
10
10
  Nydp::Symbol.mk name.to_sym, ns
11
11
  end
12
12
 
13
- def read_list token_stream, termination_token
14
- list = []
13
+ def read_list token_stream, termination_token, list=[]
15
14
  token = token_stream.next_token
16
15
  while token != nil && token.first != termination_token
17
16
  list << next_form(token, token_stream)
@@ -51,19 +50,19 @@ module Nydp
51
50
  Pair.from_list [sym(:unquote), parse_symbol($1)]
52
51
  else
53
52
  syms = txt.to_s.split /\./
54
- return split_sym syms, sym(:"dot-syntax") if syms.length > 1
53
+ return split_sym syms, sym("dot-syntax") if syms.length > 1
55
54
 
56
55
  syms = txt.split /::/
57
- return split_sym syms, sym(:"colon-colon-syntax") if syms.length > 1
56
+ return split_sym syms, sym("colon-colon-syntax") if syms.length > 1
58
57
 
59
58
  syms = txt.split /:/
60
- return split_sym syms, sym(:"colon-syntax") if syms.length > 1
59
+ return split_sym syms, sym("colon-syntax") if syms.length > 1
61
60
 
62
61
  syms = txt.split /->/
63
- return split_sym syms, sym(:"arrow-syntax") if syms.length > 1
62
+ return split_sym syms, sym("arrow-syntax") if syms.length > 1
64
63
 
65
64
  syms = txt.split(/=>/)
66
- return split_sym syms, sym(:"rocket-syntax") if syms.length > 1
65
+ return split_sym syms, sym("rocket-syntax") if syms.length > 1
67
66
 
68
67
  sym txt
69
68
  end
@@ -89,6 +88,8 @@ module Nydp
89
88
  string token_stream, token.last, close_delimiter_for(token.last)
90
89
  when :left_paren
91
90
  prefix_list token[1], read_list(token_stream, :right_paren)
91
+ when :left_brace
92
+ prefix_list token[1], read_list(token_stream, :right_brace, [sym("brace-list")])
92
93
  when :symbol
93
94
  parse_symbol token.last
94
95
  when :comment
@@ -105,16 +106,15 @@ module Nydp
105
106
  def string token_stream, open_delimiter, close_delimiter
106
107
  fragments = [sym(:"string-pieces")]
107
108
  string_token = token_stream.next_string_fragment(open_delimiter, close_delimiter)
108
- fragments << string_token
109
+ fragments << Nydp::StringAtom.new(string_token.string, string_token)
109
110
  while !(string_token.is_a? StringFragmentCloseToken)
110
111
  fragments << expression(token_stream)
111
112
  string_token = token_stream.next_string_fragment('', close_delimiter)
112
- fragments << string_token
113
+ fragments << Nydp::StringAtom.new(string_token.string, string_token)
113
114
  end
114
115
 
115
116
  if fragments.size == 2
116
- tok = fragments[1]
117
- return Nydp::StringAtom.new tok.string, tok
117
+ return fragments[1]
118
118
  else
119
119
  return Pair.from_list fragments
120
120
  end
@@ -0,0 +1,66 @@
1
+ module Nydp
2
+ class Runner
3
+ attr_accessor :vm, :ns
4
+
5
+ def initialize vm, ns
6
+ @vm = vm
7
+ @ns = ns
8
+ @precompile = Symbol.mk(:"pre-compile", ns)
9
+ @quote = Symbol.mk(:quote, ns)
10
+ end
11
+
12
+ def compile_and_eval expr
13
+ vm.thread Pair.new(Compiler.compile(expr, Nydp.NIL), Nydp.NIL)
14
+ end
15
+
16
+ def quote expr
17
+ Pair.from_list [@quote, expr]
18
+ end
19
+
20
+ def precompile expr
21
+ Pair.from_list [@precompile, quote(expr)]
22
+ end
23
+
24
+ def pre_compile expr
25
+ compile_and_eval(precompile(expr))
26
+ end
27
+
28
+ def evaluate expr
29
+ compile_and_eval(pre_compile(expr))
30
+ end
31
+ end
32
+
33
+ class StreamRunner < Runner
34
+ attr_accessor :stream, :parser
35
+
36
+ def initialize vm, ns, stream
37
+ super vm, ns
38
+ @stream = stream
39
+ @parser = Nydp::Parser.new(ns)
40
+ @tokens = Nydp::Tokeniser.new stream
41
+ end
42
+
43
+ def prompt *_
44
+ end
45
+
46
+ def run
47
+ res = Nydp.NIL
48
+ prompt
49
+ while !@tokens.finished
50
+ expr = parser.expression(@tokens)
51
+ unless expr.nil?
52
+ res = evaluate expr
53
+ prompt res
54
+ end
55
+ end
56
+ res
57
+ end
58
+ end
59
+
60
+ class Repl < StreamRunner
61
+ def prompt val=nil
62
+ puts val if val
63
+ print "nydp > "
64
+ end
65
+ end
66
+ end
@@ -5,12 +5,11 @@ module Nydp
5
5
  @string, @token = string, token
6
6
  end
7
7
 
8
- def to_s
9
- string
10
- end
8
+ def nydp_type ; :string ; end
9
+ def to_s ; string ; end
11
10
 
12
11
  def inspect
13
- token ? token.rep : string.inspect
12
+ string.inspect
14
13
  end
15
14
 
16
15
  def == other
@@ -20,5 +19,6 @@ module Nydp
20
19
  def + other
21
20
  StringAtom.new "#{@string}#{other}"
22
21
  end
22
+
23
23
  end
24
24
  end
@@ -10,9 +10,7 @@ module Nydp
10
10
  end
11
11
 
12
12
  def == other
13
- %i{ string rep class }.inject(true) { |bool, attr|
14
- bool && (self.send(attr) == other.send(attr))
15
- }
13
+ (self.class == other.class) && (self.string == other.string)
16
14
  end
17
15
  end
18
16
 
@@ -29,13 +29,8 @@ class Nydp::Symbol
29
29
  ns[name.to_sym]
30
30
  end
31
31
 
32
- def inspect
33
- "(sym #{name.to_s})"
34
- end
35
-
36
- def to_s
37
- name.to_s
38
- end
32
+ def inspect ; to_s ; end
33
+ def to_s ; name.to_s ; end
39
34
 
40
35
  def == other
41
36
  other.is_a?(Nydp::Symbol) && (self.name == other.name)
@@ -28,8 +28,12 @@ module Nydp
28
28
  if esc = s.scan(/\\/)
29
29
  rep << esc
30
30
  ch = s.getch
31
- string << ch
32
- rep << ch
31
+ case ch
32
+ when "n" ; string << "\n"
33
+ when "t" ; string << "\t"
34
+ else string << ch
35
+ end
36
+ rep << ch
33
37
  elsif closer = close_delimiter?(s, close_delimiter)
34
38
  rep << closer
35
39
  return StringFragmentCloseToken.new(string, rep)
@@ -62,13 +66,15 @@ module Nydp
62
66
  tok = [:embed_suffix, embed_suffix]
63
67
  elsif list_prefix = s.scan(/[^\s()]*\(/)
64
68
  tok = [:left_paren, list_prefix[0...-1]]
69
+ elsif list_prefix = s.scan(/[^\s()]*\{/)
70
+ tok = [:left_brace, list_prefix[0...-1]]
65
71
  elsif s.scan(/\)/)
66
72
  tok = [:right_paren]
67
73
  elsif number = s.scan(/[-+]?[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?/)
68
74
  tok = [:number, number.to_f]
69
75
  elsif integer = s.scan(/[-+]?[0-9]+/)
70
76
  tok = [:number, integer.to_i]
71
- elsif atom = s.scan(/[^\s()]+/)
77
+ elsif atom = s.scan(/[^\s()"{}]+/)
72
78
  tok = [:symbol, atom]
73
79
  else
74
80
  s.getch
@@ -3,22 +3,21 @@ module Nydp
3
3
  def to_s ; 't' ; end
4
4
  def inspect ; 't[nydp::Truth]' ; end
5
5
  def assign *_ ; self ; end
6
+ def nydp_type ; :truth ; end
6
7
  end
7
8
 
8
9
  class Nil
9
10
  def car ; self ; end
10
11
  def cdr ; self ; end
11
12
  def size ; 0 ; end
12
- def is? other ; other == self ; end
13
- def isnt? other ; other != self ; end
14
- def to_s ; "nil" ; end
13
+ def is? other ; (self.equal? other) ; end
14
+ def isnt? other ; !is?(other) ; end
15
+ def to_s ; "" ; end
15
16
  def + other ; other ; end
16
17
  def copy ; self ; end
17
18
  def assign *_ ; self ; end
18
-
19
- def inspect
20
- "nil[Nydp::Nil]"
21
- end
19
+ def inspect ; "nil" ; end
20
+ def nydp_type ; :nil ; end
22
21
 
23
22
  def execute vm
24
23
  vm.push_arg self
@@ -32,6 +31,9 @@ module Nydp
32
31
  @@nil = Nil.new
33
32
  @@t = Truth.new
34
33
 
34
+ class Nil
35
+ def self.new ; raise "no" ; end
36
+ end
35
37
  def self.NIL; @@nil; end
36
38
  def self.T; @@t; end
37
39
  end
@@ -1,3 +1,3 @@
1
1
  module Nydp
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -41,36 +41,29 @@ module Nydp
41
41
  end
42
42
  end
43
43
 
44
- def error e
45
- puts " error"
46
- puts e
47
- puts "================="
48
- puts
49
- puts "instruction stack"
50
- puts "================="
44
+ def error
45
+ msg = ""
46
+ msg << "\n"
47
+ msg << "\ninstruction stack"
48
+ msg << "\n================="
51
49
  instructions.each_with_index do |ii, ix|
52
- puts "instructions##{ix} : #{ii} #{ii.source if ii.respond_to?(:source)}"
50
+ msg << "\ninstructions##{ix} : #{ii} #{ii.source if ii.respond_to?(:source)}"
53
51
  end
54
- puts
55
- puts
56
- puts "context stack"
57
- puts "================="
52
+ msg << "\n"
53
+ msg << "\n"
54
+ msg << "\ncontext stack"
55
+ msg << "\n================="
58
56
  contexts.each_with_index do |ctx, ix|
59
- puts "context##{ix} : #{ctx}"
57
+ msg << "\ncontext##{ix} : #{ctx}"
60
58
  end
61
- puts
62
- puts
63
- puts "ruby backtrace"
64
- puts "================="
65
- (e.backtrace || []).each_with_index do |ctx, ix|
66
- puts "#{ctx}"
67
- end
68
- puts
69
- puts
59
+ msg << "\n"
60
+ msg << "\n"
70
61
 
71
62
  instructions = []
72
63
  contexts = []
73
64
  args = [Nydp.NIL]
65
+
66
+ msg
74
67
  end
75
68
  end
76
69
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Nydp do
4
- let(:ns) { { } }
5
4
  let(:vm) { Nydp::VM.new }
6
5
 
7
6
  before {
@@ -10,10 +9,6 @@ describe Nydp do
10
9
  Nydp::StreamRunner.new(vm, ns, File.new(boot_path)).run
11
10
  }
12
11
 
13
- def sym name
14
- Nydp::Symbol.mk name.to_sym, ns
15
- end
16
-
17
12
  def list *things
18
13
  Nydp::Pair.from_list things.map { |thing|
19
14
  case thing
@@ -102,7 +97,7 @@ describe Nydp do
102
97
  describe :or do
103
98
  it "should produce some nested conds" do
104
99
  result = run "(reset-uniq-counter) (pre-compile '(or a b c))"
105
- expect(result.to_s).to eq "((fn (ora-3) (cond ora-3 ora-3 ((fn (ora-4) (cond ora-4 ora-4 ((fn (ora-5) (cond ora-5 ora-5)) c))) b))) a)"
100
+ expect(result).to eq parse "((fn (ora-1) (cond ora-1 ora-1 ((fn (ora-2) (cond ora-2 ora-2 ((fn (ora-3) (cond ora-3 ora-3 nil)) c))) b))) a)"
106
101
  end
107
102
  end
108
103
 
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Nydp::Parser do
4
-
5
- let(:ns) { { } }
6
4
  let(:aa) { Nydp::Symbol.mk :aa, ns }
7
5
  let(:a) { Nydp::Symbol.mk :a, ns }
8
6
  let(:b) { Nydp::Symbol.mk :b, ns }
@@ -21,18 +19,10 @@ describe Nydp::Parser do
21
19
  let(:cocosyn) { Nydp::Symbol.mk :"colon-colon-syntax", ns }
22
20
  let(:colosyn) { Nydp::Symbol.mk :"colon-syntax", ns }
23
21
 
24
- def sym name
25
- Nydp::Symbol.mk name.to_sym, ns
26
- end
27
-
28
22
  def parse_string txt, open_delim, close_delim
29
23
  Nydp::Parser.new(ns).string(Nydp::Tokeniser.new(txt), open_delim, close_delim)
30
24
  end
31
25
 
32
- def pair_list xs, last=Nydp.NIL
33
- Nydp::Pair.from_list xs, last
34
- end
35
-
36
26
  it "should parse empty string" do
37
27
  expected = pair_list([sym('string-pieces'), Nydp::StringFragmentCloseToken.new('','$%')])
38
28
  actual = parse_string "%", '$', /%/
@@ -42,21 +32,23 @@ describe Nydp::Parser do
42
32
  it "should parse external text" do
43
33
  actual = parse_string "a fluffy bunny!", 'EAT ', /!/
44
34
  expect(actual) .to eq "a fluffy bunny"
45
- expect(actual.inspect).to eq "EAT a fluffy bunny!"
35
+ expect(actual.inspect).to eq '"a fluffy bunny"'
46
36
  end
47
37
 
48
38
  it "should parse a string delimited by eof" do
49
39
  expected = pair_list([sym('string-pieces'), Nydp::StringFragmentCloseToken.new('a fluffy bunny!','a fluffy bunny!')])
50
40
  actual = parse_string "a fluffy bunny!", '', :eof
51
41
  expect(actual) .to eq "a fluffy bunny!"
52
- expect(actual.inspect).to eq "a fluffy bunny!"
42
+ expect(actual.inspect).to eq '"a fluffy bunny!"'
53
43
  end
54
44
 
55
45
  it "should parse a string with embedded code, delimited by eof" do
56
46
  x1 = sym('string-pieces')
57
47
  x2 = Nydp::StringFragmentToken.new('a fluffy bunny! ',':a fluffy bunny! %%')
48
+ x2 = Nydp::StringAtom.new(x2.string, x2)
58
49
  x3 = sym('expr')
59
50
  x4 = Nydp::StringFragmentCloseToken.new(' a purple cow!',' a purple cow!')
51
+ x4 = Nydp::StringAtom.new(x4.string, x4)
60
52
 
61
53
  expected = pair_list([x1,x2,x3,x4])
62
54
  actual = parse_string "a fluffy bunny! %%expr a purple cow!", ':', :eof
@@ -71,8 +63,10 @@ describe Nydp::Parser do
71
63
 
72
64
  x1 = sym('string-pieces')
73
65
  x2 = Nydp::StringFragmentToken.new('a fluffy bunny! ','------->a fluffy bunny! %%')
66
+ x2 = Nydp::StringAtom.new(x2.string, x2)
74
67
  x3 = pair_list [n1, n2, n3, n4]
75
68
  x4 = Nydp::StringFragmentCloseToken.new(' a purple cow!',' a purple cow!')
69
+ x4 = Nydp::StringAtom.new(x4.string, x4)
76
70
 
77
71
  expected = pair_list([x1,x2,x3,x4])
78
72
  actual = parse_string "a fluffy bunny! %%(foo bar \"an embedded bunny :)\" zop) a purple cow!", '------->', :eof
@@ -85,8 +79,10 @@ describe Nydp::Parser do
85
79
 
86
80
  s1 = sym('string-pieces')
87
81
  s2 = Nydp::StringFragmentToken.new('a rather ','"a rather %%')
82
+ s2 = Nydp::StringAtom.new(s2.string, s2)
88
83
  s3 = pair_list [e1, e2]
89
84
  s4 = Nydp::StringFragmentCloseToken.new(' bunny :)',' bunny :)"')
85
+ s4 = Nydp::StringAtom.new(s4.string, s4)
90
86
 
91
87
  n1 = sym(:foo)
92
88
  n2 = sym(:bar)
@@ -95,8 +91,10 @@ describe Nydp::Parser do
95
91
 
96
92
  x1 = sym('string-pieces')
97
93
  x2 = Nydp::StringFragmentToken.new('a fluffy bunny! ','------->a fluffy bunny! %%')
94
+ x2 = Nydp::StringAtom.new(x2.string, x2)
98
95
  x3 = pair_list [n1, n2, n3, n4]
99
96
  x4 = Nydp::StringFragmentCloseToken.new(' a purple cow!',' a purple cow!')
97
+ x4 = Nydp::StringAtom.new(x4.string, x4)
100
98
 
101
99
  expected = pair_list([x1,x2,x3,x4])
102
100
  actual = parse_string "a fluffy bunny! %%(foo bar \"a rather %%(describe bunny) bunny :)\" zop) a purple cow!", '------->', :eof