rubymotionlisp 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a1de2f26e9bafee531ed317c6587a690ca142e1d
4
+ data.tar.gz: 660e06658d5815c777a38489d0d4ae2f69418b52
5
+ SHA512:
6
+ metadata.gz: bab4310f94c76f0f16984e17dd31ee668c94d1ca422b6faa8677bfa092c35988eb309364f12e5c0cb361312be2b4941536742773e1af57363ac33a17e3660805
7
+ data.tar.gz: f3bc077426877f9e009f78896c16d3c09d248fd9dc60dae0bc1658c10bc918279526d0c364ed09a07ac338ca37ba0c9350d59b8fc707607e993cbd9c78b46813
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ ## Overview
2
+
3
+ RubyLisp is a relatively simple Lisp dialect based on Scheme
4
+ implimented using Ruby.
5
+
6
+ RubyLisp is a lexically scoped Lisp-1:
7
+
8
+ **Lexically scoped:**
9
+ The scope of definitions are determined by where they are made in the
10
+ lexical structure of the code. Each `lambda`, `let`, and `do` creates
11
+ a new lexical scope. From [2]:
12
+
13
+ > Here references to the established entity can occur only within
14
+ > certain program portions that are lexically (that is, textually)
15
+ > contained within the establishing construct. Typically the construct
16
+ > will have a part designated the body, and the scope of all entities
17
+ > established will be (or include) the body.
18
+
19
+ **Lisp-1:**
20
+ A Lisp where functions and variables share a single namespace. This
21
+ differs from a Lisp-2 in which functions and variables have separate
22
+ namespaces.
23
+
24
+ ## Installation
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ gem 'rubylisp'
29
+
30
+ And then execute:
31
+
32
+ $ bundle
33
+
34
+ Or install it yourself as:
35
+
36
+ $ gem install rubylisp
37
+
38
+ ## Contributing
39
+
40
+ 1. Fork it
41
+ 2. Create your feature branch (git checkout -b my-new-feature)
42
+ 3. Commit your changes (git commit -am 'Add some feature')
43
+ 4. Push to the branch (git push origin my-new-feature)
44
+ 5. Create new Pull Request
45
+
46
+ ## REPL
47
+
48
+ RubyLisp includes a very basic REPL that, as expected, lets you type
49
+ in snippets (it does not support multiline snippets) of Lisp code,
50
+ evaluates them, and prints the result.
51
+
52
+ >: rubylisp
53
+
54
+ RubyLisp REPL
55
+ > 4
56
+ 4
57
+ > (+ 2 3)
58
+ 5
59
+ > (define (fib x) (if (eq? x 0) 1 (* x (fib (- x 1)))))
60
+ <function: fib>
61
+ > (fib 4)
62
+ 24
63
+
64
+ ## Integrating
65
+
66
+
67
+ The simplist way to integrate RubyLisp is to have it parse and
68
+ evaluate strings of lisp code.
69
+
70
+ >: irb
71
+ 2.0.0-p247 :001 > require 'rubylisp'
72
+ => true
73
+ 2.0.0-p247 :002 > Lisp::Initializer.register_builtins
74
+ => ...
75
+ 2.0.0-p247 :003 > Lisp::Parser.new.parse_and_eval('(+ 1 2)').to_s
76
+ => "3"
77
+ 2.0.0-p247 :004 >
78
+
79
+ But lets say you are using rubylisp to do something more embedded such as provide an extension language to your application. It's easy to provide the Lisp runtime with functions written in Ruby that can be called from Lisp code.
80
+
81
+ to be continued...
82
+
@@ -0,0 +1,230 @@
1
+ module Lisp
2
+
3
+ class AList < Object
4
+ include Enumerable
5
+
6
+ def self.register
7
+ Primitive.register("acons") {|args, env| Lisp::AList::acons_impl(args, env) }
8
+ Primitive.register("assoc") {|args, env| Lisp::AList::assoc_impl(args, env) }
9
+ Primitive.register("rassoc") {|args, env| Lisp::AList::rassoc_impl(args, env) }
10
+ Primitive.register("dissoc") {|args, env| Lisp::AList::dissoc_impl(args, env) }
11
+ Primitive.register("zip") {|args, env| Lisp::AList::zip_impl(args, env) }
12
+ Primitive.register("alist-to-list") {|args, env| Lisp::AList::alist_to_list_impl(args, env) }
13
+ Primitive.register("list-to-alist") {|args, env| Lisp::AList::list_to_alist_impl(args, env) }
14
+ end
15
+
16
+ def self.acons_impl(args, env)
17
+ raise "acons require at least 2 or 3 arguments" unless args.length == 2 || args.length == 3
18
+ key = args.car.evaluate(env)
19
+ value = args.cadr.evaluate(env)
20
+ alist = args.length == 2 ? nil : args.caddr.evaluate(env)
21
+ alist = Lisp::AList.from_list(alist) if !alist.nil? && alist.list? && !alist.alist?
22
+ raise "the last argument to acons has to be an association list" unless alist.nil? || alist.alist?
23
+
24
+ if alist.nil?
25
+ Lisp::AList.new({key => value})
26
+ else
27
+ alist.acons(key, value)
28
+ end
29
+ end
30
+
31
+ def self.assoc_impl(args, env)
32
+ raise "assoc require 2 arguments" unless args.length == 2
33
+ key = args.car.evaluate(env)
34
+ alist = args.cadr.evaluate(env)
35
+ alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
36
+ raise "the last argument to assoc has to be an association list" unless alist.alist?
37
+ alist.assoc(key)
38
+ end
39
+
40
+ def self.rassoc_impl(args, env)
41
+ raise "assoc require 2 arguments" unless args.length == 2
42
+ value = args.car.evaluate(env)
43
+ alist = args.cadr.evaluate(env)
44
+ alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
45
+ raise "the last argument to rassoc has to be an association list" unless alist.alist?
46
+ alist.rassoc(value)
47
+ end
48
+
49
+ def self.dissoc_impl(args, env)
50
+ raise "assoc require 2 arguments" unless args.length == 2
51
+ key = args.car.evaluate(env)
52
+ alist = args.cadr.evaluate(env)
53
+ alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
54
+ raise "the last argument to dissoc has to be an association list" unless alist.alist?
55
+ alist.dissoc(key)
56
+ end
57
+
58
+ def self.zip_impl(args, env)
59
+ raise "assoc require 2 or 3arguments" unless args.length == 2 || args.length == 3
60
+ key_list = args.car.evaluate(env)
61
+ raise "the keys supplied to zip has to be a list" unless key_list.list?
62
+ value_list = args.cadr.evaluate(env)
63
+ raise "the values supplied to zip has to be a list" unless value_list.list?
64
+ raise "zip requires the same number of keys and values" unless key_list.length == value_list.length
65
+
66
+ if args.length == 3
67
+ alist = args.caddr.evaluate(env)
68
+ alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
69
+ raise "the third argument to zip has to be an association list" unless alist.alist?
70
+ alist.zip(key_list.to_a, value_list.to_a)
71
+ else
72
+ Lisp::AList.zip(key_list.to_a, value_list.to_a)
73
+ end
74
+ end
75
+
76
+ def self.alist_to_list_impl(args, env)
77
+ raise "alist-to-list requires 1 arguments" unless args.length == 1
78
+ alist = args.car.evaluate(env)
79
+ return alist if alist.list? && !alist.alist?
80
+ raise "the argument to alist-to-list has to be an association list" unless alist.alist?
81
+
82
+ alist.to_list
83
+ end
84
+
85
+ def self.list_to_alist_impl(args, env)
86
+ raise "list-to-alist requires 1 arguments" unless args.length == 1
87
+ list = args.car.evaluate(env)
88
+ raise "the argument to list-to-alist has to be a list" unless list.list?
89
+
90
+ Lisp::AList.from_list(list)
91
+ end
92
+
93
+
94
+ def initialize(h=nil)
95
+ @value = h || {}
96
+ end
97
+
98
+ def lisp_object?
99
+ true
100
+ end
101
+
102
+ def eq?(sexpr)
103
+ return false unless sexpr.alist?
104
+ @value == sexpr.value
105
+ end
106
+
107
+ def empty?
108
+ @value.empty?
109
+ end
110
+
111
+ def string?
112
+ false
113
+ end
114
+
115
+ def character?
116
+ false
117
+ end
118
+
119
+ def number?
120
+ false
121
+ end
122
+
123
+ def positive?
124
+ false
125
+ end
126
+
127
+ def zero?
128
+ false
129
+ end
130
+
131
+ def negative?
132
+ false
133
+ end
134
+
135
+ def symbol?
136
+ false
137
+ end
138
+
139
+ def primitive?
140
+ false
141
+ end
142
+
143
+ def function?
144
+ false
145
+ end
146
+
147
+ def macro?
148
+ false
149
+ end
150
+
151
+ def pair?
152
+ true
153
+ end
154
+
155
+ def list?
156
+ true
157
+ end
158
+
159
+ def alist?
160
+ true
161
+ end
162
+
163
+ def frame?
164
+ false
165
+ end
166
+
167
+ def length
168
+ return @value.length
169
+ end
170
+
171
+ def car
172
+ @value.first
173
+ end
174
+
175
+ def cdr
176
+ end
177
+
178
+ def acons(k, v)
179
+ @value[k] = v
180
+ self
181
+ end
182
+
183
+ def assoc(k)
184
+ v = @value[k]
185
+ Lisp::ConsCell.cons(k, v)
186
+ end
187
+
188
+ def rassoc(value)
189
+ @value.each do |k, v|
190
+ return Lisp::ConsCell.cons(k, v) if value == v || value.eq?(v)
191
+ end
192
+ end
193
+
194
+ def dissoc(k)
195
+ @value.delete(k)
196
+ self
197
+ end
198
+
199
+ def zip(keys, values)
200
+ keys.zip(values).each {|k, v| @value[k] = v}
201
+ self
202
+ end
203
+
204
+ def self.zip(keys, values)
205
+ self.new.zip(keys, values)
206
+ end
207
+
208
+ def self.from_list(list)
209
+ h = {}
210
+ list.each do |pair|
211
+ h[pair.car] = pair.cdr
212
+ end
213
+ self.new(h)
214
+ end
215
+
216
+ def to_list
217
+ Lisp::ConsCell.array_to_list(@value.map {|k, v| Lisp::ConsCell.cons(k, v)})
218
+ end
219
+
220
+ def to_s
221
+ to_list.to_s
222
+ end
223
+
224
+ def print_string
225
+ self.to_s
226
+ end
227
+
228
+ end
229
+
230
+ end
@@ -0,0 +1,65 @@
1
+ module Lisp
2
+
3
+ class Assignment
4
+
5
+ def self.register
6
+ Primitive.register("set!", "(set! _name_ _new-value_)\n\nThe way to assign (i.e. rebind) a symbol. `name` is the symbol to be rebound.
7
+ The `new-value` sexpr is evaluated to arrive at the new value to be bound to. Use of `set!` is frowned upon, and should not be used without thought.") do |args, env|
8
+ Lisp::Assignment::setbang_impl(args, env)
9
+ end
10
+
11
+ Primitive.register("set-car!", "(set-car! _cons-cell_ _new-value_)\n\nSet the `car` pointer of `cons-cell`.") do |args, env|
12
+ Lisp::Assignment::setcarbang_impl(args, env)
13
+ end
14
+
15
+ Primitive.register("set-cdr!", "(set-cdr! _cons-cell_ _new-value_)\n\nSet the `cdr` pointer of `cons-cell`.") do |args, env|
16
+ Lisp::Assignment::setcdrbang_impl(args, env)
17
+ end
18
+
19
+ Primitive.register("set-nth!", "(set-nth! _n_ _list-or-vector_ _new-value_)\n\nSets the `n`th element of `list-or-vector` to `new-value`.") do |args, env|
20
+ Lisp::Assignment::setnthbang_impl(args, env)
21
+ end
22
+
23
+ end
24
+
25
+
26
+ def self.setbang_impl(args, env)
27
+ sym = args.car
28
+ raise "set! requires a raw (unevaluated) symbol as it's first argument." unless sym.symbol?
29
+ value = args.cadr.evaluate(env)
30
+ env.set(sym, value)
31
+ end
32
+
33
+
34
+ def self.setcarbang_impl(args, env)
35
+ pair = args.car.evaluate(env)
36
+ raise "set-car! requires a pair as it's first argument." unless pair.pair?
37
+ value = args.cadr.evaluate(env)
38
+ pair.set_car!(value)
39
+ end
40
+
41
+
42
+ def self.setcdrbang_impl(args, env)
43
+ pair = args.car.evaluate(env)
44
+ raise "set-cdr! requires a pair as it's first argument." unless pair.pair?
45
+ value = args.cadr.evaluate(env)
46
+ pair.set_cdr!(value)
47
+ end
48
+
49
+
50
+ def self.setnthbang_impl(args, env)
51
+ raise "set-nth! requires 3 arguments." unless args.length == 3
52
+ n = args.car.evaluate(env)
53
+ raise "The first argument of set-nth! has to be an number." unless n.number?
54
+ raise "The first argument of set-nth! has to be positive." unless n.value > 0
55
+
56
+ l = args.cadr.evaluate(env)
57
+ raise "set-nth! requires a list or vector as it's first argument." unless l.list? || l.vector?
58
+ value = args.caddr.evaluate(env)
59
+ l.set_nth!(n.value, value)
60
+ l
61
+ end
62
+
63
+
64
+ end
65
+ end
@@ -0,0 +1,149 @@
1
+ module Lisp
2
+
3
+ class Atom < Object
4
+
5
+ attr_reader :value
6
+
7
+ def lisp_object?
8
+ true
9
+ end
10
+
11
+ def string?
12
+ false
13
+ end
14
+
15
+ def character?
16
+ false
17
+ end
18
+
19
+ def number?
20
+ false
21
+ end
22
+
23
+ def positive?
24
+ false
25
+ end
26
+
27
+ def zero?
28
+ false
29
+ end
30
+
31
+ def negative?
32
+ false
33
+ end
34
+
35
+ def symbol?
36
+ false
37
+ end
38
+
39
+ def pair?
40
+ false
41
+ end
42
+
43
+ def list?
44
+ false
45
+ end
46
+
47
+ def primitive?
48
+ false
49
+ end
50
+
51
+ def special?
52
+ false
53
+ end
54
+
55
+ def function?
56
+ false
57
+ end
58
+
59
+ def macro?
60
+ false
61
+ end
62
+
63
+ def object?
64
+ false
65
+ end
66
+
67
+ def class?
68
+ false
69
+ end
70
+
71
+ def alist?
72
+ false
73
+ end
74
+
75
+ def frame?
76
+ false
77
+ end
78
+
79
+ def vector?
80
+ false
81
+ end
82
+
83
+ def length
84
+ 1
85
+ end
86
+
87
+ def copy
88
+ self.class.new(self.value)
89
+ end
90
+
91
+ def eq?(sexpr)
92
+ return false if sexpr.nil?
93
+ return false if self.type != sexpr.type
94
+ self.value == sexpr.value
95
+ end
96
+
97
+ def type
98
+ :unknown
99
+ end
100
+
101
+ def evaluate(env)
102
+ self
103
+ end
104
+
105
+ def apply_to(args, env)
106
+ nil
107
+ end
108
+
109
+ def all?(&block)
110
+ false
111
+ end
112
+
113
+ def true?
114
+ true
115
+ end
116
+
117
+ def false?
118
+ false
119
+ end
120
+
121
+ def car
122
+ nil
123
+ end
124
+
125
+ def cdr
126
+ nil
127
+ end
128
+
129
+ def quoted
130
+ Lisp::ConsCell.cons(Symbol.named("quote"), self)
131
+ end
132
+
133
+ def set!(v)
134
+ end
135
+
136
+ def print_string
137
+ self.to_s
138
+ end
139
+
140
+ alias print_string_helper print_string
141
+
142
+
143
+ def doc
144
+ nil
145
+ end
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,17 @@
1
+ module Lisp
2
+
3
+ class Binding
4
+ attr_accessor :symbol, :value
5
+
6
+ def initialize(symbol, value)
7
+ @symbol = symbol
8
+ @value = value
9
+ self
10
+ end
11
+
12
+ def to_s
13
+ "#{symbol.name} -> #{value.to_s}"
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,49 @@
1
+ module Lisp
2
+
3
+ class Boolean < Atom
4
+ def self.TRUE
5
+ @true_constant ||= Boolean.new(true)
6
+ end
7
+
8
+ def self.FALSE
9
+ @false_constant ||= Boolean.new(false)
10
+ end
11
+
12
+ def self.with_value(b)
13
+ b ? self.TRUE : self.FALSE
14
+ end
15
+
16
+ def initialize(b)
17
+ @value = b
18
+ end
19
+
20
+ def type
21
+ :boolean
22
+ end
23
+
24
+ def boolean?
25
+ true
26
+ end
27
+
28
+ def to_s
29
+ return "#t" if @value
30
+ "#f"
31
+ end
32
+
33
+ def true?
34
+ @value
35
+ end
36
+
37
+ def false?
38
+ !@value
39
+ end
40
+
41
+ def negate
42
+ Lisp::Boolean.with_value(!@value)
43
+ end
44
+
45
+ end
46
+
47
+ TRUE = Boolean.TRUE
48
+ FALSE = Boolean.FALSE
49
+ end
@@ -0,0 +1,31 @@
1
+ module Lisp
2
+
3
+ class Initializer
4
+
5
+ def self.initialize_global_environment
6
+ Lisp::EnvironmentFrame.global.bind(Symbol.named("nil"), nil)
7
+ end
8
+
9
+ def self.register_builtins
10
+ Lisp::Equivalence.register
11
+ Lisp::Math.register
12
+ Lisp::Logical.register
13
+ Lisp::SpecialForms.register
14
+ Lisp::ListSupport.register
15
+ Lisp::Relational.register
16
+ Lisp::TypeChecks.register
17
+ Lisp::Assignment.register
18
+ Lisp::Testing.register
19
+ Lisp::IO.register
20
+ Lisp::AList.register
21
+ Lisp::Frame.register
22
+ Lisp::Character.register
23
+ Lisp::String.register
24
+ Lisp::NativeObject.register
25
+ Lisp::ClassObject.register
26
+ Lisp::System.register
27
+ Lisp::Vector.register
28
+ end
29
+ end
30
+
31
+ end