rubymotionlisp 0.1.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.
- checksums.yaml +7 -0
- data/README.md +82 -0
- data/lib/rubylisp/alist.rb +230 -0
- data/lib/rubylisp/assignment.rb +65 -0
- data/lib/rubylisp/atom.rb +149 -0
- data/lib/rubylisp/binding.rb +17 -0
- data/lib/rubylisp/boolean.rb +49 -0
- data/lib/rubylisp/builtins.rb +31 -0
- data/lib/rubylisp/character.rb +383 -0
- data/lib/rubylisp/cons_cell.rb +255 -0
- data/lib/rubylisp/environment_frame.rb +116 -0
- data/lib/rubylisp/equivalence.rb +118 -0
- data/lib/rubylisp/exception.rb +98 -0
- data/lib/rubylisp/ext.rb +122 -0
- data/lib/rubylisp/ffi_class.rb +162 -0
- data/lib/rubylisp/ffi_new.rb +32 -0
- data/lib/rubylisp/ffi_send.rb +83 -0
- data/lib/rubylisp/ffi_static.rb +22 -0
- data/lib/rubylisp/frame.rb +284 -0
- data/lib/rubylisp/function.rb +92 -0
- data/lib/rubylisp/io.rb +74 -0
- data/lib/rubylisp/list_support.rb +527 -0
- data/lib/rubylisp/logical.rb +38 -0
- data/lib/rubylisp/macro.rb +95 -0
- data/lib/rubylisp/math.rb +403 -0
- data/lib/rubylisp/number.rb +63 -0
- data/lib/rubylisp/object.rb +62 -0
- data/lib/rubylisp/parser.rb +189 -0
- data/lib/rubylisp/primitive.rb +45 -0
- data/lib/rubylisp/relational.rb +46 -0
- data/lib/rubylisp/special_forms.rb +454 -0
- data/lib/rubylisp/string.rb +841 -0
- data/lib/rubylisp/symbol.rb +56 -0
- data/lib/rubylisp/system.rb +19 -0
- data/lib/rubylisp/testing.rb +136 -0
- data/lib/rubylisp/tokenizer.rb +292 -0
- data/lib/rubylisp/type_checks.rb +58 -0
- data/lib/rubylisp/vector.rb +114 -0
- data/lib/rubylisp.rb +1 -0
- data/lib/rubymotionlisp.rb +12 -0
- metadata +82 -0
@@ -0,0 +1,189 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Parser
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
end
|
7
|
+
|
8
|
+
def make_number(str)
|
9
|
+
Lisp::Number.with_value(str.to_i)
|
10
|
+
end
|
11
|
+
|
12
|
+
def make_hex_number(str)
|
13
|
+
Lisp::Number.with_value(str.gsub("#x", "0x").to_i(0))
|
14
|
+
end
|
15
|
+
|
16
|
+
def make_float(str)
|
17
|
+
Lisp::Number.with_value(str.to_f)
|
18
|
+
end
|
19
|
+
|
20
|
+
def make_string(str)
|
21
|
+
Lisp::String.with_value(str[1...-1])
|
22
|
+
end
|
23
|
+
|
24
|
+
def make_symbol(str)
|
25
|
+
Lisp::Symbol.named(str)
|
26
|
+
end
|
27
|
+
|
28
|
+
def make_character(ch)
|
29
|
+
Lisp::Character.with_value(ch)
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_cons_cell(tokens)
|
33
|
+
tok, lit = tokens.next_token
|
34
|
+
if tok == :RPAREN
|
35
|
+
tokens.consume_token
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
car = nil
|
40
|
+
cdr = nil
|
41
|
+
cells = []
|
42
|
+
while tok != :RPAREN
|
43
|
+
if tok == :PERIOD
|
44
|
+
tokens.consume_token
|
45
|
+
cdr = self.parse_sexpr(tokens)
|
46
|
+
return nil if tokens.next_token[0] == :EOF
|
47
|
+
tok, lit = tokens.next_token
|
48
|
+
raise "Expected ')' on line #{tokens.line_number}" if tok != :RPAREN
|
49
|
+
tokens.consume_token
|
50
|
+
return Lisp::ConsCell.array_to_list(cells, cdr)
|
51
|
+
else
|
52
|
+
car = self.parse_sexpr(tokens)
|
53
|
+
raise "Unexpected EOF (expected closing parenthesis) on line #{tokens.line_number}" if tokens.next_token[0] == :EOF
|
54
|
+
cells << car
|
55
|
+
end
|
56
|
+
tok, lit = tokens.next_token
|
57
|
+
end
|
58
|
+
|
59
|
+
tokens.consume_token
|
60
|
+
return Lisp::ConsCell.array_to_list(cells)
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_map(tokens)
|
64
|
+
m = {}
|
65
|
+
tok, lit = tokens.next_token
|
66
|
+
if tok == :RBRACE
|
67
|
+
tokens.consume_token
|
68
|
+
return ConsCell.cons(Symbol.named("make-frame"), nil)
|
69
|
+
end
|
70
|
+
|
71
|
+
cells = []
|
72
|
+
while tok != :RBRACE
|
73
|
+
item = self.parse_sexpr(tokens)
|
74
|
+
raise "Unexpected EOF (expected closing brace) on line #{tokens.line_number}" if tokens.next_token[0] == :EOF
|
75
|
+
cells << item
|
76
|
+
tok, lit = tokens.next_token
|
77
|
+
end
|
78
|
+
|
79
|
+
tokens.consume_token
|
80
|
+
return ConsCell.cons(Symbol.named("make-frame"), ConsCell.array_to_list(cells))
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def parse_vector(tokens)
|
85
|
+
v = []
|
86
|
+
tok, lit = tokens.next_token
|
87
|
+
if tok == :RBRACKET
|
88
|
+
tokens.consume_token
|
89
|
+
return ConsCell.cons(Symbol.named("make-vector"), nil)
|
90
|
+
end
|
91
|
+
|
92
|
+
cells = []
|
93
|
+
while tok != :RBRACKET
|
94
|
+
item = self.parse_sexpr(tokens)
|
95
|
+
raise "Unexpected EOF (expected closing bracket) on line #{tokens.line_number}" if tokens.next_token[0] == :EOF
|
96
|
+
cells << item
|
97
|
+
tok, lit = tokens.next_token
|
98
|
+
end
|
99
|
+
|
100
|
+
tokens.consume_token
|
101
|
+
return ConsCell.cons(Symbol.named("make-vector"), ConsCell.array_to_list(cells))
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def parse_sexpr(tokens)
|
106
|
+
while true
|
107
|
+
tok, lit = tokens.next_token
|
108
|
+
#puts "token: <#{tok}, #{lit}>"
|
109
|
+
return nil if tok == :EOF
|
110
|
+
tokens.consume_token
|
111
|
+
case tok
|
112
|
+
when :COMMENT
|
113
|
+
next
|
114
|
+
when :NUMBER
|
115
|
+
return make_number(lit)
|
116
|
+
when :FLOAT
|
117
|
+
return make_float(lit)
|
118
|
+
when :HEXNUMBER
|
119
|
+
return make_hex_number(lit)
|
120
|
+
when :STRING
|
121
|
+
return make_string(lit)
|
122
|
+
when :CHARACTER
|
123
|
+
return make_character(lit)
|
124
|
+
when :LPAREN
|
125
|
+
return parse_cons_cell(tokens)
|
126
|
+
when :LBRACE
|
127
|
+
return parse_map(tokens)
|
128
|
+
when :LBRACKET
|
129
|
+
return parse_vector(tokens)
|
130
|
+
when :SYMBOL
|
131
|
+
return make_symbol(lit)
|
132
|
+
when :FFI_NEW_SYMBOL
|
133
|
+
return FfiNew.new(lit)
|
134
|
+
when :FFI_SEND_SYMBOL
|
135
|
+
return FfiSend.new(lit)
|
136
|
+
when :FFI_STATIC_SYMBOL
|
137
|
+
return FfiStatic.new(lit)
|
138
|
+
when :FALSE
|
139
|
+
return Lisp::FALSE
|
140
|
+
when :TRUE
|
141
|
+
return Lisp::TRUE
|
142
|
+
when :QUOTE
|
143
|
+
expr = parse_sexpr(tokens)
|
144
|
+
return ConsCell.array_to_list([Symbol.named('quote'), expr])
|
145
|
+
when :BACKQUOTE
|
146
|
+
expr = parse_sexpr(tokens)
|
147
|
+
return ConsCell.array_to_list([Symbol.named('quasiquote'), expr])
|
148
|
+
when :COMMA
|
149
|
+
expr = parse_sexpr(tokens)
|
150
|
+
return ConsCell.array_to_list([Symbol.named('unquote'), expr])
|
151
|
+
when :COMMAAT
|
152
|
+
expr = parse_sexpr(tokens)
|
153
|
+
return ConsCell.array_to_list([Symbol.named('unquote-splicing'), expr])
|
154
|
+
when :ILLEGAL
|
155
|
+
raise "Illegal token: #{lit} on line #{tokens.line_number}"
|
156
|
+
else
|
157
|
+
return make_symbol(lit)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def parse(src)
|
163
|
+
tokenizer = Tokenizer.new(src)
|
164
|
+
tokenizer.init
|
165
|
+
|
166
|
+
sexpr = self.parse_sexpr(tokenizer)
|
167
|
+
return sexpr
|
168
|
+
end
|
169
|
+
|
170
|
+
def parse_and_eval(src, env=Lisp::EnvironmentFrame.global)
|
171
|
+
sexpr = self.parse(src)
|
172
|
+
return sexpr.evaluate(env)
|
173
|
+
end
|
174
|
+
|
175
|
+
def parse_and_eval_all(src, env=Lisp::EnvironmentFrame.global)
|
176
|
+
tokenizer = Tokenizer.new(src)
|
177
|
+
tokenizer.init
|
178
|
+
result = nil
|
179
|
+
until tokenizer.eof?
|
180
|
+
sexpr = self.parse_sexpr(tokenizer)
|
181
|
+
result = sexpr.evaluate(env)
|
182
|
+
end
|
183
|
+
result
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Primitive < Atom
|
4
|
+
|
5
|
+
attr_reader :doc
|
6
|
+
|
7
|
+
def self.register(name, doc="", special=false, env=Lisp::EnvironmentFrame.global, &implementation)
|
8
|
+
instance = self.new(name, doc, special, &implementation)
|
9
|
+
env.bind(Symbol.named(name), instance)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(name, doc, special, &implementation)
|
13
|
+
@name = name
|
14
|
+
@doc = doc
|
15
|
+
@special = special
|
16
|
+
@implementation = implementation
|
17
|
+
end
|
18
|
+
|
19
|
+
def apply_to(args, env)
|
20
|
+
@implementation.call(args, env)
|
21
|
+
end
|
22
|
+
|
23
|
+
def apply_to_without_evaluating(args, env)
|
24
|
+
@implementation.call(args, env)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"<prim: #{@name}>"
|
29
|
+
end
|
30
|
+
|
31
|
+
def primitive?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def special?
|
36
|
+
@special
|
37
|
+
end
|
38
|
+
|
39
|
+
def type
|
40
|
+
:primitive
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Relational
|
4
|
+
|
5
|
+
def self.register
|
6
|
+
Primitive.register("<", "(< number number)\n\nReturns whether the first argument is less than the second argument.") do |args, env|
|
7
|
+
Lisp::Relational::lt_impl(args, env)
|
8
|
+
end
|
9
|
+
|
10
|
+
Primitive.register(">", "(> number number)\n\nReturns whether the first argument is greater than the second argument.") do |args, env|
|
11
|
+
Lisp::Relational::gt_impl(args, env)
|
12
|
+
end
|
13
|
+
|
14
|
+
Primitive.register("<=", "(<= number number)\n\nReturns whether the first argument is less than or equal to the second argument.") do |args, env|
|
15
|
+
Lisp::Relational::lteq_impl(args, env)
|
16
|
+
end
|
17
|
+
|
18
|
+
Primitive.register(">=", "(>= number number)\n\nReturns whether the first argument is greater than or equal to the second argument.") do |args, env|
|
19
|
+
Lisp::Relational::gteq_impl(args, env)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def self.lt_impl(args, env)
|
25
|
+
raise "< needs at least 2 arguments" unless args.length > 1
|
26
|
+
return Lisp::Boolean.with_value(args.car.evaluate(env).value < args.cadr.evaluate(env).value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.gt_impl(args, env)
|
30
|
+
raise "> needs at least 2 arguments" unless args.length > 1
|
31
|
+
return Lisp::Boolean.with_value(args.car.evaluate(env).value > args.cadr.evaluate(env).value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.lteq_impl(args, env)
|
35
|
+
raise "<= needs at least 2 arguments" unless args.length > 1
|
36
|
+
return Lisp::Boolean.with_value(args.car.evaluate(env).value <= args.cadr.evaluate(env).value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.gteq_impl(args, env)
|
40
|
+
raise ">= needs at least 2 arguments" unless args.length > 1
|
41
|
+
return Lisp::Boolean.with_value(args.car.evaluate(env).value >= args.cadr.evaluate(env).value)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|