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.
@@ -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 .lasp files as .clj
6
+ highlighting by just setting your editor to treat `.lasp` files as `.clj`
7
7
 
8
- In this document output is shown with ;; and normal comments with ;.
8
+ In this document output is shown with `;;` and normal comments with `;`.
9
9
 
10
10
  ## Data types
11
11
 
12
- ```lisp
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
- ; Strings
22
+ ; Text
23
23
  "hello world!" ;; => "hello world!"
24
24
 
25
- ; Symbol-style strings (not its own type)
25
+ ; Symbol-style text (not its own type)
26
26
  :hey ;; => "hey"
27
27
 
28
28
  ; Lists
29
- (list 1 2 3) ;; => [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
- ```lisp
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
- ```lisp
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
- ```lisp
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
- ```lisp
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
- ```lisp
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
- ## Misc
140
+ ## If
136
141
 
137
- ```lisp
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
- (println "yep!")
146
- (println "nope!"))
147
- ;; yep!
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
- ```lisp
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
- ```lisp
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
- ```lisp
220
+ ```clojure
216
221
  ; Print one row in the pyramid
217
- (def print-row
218
- (fn (length)
219
- (println (* "#" length)))) ; We use the fact that the host platform (Ruby) can multiply strings
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
- (def print-pyramid
223
- (fn (height current-width)
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
- ```lisp
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
@@ -7,5 +7,5 @@ Lasp::load_stdlib!
7
7
  if ARGV.first
8
8
  Lasp::execute_file(ARGV.first)
9
9
  else
10
- Lasp::repl
10
+ Lasp::Repl.run
11
11
  end
@@ -1,6 +1,8 @@
1
1
  require "lasp/version"
2
- require "lasp/eval"
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
- Lasp::eval(Parser.new.parse(program), env)
17
+ Interpreter.eval(Parser.parse(program), env)
16
18
  end
17
19
 
18
20
  def load_stdlib!
@@ -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
- :println => -> (output) { puts output },
24
- :apply => -> (f, list) { f.call(*list) },
25
- :"." => -> (obj, m, *args) { obj.send(m, *args) },
26
- :require => -> (path) { Lasp::execute_file(path) },
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
@@ -1,3 +1,6 @@
1
1
  module Lasp
2
- SyntaxError = Class.new(StandardError)
2
+ LaspError = Class.new(StandardError)
3
+ SyntaxError = Class.new(LaspError)
4
+ ArgumentError = Class.new(LaspError)
5
+ NameError = Class.new(LaspError)
3
6
  end
@@ -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
@@ -1,4 +1,4 @@
1
- require "lasp/eval"
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
- Lasp::eval(body, env_with_args(args))
16
+ Interpreter.eval(body, env_with_args(args))
17
17
  end
18
18
 
19
19
  def inspect