nydp 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +58 -0
- data/Rakefile +1 -0
- data/bin/nydp +5 -0
- data/bin/nydp-tests +5 -0
- data/lib/lisp/boot.nydp +219 -0
- data/lib/lisp/test-runner.nydp +39 -0
- data/lib/lisp/tests/foundation-test.nydp +28 -0
- data/lib/nydp.rb +143 -0
- data/lib/nydp/assignment.rb +40 -0
- data/lib/nydp/builtin.rb +8 -0
- data/lib/nydp/builtin/apply.rb +16 -0
- data/lib/nydp/builtin/car.rb +5 -0
- data/lib/nydp/builtin/cdr.rb +5 -0
- data/lib/nydp/builtin/cdr_set.rb +8 -0
- data/lib/nydp/builtin/comment.rb +5 -0
- data/lib/nydp/builtin/cons.rb +16 -0
- data/lib/nydp/builtin/divide.rb +13 -0
- data/lib/nydp/builtin/error.rb +6 -0
- data/lib/nydp/builtin/eval.rb +14 -0
- data/lib/nydp/builtin/greater_than.rb +10 -0
- data/lib/nydp/builtin/hash.rb +30 -0
- data/lib/nydp/builtin/inspect.rb +5 -0
- data/lib/nydp/builtin/is_equal.rb +5 -0
- data/lib/nydp/builtin/less_than.rb +10 -0
- data/lib/nydp/builtin/millisecs.rb +7 -0
- data/lib/nydp/builtin/minus.rb +13 -0
- data/lib/nydp/builtin/plus.rb +28 -0
- data/lib/nydp/builtin/pre_compile.rb +5 -0
- data/lib/nydp/builtin/puts.rb +7 -0
- data/lib/nydp/builtin/quit.rb +5 -0
- data/lib/nydp/builtin/random_string.rb +11 -0
- data/lib/nydp/builtin/times.rb +13 -0
- data/lib/nydp/builtin/to_string.rb +12 -0
- data/lib/nydp/builtin/to_sym.rb +21 -0
- data/lib/nydp/builtin/vm_info.rb +13 -0
- data/lib/nydp/closure.rb +17 -0
- data/lib/nydp/compiler.rb +49 -0
- data/lib/nydp/cond.rb +56 -0
- data/lib/nydp/context_symbol.rb +22 -0
- data/lib/nydp/error.rb +4 -0
- data/lib/nydp/function_invocation.rb +52 -0
- data/lib/nydp/helper.rb +32 -0
- data/lib/nydp/interpreted_function.rb +79 -0
- data/lib/nydp/lexical_context.rb +38 -0
- data/lib/nydp/literal.rb +40 -0
- data/lib/nydp/pair.rb +112 -0
- data/lib/nydp/parser.rb +123 -0
- data/lib/nydp/string_atom.rb +24 -0
- data/lib/nydp/string_token.rb +21 -0
- data/lib/nydp/symbol.rb +47 -0
- data/lib/nydp/symbol_lookup.rb +43 -0
- data/lib/nydp/tokeniser.rb +80 -0
- data/lib/nydp/truth.rb +37 -0
- data/lib/nydp/version.rb +3 -0
- data/lib/nydp/vm.rb +76 -0
- data/nydp.gemspec +27 -0
- data/spec/boot_spec.rb +119 -0
- data/spec/embedded_spec.rb +106 -0
- data/spec/nypd_spec.rb +127 -0
- data/spec/pair_spec.rb +102 -0
- data/spec/parser_spec.rb +191 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/symbol_spec.rb +32 -0
- metadata +176 -0
data/lib/nydp/cond.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Nydp
|
2
|
+
class ExecuteConditionalInstruction
|
3
|
+
extend Helper
|
4
|
+
attr_reader :when_true, :when_false
|
5
|
+
|
6
|
+
def initialize when_true, when_false
|
7
|
+
@when_true, @when_false = when_true, when_false
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute vm
|
11
|
+
arg = vm.pop_arg
|
12
|
+
truth = !Nydp.NIL.is?(arg)
|
13
|
+
vm.push_instructions (truth ? when_true : when_false), vm.peek_context
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
"when_true:#{when_true.inspect}:when_false:#{when_false.inspect}"
|
18
|
+
end
|
19
|
+
def to_s
|
20
|
+
"#{when_true.car.to_s} #{when_false.car.to_s}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Cond
|
25
|
+
extend Helper
|
26
|
+
include Helper
|
27
|
+
attr_reader :condition, :conditional
|
28
|
+
|
29
|
+
def initialize cond, when_true, when_false
|
30
|
+
@condition, @conditional = cond, cons(ExecuteConditionalInstruction.new(when_true, when_false))
|
31
|
+
end
|
32
|
+
|
33
|
+
def execute vm
|
34
|
+
vm.push_instructions conditional, vm.peek_context
|
35
|
+
vm.push_instructions condition, vm.peek_context
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect
|
39
|
+
"cond:#{condition.inspect}:#{conditional.inspect}"
|
40
|
+
end
|
41
|
+
def to_s
|
42
|
+
"(cond #{condition.car.to_s} #{conditional.to_s})"
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.build expressions, bindings
|
46
|
+
if expressions.is_a? Nydp::Pair
|
47
|
+
cond = cons Compiler.compile expressions.car, bindings
|
48
|
+
when_true = cons Compiler.compile expressions.cdr.car, bindings
|
49
|
+
when_false = cons Compiler.compile expressions.cdr.cdr.car, bindings
|
50
|
+
new(cond, when_true, when_false)
|
51
|
+
else
|
52
|
+
raise "can't compile Cond: #{expr.inspect}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Nydp
|
2
|
+
class ContextSymbol
|
3
|
+
attr_accessor :depth, :name
|
4
|
+
|
5
|
+
def initialize depth, name
|
6
|
+
@depth, @name = depth, name
|
7
|
+
end
|
8
|
+
|
9
|
+
def value context
|
10
|
+
context.nth(depth).at(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def assign value, context
|
14
|
+
context.nth(depth).set(name, value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect; to_s; end
|
18
|
+
def to_s
|
19
|
+
"[#{depth}]#{name}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/nydp/error.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Nydp
|
2
|
+
class InvokeFunctionInstruction
|
3
|
+
def initialize arg_count, source_expression
|
4
|
+
@source_expression = source_expression
|
5
|
+
@arg_count = arg_count
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute vm
|
9
|
+
args = vm.pop_args @arg_count
|
10
|
+
args.car.invoke vm, args.cdr
|
11
|
+
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}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def source
|
23
|
+
@source_expression
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
source
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class FunctionInvocation
|
32
|
+
extend Helper
|
33
|
+
|
34
|
+
def self.build expression, bindings
|
35
|
+
new cons(InvokeFunctionInstruction.new(expression.size, expression)), Compiler.compile_each(expression, bindings), expression
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize function_instruction, argument_instructions, source
|
39
|
+
@function_instruction, @argument_instructions, @source = function_instruction, argument_instructions, source
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute vm
|
43
|
+
vm.push_instructions @function_instruction, vm.peek_context
|
44
|
+
vm.push_instructions @argument_instructions, vm.peek_context
|
45
|
+
end
|
46
|
+
|
47
|
+
def inspect; "#function_invocation:#{to_s}"; end
|
48
|
+
def to_s
|
49
|
+
@source.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/nydp/helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Nydp
|
2
|
+
module Helper
|
3
|
+
def sym? expr, name
|
4
|
+
expr.is_a?(Nydp::Symbol) && (expr.is? name)
|
5
|
+
end
|
6
|
+
|
7
|
+
def pair? expr
|
8
|
+
expr.is_a?(Nydp::Pair)
|
9
|
+
end
|
10
|
+
|
11
|
+
def cons a, b=Nydp.NIL
|
12
|
+
Nydp::Pair.new a, b
|
13
|
+
end
|
14
|
+
|
15
|
+
def list *args
|
16
|
+
Nydp::Pair.from_list args
|
17
|
+
end
|
18
|
+
|
19
|
+
def sym name, ns
|
20
|
+
Nydp::Symbol.mk name, ns
|
21
|
+
end
|
22
|
+
|
23
|
+
def literal? expr
|
24
|
+
case expr
|
25
|
+
when String, Float, Integer, Fixnum, Nydp.NIL, Nydp::Symbol, Nydp::StringAtom, Nydp::Truth, Nydp::Nil
|
26
|
+
true
|
27
|
+
else
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'nydp/lexical_context'
|
2
|
+
require 'nydp/closure'
|
3
|
+
|
4
|
+
module Nydp
|
5
|
+
class PopArg
|
6
|
+
def self.execute vm
|
7
|
+
vm.pop_arg
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.to_s
|
11
|
+
""
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.inspect
|
15
|
+
"#pop_arg"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class InterpretedFunction
|
20
|
+
include Helper
|
21
|
+
extend Helper
|
22
|
+
|
23
|
+
attr_accessor :arg_names, :body
|
24
|
+
|
25
|
+
def invoke vm, parent_context, arg_values
|
26
|
+
lc = LexicalContext.new parent_context
|
27
|
+
setup_context lc, arg_names, arg_values
|
28
|
+
vm.push_instructions self.body, lc
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_context context, names, values
|
32
|
+
if pair? names
|
33
|
+
context.set names.car, values.car
|
34
|
+
setup_context context, names.cdr, values.cdr
|
35
|
+
elsif Nydp.NIL.isnt? names
|
36
|
+
context.set names, values
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.build arg_list, body, bindings
|
41
|
+
my_params = { }
|
42
|
+
index_parameters arg_list, my_params
|
43
|
+
ifn = Nydp::InterpretedFunction.new
|
44
|
+
ifn.arg_names = arg_list
|
45
|
+
ifn.body = compile_body body, cons(my_params, bindings), []
|
46
|
+
ifn
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.compile_body body_forms, bindings, instructions
|
50
|
+
instructions << Nydp::Compiler.compile(body_forms.car, bindings)
|
51
|
+
|
52
|
+
rest = body_forms.cdr
|
53
|
+
if Nydp.NIL.is? rest
|
54
|
+
return Pair.from_list(instructions)
|
55
|
+
else
|
56
|
+
instructions << PopArg
|
57
|
+
compile_body rest, bindings, instructions
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.index_parameters arg_list, hsh
|
62
|
+
if pair? arg_list
|
63
|
+
index_parameters arg_list.car, hsh
|
64
|
+
index_parameters arg_list.cdr, hsh
|
65
|
+
elsif Nydp.NIL.isnt? arg_list
|
66
|
+
hsh[arg_list] = hsh.size
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def execute vm
|
71
|
+
vm.push_arg Closure.new(self, vm.peek_context)
|
72
|
+
end
|
73
|
+
|
74
|
+
def inspect; to_s; end
|
75
|
+
def to_s
|
76
|
+
"(fn #{arg_names.to_s} #{body.map { |b| b.to_s}.join(' ')})"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Nydp::LexicalContext
|
2
|
+
attr_reader :values, :parent
|
3
|
+
|
4
|
+
def initialize parent
|
5
|
+
@parent = parent
|
6
|
+
@values = { }
|
7
|
+
end
|
8
|
+
|
9
|
+
def nth n
|
10
|
+
case n
|
11
|
+
when 0
|
12
|
+
self
|
13
|
+
when -1
|
14
|
+
raise "wrong nesting level"
|
15
|
+
else
|
16
|
+
parent.nth(n - 1)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def at name
|
21
|
+
values[name]
|
22
|
+
end
|
23
|
+
|
24
|
+
def set name, value
|
25
|
+
values[name] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s_with_indent str
|
29
|
+
me = @values.map { |k, v|
|
30
|
+
[str, k, "=>", v].join ' '
|
31
|
+
}.join "\n"
|
32
|
+
me + (parent ? parent.to_s_with_indent(" #{str}") : '')
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
to_s_with_indent ''
|
37
|
+
end
|
38
|
+
end
|
data/lib/nydp/literal.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Nydp
|
2
|
+
class Literal
|
3
|
+
attr_reader :expression
|
4
|
+
|
5
|
+
def initialize expression
|
6
|
+
@expression = expression
|
7
|
+
end
|
8
|
+
|
9
|
+
def lisp_apply
|
10
|
+
expression
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.build expression, bindings
|
14
|
+
new expression
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute vm
|
18
|
+
vm.push_arg expression
|
19
|
+
end
|
20
|
+
|
21
|
+
def inspect; @expression.inspect; end
|
22
|
+
def to_s ; @expression.to_s ; end
|
23
|
+
|
24
|
+
def coerce _
|
25
|
+
[_, expression]
|
26
|
+
end
|
27
|
+
|
28
|
+
def > other
|
29
|
+
other < expression
|
30
|
+
end
|
31
|
+
|
32
|
+
def < other
|
33
|
+
other > expression
|
34
|
+
end
|
35
|
+
|
36
|
+
def == other
|
37
|
+
other.is_a?(Literal) && (self.expression == other.expression)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/nydp/pair.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
class Nydp::Pair
|
2
|
+
include Nydp::Helper, Enumerable
|
3
|
+
extend Nydp::Helper
|
4
|
+
|
5
|
+
attr_accessor :car, :cdr
|
6
|
+
|
7
|
+
def initialize car, cdr
|
8
|
+
@car, @cdr = car, cdr
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.mk a, b
|
12
|
+
new a, b
|
13
|
+
end
|
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
|
19
|
+
|
20
|
+
def self.parse_list list
|
21
|
+
if sym? list.slice(-2), "."
|
22
|
+
from_list(list[0...-2], list.slice(-1))
|
23
|
+
else
|
24
|
+
from_list list
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.from_list list, last=Nydp.NIL, n=0
|
29
|
+
if n >= list.size
|
30
|
+
last
|
31
|
+
else
|
32
|
+
mk list[n], from_list(list, last, n+1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy
|
37
|
+
cons(car, cdr.copy)
|
38
|
+
end
|
39
|
+
|
40
|
+
def + other
|
41
|
+
copy.append other
|
42
|
+
end
|
43
|
+
|
44
|
+
def == other
|
45
|
+
(other.respond_to? :car) && (self.car == other.car) && (self.cdr == other.cdr)
|
46
|
+
end
|
47
|
+
|
48
|
+
def size
|
49
|
+
1 + (cdr.is_a?(Nydp::Pair) ? cdr.size : 0)
|
50
|
+
end
|
51
|
+
|
52
|
+
def each &block
|
53
|
+
yield car
|
54
|
+
cdr.each(&block) unless Nydp.NIL.is?(cdr)
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
"(#{inspect_rest})"
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
if car.is_a?(Nydp::Symbol) && car.is?(:quote)
|
63
|
+
if Nydp.NIL.is? cdr.cdr
|
64
|
+
"'#{cdr.car.to_s}"
|
65
|
+
else
|
66
|
+
"'#{cdr.to_s}"
|
67
|
+
end
|
68
|
+
else
|
69
|
+
"(#{to_s_rest})"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_s_rest
|
74
|
+
cdr_s = if cdr.is_a?(self.class)
|
75
|
+
cdr.to_s_rest
|
76
|
+
elsif Nydp.NIL.is? cdr
|
77
|
+
nil
|
78
|
+
else
|
79
|
+
". #{cdr.to_s}"
|
80
|
+
end
|
81
|
+
|
82
|
+
[car.to_s, cdr_s].compact.join " "
|
83
|
+
end
|
84
|
+
|
85
|
+
def inspect_rest
|
86
|
+
cdr_s = if cdr.is_a?(self.class)
|
87
|
+
cdr.inspect_rest
|
88
|
+
elsif cdr == Nydp.NIL
|
89
|
+
nil
|
90
|
+
else
|
91
|
+
". #{cdr.inspect}"
|
92
|
+
end
|
93
|
+
|
94
|
+
[car.inspect, cdr_s].compact.join " "
|
95
|
+
end
|
96
|
+
|
97
|
+
def append pair
|
98
|
+
if Nydp.NIL.is? self.cdr
|
99
|
+
self.cdr = pair
|
100
|
+
elsif pair? self.cdr
|
101
|
+
self.cdr.append pair
|
102
|
+
else
|
103
|
+
raise "can't append #{pair} to list #{self} : cdr is #{self.cdr.inspect}"
|
104
|
+
end
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
def repush instructions, _
|
109
|
+
instructions.push self
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
data/lib/nydp/parser.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
module Nydp
|
2
|
+
class Parser
|
3
|
+
attr_accessor :ns
|
4
|
+
|
5
|
+
def initialize ns
|
6
|
+
@ns = ns
|
7
|
+
end
|
8
|
+
|
9
|
+
def sym name
|
10
|
+
Nydp::Symbol.mk name.to_sym, ns
|
11
|
+
end
|
12
|
+
|
13
|
+
def read_list token_stream, termination_token
|
14
|
+
list = []
|
15
|
+
token = token_stream.next_token
|
16
|
+
while token != nil && token.first != termination_token
|
17
|
+
list << next_form(token, token_stream)
|
18
|
+
token = token_stream.next_token
|
19
|
+
end
|
20
|
+
Pair.parse_list list
|
21
|
+
end
|
22
|
+
|
23
|
+
def prefix_list prefix, list
|
24
|
+
case prefix
|
25
|
+
when "'"
|
26
|
+
Pair.from_list [sym(:quote), list]
|
27
|
+
when "`"
|
28
|
+
Pair.from_list [sym(:quasiquote), list]
|
29
|
+
when ","
|
30
|
+
Pair.from_list [sym(:unquote), list]
|
31
|
+
when ",@"
|
32
|
+
Pair.from_list [sym(:"unquote-splicing"), list]
|
33
|
+
else
|
34
|
+
list
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def split_sym syms, pfx
|
39
|
+
return Pair.from_list [pfx] + syms.map { |s| parse_symbol s }
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_symbol txt
|
43
|
+
case txt
|
44
|
+
when /^'(.+)$/
|
45
|
+
Pair.from_list [sym(:quote), parse_symbol($1)]
|
46
|
+
when /^`(.+)$/
|
47
|
+
Pair.from_list [sym(:quasiquote), parse_symbol($1)]
|
48
|
+
when /^,@(.+)$/
|
49
|
+
Pair.from_list [sym(:"unquote-splicing"), parse_symbol($1)]
|
50
|
+
when /^,(.+)$/
|
51
|
+
Pair.from_list [sym(:unquote), parse_symbol($1)]
|
52
|
+
else
|
53
|
+
syms = txt.to_s.split /\./
|
54
|
+
return split_sym syms, sym(:"dot-syntax") if syms.length > 1
|
55
|
+
|
56
|
+
syms = txt.split /::/
|
57
|
+
return split_sym syms, sym(:"colon-colon-syntax") if syms.length > 1
|
58
|
+
|
59
|
+
syms = txt.split /:/
|
60
|
+
return split_sym syms, sym(:"colon-syntax") if syms.length > 1
|
61
|
+
|
62
|
+
syms = txt.split /->/
|
63
|
+
return split_sym syms, sym(:"arrow-syntax") if syms.length > 1
|
64
|
+
|
65
|
+
syms = txt.split(/=>/)
|
66
|
+
return split_sym syms, sym(:"rocket-syntax") if syms.length > 1
|
67
|
+
|
68
|
+
sym txt
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def close_delimiter_for opener
|
73
|
+
case opener
|
74
|
+
when '"'
|
75
|
+
/"/
|
76
|
+
when /.*{$/
|
77
|
+
/}/
|
78
|
+
when /<<(.+)$/
|
79
|
+
Regexp.new $1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def next_form token, token_stream
|
84
|
+
return nil if token.nil?
|
85
|
+
case token.first
|
86
|
+
when :embed_suffix
|
87
|
+
Nydp.NIL
|
88
|
+
when :string_open_delim
|
89
|
+
string token_stream, token.last, close_delimiter_for(token.last)
|
90
|
+
when :left_paren
|
91
|
+
prefix_list token[1], read_list(token_stream, :right_paren)
|
92
|
+
when :symbol
|
93
|
+
parse_symbol token.last
|
94
|
+
when :comment
|
95
|
+
Pair.from_list [sym(:comment), token.last]
|
96
|
+
else
|
97
|
+
token.last
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def expression token_stream
|
102
|
+
next_form token_stream.next_token, token_stream
|
103
|
+
end
|
104
|
+
|
105
|
+
def string token_stream, open_delimiter, close_delimiter
|
106
|
+
fragments = [sym(:"string-pieces")]
|
107
|
+
string_token = token_stream.next_string_fragment(open_delimiter, close_delimiter)
|
108
|
+
fragments << string_token
|
109
|
+
while !(string_token.is_a? StringFragmentCloseToken)
|
110
|
+
fragments << expression(token_stream)
|
111
|
+
string_token = token_stream.next_string_fragment('', close_delimiter)
|
112
|
+
fragments << string_token
|
113
|
+
end
|
114
|
+
|
115
|
+
if fragments.size == 2
|
116
|
+
tok = fragments[1]
|
117
|
+
return Nydp::StringAtom.new tok.string, tok
|
118
|
+
else
|
119
|
+
return Pair.from_list fragments
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|