lasp 0.8.0 → 0.9.0
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 +4 -4
- data/CHANGELOG.md +30 -0
- data/DOCUMENTATION.md +942 -0
- data/EXAMPLES.md +57 -34
- data/README.md +7 -92
- data/bin/lasp +1 -1
- data/lib/lasp.rb +4 -2
- data/lib/lasp/corelib.rb +24 -22
- data/lib/lasp/errors.rb +4 -1
- data/lib/lasp/ext.rb +33 -0
- data/lib/lasp/fn.rb +2 -2
- data/lib/lasp/interpreter.rb +79 -0
- data/lib/lasp/params.rb +17 -8
- data/lib/lasp/parser.rb +22 -12
- data/lib/lasp/repl.rb +50 -29
- data/lib/lasp/stdlib.lasp +113 -109
- data/lib/lasp/stdmacros.lasp +31 -0
- data/lib/lasp/version.rb +1 -1
- metadata +5 -5
- data/lib/lasp/eval.rb +0 -66
- data/lib/lasp/parameters.rb +0 -93
- data/lib/lasp/representation.rb +0 -17
data/EXAMPLES.md
CHANGED
@@ -3,13 +3,13 @@
|
|
3
3
|
A complete list of the available functions can be found in the README.
|
4
4
|
|
5
5
|
Since Läsp is very similar to Clojure, you can get pretty decent syntax
|
6
|
-
highlighting by just setting your editor to treat
|
6
|
+
highlighting by just setting your editor to treat `.lasp` files as `.clj`
|
7
7
|
|
8
|
-
In this document output is shown with
|
8
|
+
In this document output is shown with `;;` and normal comments with `;`.
|
9
9
|
|
10
10
|
## Data types
|
11
11
|
|
12
|
-
```
|
12
|
+
```clojure
|
13
13
|
; Number types
|
14
14
|
1
|
15
15
|
1.5
|
@@ -19,23 +19,28 @@ true
|
|
19
19
|
false
|
20
20
|
nil
|
21
21
|
|
22
|
-
;
|
22
|
+
; Text
|
23
23
|
"hello world!" ;; => "hello world!"
|
24
24
|
|
25
|
-
; Symbol-style
|
25
|
+
; Symbol-style text (not its own type)
|
26
26
|
:hey ;; => "hey"
|
27
27
|
|
28
28
|
; Lists
|
29
|
-
(list 1 2 3) ;; =>
|
30
|
-
(list) ;; =>
|
29
|
+
(list 1 2 3) ;; => (1 2 3)
|
30
|
+
(list) ;; => ()
|
31
31
|
```
|
32
32
|
|
33
33
|
## Basic function calls
|
34
34
|
|
35
|
-
```
|
35
|
+
```clojure
|
36
36
|
; inc is a function that increments its argument, and 1 is the single argument
|
37
37
|
(inc 1) ;; => 2
|
38
38
|
|
39
|
+
; Outputting to the terminal
|
40
|
+
(println "hello world!")
|
41
|
+
;; hello world!
|
42
|
+
;; => nil
|
43
|
+
|
39
44
|
; Simple maths functions take any number of arguments
|
40
45
|
(/ 20 2) ;; => 10
|
41
46
|
(+ 1 3 5) ;; => 9
|
@@ -52,7 +57,7 @@ nil
|
|
52
57
|
|
53
58
|
## List operations
|
54
59
|
|
55
|
-
```
|
60
|
+
```clojure
|
56
61
|
(head (list 1 2 3)) ;; => 1
|
57
62
|
(first (list 1 2 3)) ;; => 1
|
58
63
|
|
@@ -86,7 +91,7 @@ nil
|
|
86
91
|
|
87
92
|
## Dictionaries
|
88
93
|
|
89
|
-
```
|
94
|
+
```clojure
|
90
95
|
; Create a dict
|
91
96
|
(dict :one 1 :two 2) ;; => {"one" 1, "two" 2}
|
92
97
|
|
@@ -102,7 +107,7 @@ nil
|
|
102
107
|
|
103
108
|
## More complex functions
|
104
109
|
|
105
|
-
```
|
110
|
+
```clojure
|
106
111
|
; Apply a function to all items in a list
|
107
112
|
(map inc (list 1 2 3)) ;; => (2 3 4)
|
108
113
|
|
@@ -123,7 +128,7 @@ nil
|
|
123
128
|
|
124
129
|
## Variables
|
125
130
|
|
126
|
-
```
|
131
|
+
```clojure
|
127
132
|
; Define and evaluate a variable
|
128
133
|
(def x (list 1 2 3))
|
129
134
|
x ;; => (1 2 3)
|
@@ -132,20 +137,13 @@ x ;; => (1 2 3)
|
|
132
137
|
(sum x) ;; => 6
|
133
138
|
```
|
134
139
|
|
135
|
-
##
|
140
|
+
## If
|
136
141
|
|
137
|
-
```
|
138
|
-
; Outputting to the terminal
|
139
|
-
(println "hello world!")
|
140
|
-
;; hello world!
|
141
|
-
;; => nil
|
142
|
-
|
143
|
-
; If
|
142
|
+
```clojure
|
144
143
|
(if (< 4.9 5)
|
145
|
-
|
146
|
-
|
147
|
-
;;
|
148
|
-
;; => nil
|
144
|
+
"under"
|
145
|
+
"over")
|
146
|
+
;; => "under"
|
149
147
|
|
150
148
|
(if (< 5.1 5)
|
151
149
|
(println "yep!")
|
@@ -156,7 +154,7 @@ x ;; => (1 2 3)
|
|
156
154
|
|
157
155
|
## Creating functions
|
158
156
|
|
159
|
-
```
|
157
|
+
```clojure
|
160
158
|
; A function has 2 forms, one with the parameters and one with the body.
|
161
159
|
; Here's a function that adds 10 to its argument
|
162
160
|
(fn (x) (+ 10 x))
|
@@ -192,11 +190,18 @@ x ;; => (1 2 3)
|
|
192
190
|
(add-first-two 1 2) ;; => 3
|
193
191
|
(add-first-two 1 2 3) ;; => 3
|
194
192
|
(add-first-two 1) ;; !> wrong number of arguments (1 for 2+)
|
193
|
+
|
194
|
+
|
195
|
+
; Defining a function is a very common thing to do, therefore there is a shorthand.
|
196
|
+
; This will do the same thing as the example above:
|
197
|
+
(defn add-first-two
|
198
|
+
(a b & args)
|
199
|
+
(+ a b))
|
195
200
|
```
|
196
201
|
|
197
202
|
### Count the amount of 5:s in a list
|
198
203
|
|
199
|
-
```
|
204
|
+
```clojure
|
200
205
|
; The list we will operate on
|
201
206
|
(def fives (list 1 5 2 3 5 8 5)) ; 5 occurs 3 times.
|
202
207
|
|
@@ -212,20 +217,20 @@ x ;; => (1 2 3)
|
|
212
217
|
|
213
218
|
### Print a beautiful pyramid
|
214
219
|
|
215
|
-
```
|
220
|
+
```clojure
|
216
221
|
; Print one row in the pyramid
|
217
|
-
(
|
218
|
-
(
|
219
|
-
|
222
|
+
(defn print-row
|
223
|
+
(length)
|
224
|
+
(println (* "#" length))) ; We use the fact that the host platform (Ruby) can multiply text
|
220
225
|
|
221
226
|
; Print the entire pyramid
|
222
|
-
(
|
223
|
-
(
|
227
|
+
(defn print-pyramid
|
228
|
+
(height current-width)
|
224
229
|
(if (= current-width height)
|
225
230
|
nil
|
226
231
|
(do
|
227
232
|
(print-row current-width)
|
228
|
-
(print-pyramid height (inc current-width)))))
|
233
|
+
(print-pyramid height (inc current-width)))))
|
229
234
|
|
230
235
|
; Do it!
|
231
236
|
(print-pyramid 10 1)
|
@@ -242,10 +247,28 @@ x ;; => (1 2 3)
|
|
242
247
|
|
243
248
|
## Interoperability
|
244
249
|
|
245
|
-
```
|
250
|
+
```clojure
|
246
251
|
; The . function allows for Ruby interoperability.
|
247
252
|
(. "01011101" :to_i 2) ;; => 93
|
248
253
|
|
249
254
|
(def parse_binary (fn (bin) (. bin :to_i 2)))
|
250
255
|
(parse_binary "01011101") ;; => 93
|
251
256
|
```
|
257
|
+
|
258
|
+
## Macros
|
259
|
+
|
260
|
+
Since Läsp code is just lists, it is quite easy to write code that restructures
|
261
|
+
those lists before they are executed - this is what macros do. If you would
|
262
|
+
like to make a function that takes a form that performs maths in a more natural
|
263
|
+
order like `(1 + 2)`, then you can accomplish it with macros:
|
264
|
+
|
265
|
+
```clojure
|
266
|
+
(def infix
|
267
|
+
(macro (form)
|
268
|
+
(list (second form) (first form) (last form))))
|
269
|
+
|
270
|
+
; This will be restructured to `(+ 4 5)` before it is run.
|
271
|
+
(infix (4 + 5)) ; => 9
|
272
|
+
```
|
273
|
+
|
274
|
+
Refer to the [macro](DOCUMENTATION.md#macro) section in the documentation for a more detailed explanation.
|
data/README.md
CHANGED
@@ -19,6 +19,10 @@ gem install lasp
|
|
19
19
|
|
20
20
|
# If it doesn't work you might need to sudo
|
21
21
|
sudo gem install lasp
|
22
|
+
|
23
|
+
# You can update to the latest version the same way:
|
24
|
+
gem update lasp
|
25
|
+
sudo gem update lasp
|
22
26
|
```
|
23
27
|
|
24
28
|
## Running
|
@@ -35,6 +39,9 @@ lasp path/to/program.lasp
|
|
35
39
|
|
36
40
|
## The language
|
37
41
|
|
42
|
+
Please reference the [documentation](DOCUMENTATION.md) for specific definitions
|
43
|
+
and examples of all available functions.
|
44
|
+
|
38
45
|
### Examples
|
39
46
|
|
40
47
|
More advanced examples can be found in [EXAMPLES.md](EXAMPLES.md), you can also
|
@@ -53,17 +60,6 @@ x ;; => 6
|
|
53
60
|
(inc 5) ;; => 6
|
54
61
|
```
|
55
62
|
|
56
|
-
### Data types
|
57
|
-
|
58
|
-
Supports these datatypes (implemented as their Ruby counterparts)
|
59
|
-
|
60
|
-
- integer
|
61
|
-
- float
|
62
|
-
- boolean
|
63
|
-
- nil
|
64
|
-
- string
|
65
|
-
- list
|
66
|
-
- dict
|
67
63
|
|
68
64
|
### Comments
|
69
65
|
|
@@ -74,87 +70,6 @@ Comments start with a `;` and end at the end of a line
|
|
74
70
|
(+ 1 2) ; This is also a comment
|
75
71
|
```
|
76
72
|
|
77
|
-
### Functions in corelib
|
78
|
-
|
79
|
-
Implemented as Ruby lambdas.
|
80
|
-
|
81
|
-
- `+`
|
82
|
-
- `-`
|
83
|
-
- `*`
|
84
|
-
- `/`
|
85
|
-
- `<`
|
86
|
-
- `>`
|
87
|
-
- `<=`
|
88
|
-
- `>=`
|
89
|
-
- `=`
|
90
|
-
- `list`
|
91
|
-
- `head`
|
92
|
-
- `tail`
|
93
|
-
- `cons`
|
94
|
-
- `dict`
|
95
|
-
- `get`
|
96
|
-
- `assoc`
|
97
|
-
- `dissoc`
|
98
|
-
- `not`
|
99
|
-
- `println`
|
100
|
-
- `apply`
|
101
|
-
- `.`
|
102
|
-
- `require`
|
103
|
-
|
104
|
-
### Special forms
|
105
|
-
|
106
|
-
Implemented as special cases while evaluating.
|
107
|
-
|
108
|
-
- `def`
|
109
|
-
- `fn`
|
110
|
-
- `do`
|
111
|
-
- `if`
|
112
|
-
- `quote`
|
113
|
-
- `macro`
|
114
|
-
|
115
|
-
### Functions in stdlib
|
116
|
-
|
117
|
-
Implemented in Läsp itself.
|
118
|
-
|
119
|
-
- `first` (alias of `head`)
|
120
|
-
- `rest` (alias of `tail`)
|
121
|
-
- `inc`
|
122
|
-
- `dec`
|
123
|
-
- `nil?`
|
124
|
-
- `empty?`
|
125
|
-
- `not=`
|
126
|
-
- `second`
|
127
|
-
- `mod`
|
128
|
-
- `complement`
|
129
|
-
- `even?`
|
130
|
-
- `odd?`
|
131
|
-
- `zero?`
|
132
|
-
- `len`
|
133
|
-
- `nth`
|
134
|
-
- `last`
|
135
|
-
- `reverse`
|
136
|
-
- `map`
|
137
|
-
- `reduce`
|
138
|
-
- `filter`
|
139
|
-
- `sum`
|
140
|
-
- `take`
|
141
|
-
- `drop`
|
142
|
-
- `range`
|
143
|
-
- `max`
|
144
|
-
- `min`
|
145
|
-
- `ruby-method`
|
146
|
-
- `str->list`
|
147
|
-
- `list->str`
|
148
|
-
- `->str`
|
149
|
-
- `pipe`
|
150
|
-
- `reverse-str`
|
151
|
-
|
152
|
-
## Macros in stdlib
|
153
|
-
|
154
|
-
- `defn`
|
155
|
-
- `defm`
|
156
|
-
- `macroexpand`
|
157
|
-
|
158
73
|
## Developing
|
159
74
|
|
160
75
|
### Run the specs
|
data/bin/lasp
CHANGED
data/lib/lasp.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require "lasp/version"
|
2
|
-
require "lasp/
|
2
|
+
require "lasp/env"
|
3
3
|
require "lasp/parser"
|
4
|
+
require "lasp/interpreter"
|
5
|
+
require "lasp/ext"
|
4
6
|
|
5
7
|
module Lasp
|
6
8
|
STDLIB_PATH = File.expand_path("../lasp/stdlib.lasp", __FILE__)
|
@@ -12,7 +14,7 @@ module Lasp
|
|
12
14
|
end
|
13
15
|
|
14
16
|
def execute(program, env = global_env)
|
15
|
-
|
17
|
+
Interpreter.eval(Parser.parse(program), env)
|
16
18
|
end
|
17
19
|
|
18
20
|
def load_stdlib!
|
data/lib/lasp/corelib.rb
CHANGED
@@ -2,27 +2,29 @@ require "lasp"
|
|
2
2
|
|
3
3
|
module Lasp
|
4
4
|
CORELIB = {
|
5
|
-
:+ => -> (*args) { args.reduce(:+)
|
6
|
-
:- => -> (*args) { args.reduce(:-)
|
7
|
-
:* => -> (*args) { args.reduce(:*)
|
8
|
-
:/ => -> (*args) { args.reduce(:/)
|
9
|
-
:< => -> (*args) { args.each_cons(2).all? { |a, b| a < b
|
10
|
-
:> => -> (*args) { args.each_cons(2).all? { |a, b| a > b
|
11
|
-
:<= => -> (*args) { args.each_cons(2).all? { |a, b| a <= b }
|
12
|
-
:>= => -> (*args) { args.each_cons(2).all? { |a, b| a >= b }
|
13
|
-
:"=" => -> (*args) { args.uniq.count == 1
|
14
|
-
:list => -> (*args) { args
|
15
|
-
:head => -> (list) { list.first
|
16
|
-
:tail => -> (list) { list.drop(1)
|
17
|
-
:cons => -> (item, list) { [item] + list
|
18
|
-
:dict => -> (*args) { Hash[*args]
|
19
|
-
:get => -> (key, a) { a[key]
|
20
|
-
:assoc => -> (a, key, val) { a.dup.tap { |a| a[key] = val }
|
21
|
-
:dissoc => -> (a, key) { a.dup.tap { |a| a.delete(key) }
|
22
|
-
:not => -> (arg) { !arg
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
5
|
+
:+ => -> (*args) { args.reduce(:+) },
|
6
|
+
:- => -> (*args) { args.reduce(:-) },
|
7
|
+
:* => -> (*args) { args.reduce(:*) },
|
8
|
+
:/ => -> (*args) { args.reduce(:/) },
|
9
|
+
:< => -> (*args) { args.each_cons(2).all? { |a, b| a < b } },
|
10
|
+
:> => -> (*args) { args.each_cons(2).all? { |a, b| a > b } },
|
11
|
+
:<= => -> (*args) { args.each_cons(2).all? { |a, b| a <= b } },
|
12
|
+
:>= => -> (*args) { args.each_cons(2).all? { |a, b| a >= b } },
|
13
|
+
:"=" => -> (*args) { args.uniq.count == 1 },
|
14
|
+
:list => -> (*args) { args },
|
15
|
+
:head => -> (list) { list.first },
|
16
|
+
:tail => -> (list) { list.drop(1) },
|
17
|
+
:cons => -> (item, list) { [item] + list },
|
18
|
+
:dict => -> (*args) { Hash[*args] },
|
19
|
+
:get => -> (key, a) { a[key] },
|
20
|
+
:assoc => -> (a, key, val) { a.dup.tap { |a| a[key] = val } },
|
21
|
+
:dissoc => -> (a, key) { a.dup.tap { |a| a.delete(key) } },
|
22
|
+
:not => -> (arg) { !arg },
|
23
|
+
:print => -> (output) { STDOUT.print(output) },
|
24
|
+
:println => -> (output) { STDOUT.puts(output) },
|
25
|
+
:readln => -> () { STDIN.gets.chomp },
|
26
|
+
:apply => -> (f, list) { f.call(*list) },
|
27
|
+
:"." => -> (obj, m, *args) { obj.send(m, *args) },
|
28
|
+
:require => -> (p) { execute_file(File.expand_path(p, __dir__)) },
|
27
29
|
}
|
28
30
|
end
|
data/lib/lasp/errors.rb
CHANGED
data/lib/lasp/ext.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class Array
|
2
|
+
def to_s
|
3
|
+
"(#{ map(&:inspect).join(" ") })"
|
4
|
+
end
|
5
|
+
|
6
|
+
def inspect
|
7
|
+
to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(index)
|
11
|
+
self[index]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Hash
|
16
|
+
def to_s
|
17
|
+
"{#{ map { |pair| pair.map(&:inspect).join(" ") }.join(", ") }}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(index)
|
25
|
+
self[index]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Symbol
|
30
|
+
def inspect
|
31
|
+
to_s
|
32
|
+
end
|
33
|
+
end
|
data/lib/lasp/fn.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "lasp/
|
1
|
+
require "lasp/interpreter"
|
2
2
|
require "lasp/params"
|
3
3
|
require "lasp/errors"
|
4
4
|
|
@@ -13,7 +13,7 @@ module Lasp
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def call(*args)
|
16
|
-
|
16
|
+
Interpreter.eval(body, env_with_args(args))
|
17
17
|
end
|
18
18
|
|
19
19
|
def inspect
|