lasp 0.6.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d33419ed01e48e150efc416ec315d24df18ee6b9
4
- data.tar.gz: 2c9c32ff5dad6abe4fab2f55fdeb0e9ab3cf36b2
3
+ metadata.gz: c6fb8d2312d17d1d15be5e17ad26569f839789b3
4
+ data.tar.gz: 7c473de16a4e3c017af92fa423ef976c04b369ce
5
5
  SHA512:
6
- metadata.gz: 9c38c3f9008608f4bec13175e7e03fe545e6767d2292fa9f3d75eca7151068c520ffe2e0e4546fc15a438adc409223a369e11b9db43ed3ea386193d8de19cb07
7
- data.tar.gz: efd637931a8d72b480384118186df5060e975e1bd1b60afac9e628060631204ddf4005f5cc0f76f93d15b5628030df1024c62130bb8cd8a58f2d4848bd693c5a
6
+ metadata.gz: b4a30a116ecfeefb43ea5f02c2dd11c4686da9d338625d70ecaa11cad37284b3de0a4e7110d80fda135da9ece294902a839b715676dfc3084eaba8863ca89c6a
7
+ data.tar.gz: 2d39bb873b1698e27f462c141185561582cf8749a8cc920b97041658b657207018ae7f28b2d485afe6c189c1ee5f63f2f80833222f4ac0f0c6a4ff9958763ab0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Läsp changelog
2
2
 
3
+ ## v0.7.0
4
+
5
+ - Arity is now enforced in function calls and will throw errors when mismatched
6
+ - Add methods to stdlib:
7
+ - `zero?`
8
+ - `list->str`
9
+ - `str->list`
10
+ - `->str`
11
+ - `reverse-str`
12
+ - `ruby-method`
13
+ - `pipe`
14
+ - REPL improvements:
15
+ - Automatically close trailing parentheses
16
+ - Change error prompt from `*>` to `!>`
17
+ - Return nil when pressing Ctrl+D (this used to cause an error)
18
+ - Many refactorings
19
+
3
20
  ## v0.6.0
4
21
 
5
22
  - `<` and `>` now return false when given a list of equal items, they all **have to** increase or decrease.
data/README.md CHANGED
@@ -78,6 +78,8 @@ Implemented as Ruby lambdas.
78
78
  - `/`
79
79
  - `<`
80
80
  - `>`
81
+ - `<=`
82
+ - `>=`
81
83
  - `=`
82
84
  - `list`
83
85
  - `head`
@@ -113,6 +115,7 @@ Implemented in Läsp itself.
113
115
  - `complement`
114
116
  - `even?`
115
117
  - `odd?`
118
+ - `zero?`
116
119
  - `len`
117
120
  - `nth`
118
121
  - `last`
@@ -126,6 +129,12 @@ Implemented in Läsp itself.
126
129
  - `range`
127
130
  - `max`
128
131
  - `min`
132
+ - `ruby-method`
133
+ - `str->list`
134
+ - `list->str`
135
+ - `->str`
136
+ - `pipe`
137
+ - `reverse-str`
129
138
 
130
139
  ## Developing
131
140
 
data/lib/lasp/eval.rb CHANGED
@@ -4,33 +4,53 @@ require "lasp/env"
4
4
  module Lasp
5
5
  module_function
6
6
 
7
- def eval(ast, env)
8
- case ast
9
- when Symbol then env.fetch(ast)
10
- when Array then eval_form(ast, env)
11
- else ast
7
+ def eval(form, env)
8
+ case form
9
+ when Symbol then env.fetch(form)
10
+ when Array then eval_form(form, env)
11
+ else form
12
12
  end
13
13
  end
14
14
 
15
15
  def eval_form(form, env)
16
16
  head, *tail = *form
17
17
 
18
- if head == :def
19
- key, value = tail
20
- env[key] = Lasp::eval(value, env)
21
- elsif head == :fn
22
- params, func = tail
23
- -> (*args) { Lasp::eval(func, env.merge(Hash[params.zip(args)])) }
24
- elsif head == :do
25
- tail.map { |form| Lasp::eval(form, env) }.last
26
- elsif head == :if
27
- conditional, true_form, false_form = tail
28
- Lasp::eval(conditional, env) ? Lasp::eval(true_form, env) : Lasp::eval(false_form, env)
29
- elsif Proc === head
30
- head.(*tail)
31
- else
32
- fn = Lasp::eval(head, env)
33
- fn.(*tail.map { |form| Lasp::eval(form, env) })
18
+ case head
19
+ when :def then def_special_form(tail, env)
20
+ when :fn then fn_special_form(tail, env)
21
+ when :do then do_special_form(tail, env)
22
+ when :if then if_special_form(tail, env)
23
+ when Proc then head.(*tail)
24
+ else call_function(head, tail, env)
34
25
  end
35
26
  end
27
+
28
+ def call_function(symbol, args, env)
29
+ fn = Lasp::eval(symbol, env)
30
+ fn.(*args.map { |form| Lasp::eval(form, env) })
31
+ end
32
+
33
+ def def_special_form(form, env)
34
+ key, value = form
35
+ env[key] = Lasp::eval(value, env)
36
+ end
37
+
38
+ def fn_special_form(form, env)
39
+ params, func = form
40
+ -> (*args) {
41
+ unless args.count == params.count
42
+ fail ArgumentError, "wrong number of arguments (#{args.count} for #{params.count})"
43
+ end
44
+ Lasp::eval(func, env.merge(Hash[params.zip(args)]))
45
+ }
46
+ end
47
+
48
+ def do_special_form(form, env)
49
+ form.map { |form| Lasp::eval(form, env) }.last
50
+ end
51
+
52
+ def if_special_form(form, env)
53
+ conditional, true_form, false_form = form
54
+ Lasp::eval(conditional, env) ? Lasp::eval(true_form, env) : Lasp::eval(false_form, env)
55
+ end
36
56
  end
data/lib/lasp/repl.rb CHANGED
@@ -10,12 +10,31 @@ module Lasp
10
10
  puts "((( Läsp v#{Lasp::VERSION} REPL (ctrl+c to exit) )))\n\n"
11
11
  loop do
12
12
  begin
13
- input = Readline.readline("lasp> ", true)
14
- result = Lasp::execute(input)
13
+ history = true
14
+ input = Readline.readline("lasp> ", history).to_s
15
+ input = autoclose_parentheses(input)
16
+ result = Lasp::execute(input)
15
17
  puts " => #{result.inspect}"
16
18
  rescue
17
- puts " *> #{$!}"
19
+ puts " !> #{$!}"
18
20
  end
19
21
  end
20
22
  end
23
+
24
+ def autoclose_parentheses(input)
25
+ num_opens = input.chars.select { |c| c == "(" }.count
26
+ num_closes = input.chars.select { |c| c == ")" }.count
27
+
28
+ if num_opens > num_closes
29
+ missing_closes = num_opens - num_closes
30
+
31
+ puts " ?> Appending #{missing_closes} missing closing parentheses:"
32
+ corrected_input = input + (")" * missing_closes)
33
+ puts " ?> #{corrected_input}"
34
+
35
+ corrected_input
36
+ else
37
+ input
38
+ end
39
+ end
21
40
  end
data/lib/lasp/stdlib.lasp CHANGED
@@ -11,7 +11,7 @@
11
11
  ; If a list is empty
12
12
  (def empty?
13
13
  (fn (coll)
14
- (= (head coll) nil)))
14
+ (= nil (head coll))))
15
15
 
16
16
  ; Modulus
17
17
  (def mod
@@ -23,11 +23,15 @@
23
23
 
24
24
  ; If a number is even
25
25
  (def even?
26
- (fn (x) (= (mod x 2) 0)))
26
+ (fn (x) (zero? (mod x 2))))
27
27
 
28
28
  ; If a number is odd
29
29
  (def odd? (complement even?))
30
30
 
31
+ ; If a number is zero
32
+ (def zero?
33
+ (fn (x) (= 0 x)))
34
+
31
35
  ; Length of a list
32
36
  (def len
33
37
  (fn (coll)
@@ -38,7 +42,7 @@
38
42
  ; Gets an item in a list by index
39
43
  (def nth
40
44
  (fn (index coll)
41
- (if (= 0 index)
45
+ (if (zero? index)
42
46
  (head coll)
43
47
  (nth (dec index) (tail coll)))))
44
48
 
@@ -85,14 +89,14 @@
85
89
  ; Take x items from list
86
90
  (def take
87
91
  (fn (num coll)
88
- (if (= num 0)
92
+ (if (zero? num)
89
93
  (list)
90
94
  (cons (head coll) (take (dec num) (tail coll))))))
91
95
 
92
96
  ; Drop x items from list
93
97
  (def drop
94
98
  (fn (num coll)
95
- (if (= num 0)
99
+ (if (zero? num)
96
100
  coll
97
101
  (drop (dec num) (tail coll)))))
98
102
 
@@ -118,3 +122,30 @@
118
122
  (fn (acc item) (if (> acc item) item acc))
119
123
  (head coll)
120
124
  (tail coll))))
125
+
126
+ ; Takes a method from Ruby-land and returns a Lasp function
127
+ (def ruby-method
128
+ (fn (meth)
129
+ (fn (arg)
130
+ (. arg meth))))
131
+
132
+ ; Convert string to list
133
+ (def str->list (ruby-method :chars))
134
+
135
+ ; Convert list to string
136
+ (def list->str (ruby-method :join))
137
+
138
+ ; Convert most things to a string
139
+ (def ->str (ruby-method :to_s))
140
+
141
+ ; Pass a value in order through a list of functions
142
+ (def pipe
143
+ (fn (item fns)
144
+ (if (empty? fns)
145
+ item
146
+ (pipe ((head fns) item) (tail fns)))))
147
+
148
+ ; Reverses a string
149
+ (def reverse-str
150
+ (fn (str)
151
+ (pipe str (list str->list reverse list->str))))
data/lib/lasp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lasp
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lasp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jimmy Börjesson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-17 00:00:00.000000000 Z
11
+ date: 2016-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler