iode 0.0.3 → 0.0.4
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 +90 -15
- data/lib/iode.rb +3 -0
- data/lib/iode/core/lists.rb +4 -0
- data/lib/iode/core/output.rb +5 -0
- data/lib/iode/core/strings.rb +31 -0
- data/lib/iode/interpreter.rb +37 -4
- data/lib/iode/lambda.rb +21 -0
- data/lib/iode/macro.rb +21 -0
- data/lib/iode/reader.rb +3 -1
- data/lib/iode/version.rb +1 -1
- metadata +21 -25
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 10252bb4757e9c4d3cdbb7177e142418f392b212
|
4
|
+
data.tar.gz: 75522eef2c8d52839309381993811fc5e365053d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a3f403e1b8149bc875d8e32f3d20745143bfbc68d55568038c4077ac1745f528f2bfc6fe33e63d659fac713c665d04db0539203ede36a0e156549d4597dc9687
|
7
|
+
data.tar.gz: efe9309b7b749a962c1456f282f1c634b611e854f82111c126d9ecb067e706ed616d4d9f87639925bd9f931cf4f4fee0b246ae3aea26de5672498a957a21add5
|
data/README.md
CHANGED
@@ -63,31 +63,106 @@ Of course, functions can be defined recursively too.
|
|
63
63
|
``` lisp
|
64
64
|
;; Recursive function example.
|
65
65
|
(def loop
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
66
|
+
(lambda (n)
|
67
|
+
(if (= n 0)
|
68
|
+
(quote done)
|
69
|
+
(progn
|
70
|
+
(puts n)
|
71
|
+
(loop (- n 1))))))
|
72
72
|
|
73
73
|
(loop 20)
|
74
74
|
```
|
75
75
|
|
76
|
-
The above code will print 20 through 1 to the screen and finally return the
|
77
|
-
Symbol `:done` to Ruby (quoted Iode Symbols are also Ruby Symbols). Note that
|
78
|
-
I haven't yet done tail call elimination.
|
79
|
-
|
80
76
|
Similarly, closures can be returned from functions.
|
81
77
|
|
82
78
|
``` lisp
|
83
|
-
|
84
|
-
(
|
85
|
-
|
86
|
-
|
79
|
+
(def dec
|
80
|
+
(lambda (n)
|
81
|
+
(- n 1)))
|
82
|
+
|
83
|
+
(def expt
|
84
|
+
(lambda (n x)
|
85
|
+
(if (= x 0)
|
86
|
+
1
|
87
|
+
(* n (expt n (dec x))))))
|
88
|
+
|
89
|
+
(def make-expt-fn
|
90
|
+
(lambda (x)
|
91
|
+
(lambda (n) (expt n x))))
|
92
|
+
|
93
|
+
(def square
|
94
|
+
(make-expt-fn 2))
|
95
|
+
|
96
|
+
(def cube
|
97
|
+
(make-expt-fn 3))
|
98
|
+
|
99
|
+
(puts (square 4))
|
100
|
+
(puts (cube 4))
|
101
|
+
```
|
102
|
+
|
103
|
+
Or something that updates some internal state.
|
104
|
+
|
105
|
+
``` lisp
|
106
|
+
(def make-counter
|
107
|
+
(lambda (n)
|
108
|
+
(lambda () (set! n (inc n)))))
|
109
|
+
|
110
|
+
(def counter
|
111
|
+
(make-counter 0))
|
112
|
+
|
113
|
+
(puts (counter)) ; 1
|
114
|
+
(puts (counter)) ; 2
|
115
|
+
(puts (counter)) ; 3
|
116
|
+
(puts (counter)) ; 4
|
117
|
+
```
|
118
|
+
|
119
|
+
#### Macros
|
120
|
+
|
121
|
+
Yes, iode has macros. In fact, very powerful macros. You can think of macros in
|
122
|
+
the same way you think about lambdas. They are 100% first-class to iode and
|
123
|
+
have values that can be assigned to variables, passed into functions etc. Like
|
124
|
+
lambdas, they also provide a lexical closure over their environment. The
|
125
|
+
difference between a macro and a lambda is that a macro receives unevaluated
|
126
|
+
*code* as input and produces *code* as output.
|
127
|
+
|
128
|
+
The syntax for returning code is a little cumbersome at this point, since I
|
129
|
+
haven't yet added quasiquoting to provide that magical "templating" that lisps
|
130
|
+
offer. Lots of `list` and `quote` for now. Quasiquoting is coming, however.
|
131
|
+
|
132
|
+
Since iode doesn't yet have a `let` form, let's make our own with a macro.
|
133
|
+
|
134
|
+
``` lisp
|
135
|
+
(def cadr
|
136
|
+
(lambda (v) (car (cdr v))))
|
137
|
+
|
138
|
+
(def let
|
139
|
+
(macro (bindings body)
|
140
|
+
(list
|
141
|
+
(quote apply)
|
142
|
+
(list (quote lambda)
|
143
|
+
(map car bindings)
|
144
|
+
body)
|
145
|
+
(map cadr bindings))))
|
146
|
+
|
147
|
+
(let ((x 7)
|
148
|
+
(y 8))
|
149
|
+
(puts (* x y)))
|
150
|
+
```
|
87
151
|
|
88
|
-
|
152
|
+
Note that the body of the macro in this version must be a single s-expression,
|
153
|
+
since variadic arguments are not yet implemented in the language. You may use
|
154
|
+
a `progn`, however.
|
155
|
+
|
156
|
+
``` lisp
|
157
|
+
(let ((x 7)
|
158
|
+
(y 8))
|
159
|
+
(progn
|
160
|
+
(puts (str "x = " x))
|
161
|
+
(puts (str "y = " y))
|
162
|
+
(puts (str "x * y = " (* x y)))))
|
89
163
|
```
|
90
164
|
|
165
|
+
Macros as values are a powerful feature of iode.
|
91
166
|
|
92
167
|
### In Ruby Code
|
93
168
|
|
data/lib/iode.rb
CHANGED
@@ -18,8 +18,11 @@ require "iode/version"
|
|
18
18
|
require "iode/core/comparisons"
|
19
19
|
require "iode/core/lists"
|
20
20
|
require "iode/core/math"
|
21
|
+
require "iode/core/strings"
|
21
22
|
require "iode/core/output"
|
22
23
|
require "iode/scope"
|
24
|
+
require "iode/lambda"
|
25
|
+
require "iode/macro"
|
23
26
|
require "iode/interpreter"
|
24
27
|
require "iode/reader"
|
25
28
|
|
data/lib/iode/core/lists.rb
CHANGED
data/lib/iode/core/output.rb
CHANGED
@@ -15,6 +15,7 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
17
|
require "iode/core"
|
18
|
+
require "pp"
|
18
19
|
|
19
20
|
module Iode
|
20
21
|
module Core
|
@@ -26,6 +27,10 @@ module Iode
|
|
26
27
|
def p(*args, &block)
|
27
28
|
Kernel.p(*args, &block)
|
28
29
|
end
|
30
|
+
|
31
|
+
def pp(*args, &block)
|
32
|
+
Kernel.pp(*args, &block)
|
33
|
+
end
|
29
34
|
end
|
30
35
|
end
|
31
36
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# iode: core/lists.rb
|
2
|
+
#
|
3
|
+
# Copyright 2014 Chris Corbyn <chris@w3style.co.uk>
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module Iode
|
18
|
+
module Core
|
19
|
+
module Strings
|
20
|
+
def str(*args)
|
21
|
+
args.map(&:to_s).join
|
22
|
+
end
|
23
|
+
|
24
|
+
def format(s, *args)
|
25
|
+
s % args
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Iode::Core.register Iode::Core::Strings
|
data/lib/iode/interpreter.rb
CHANGED
@@ -63,7 +63,7 @@ module Iode
|
|
63
63
|
sexps.inject(nil){|_,s| eval(s)}
|
64
64
|
end
|
65
65
|
|
66
|
-
# Create a new lambda
|
66
|
+
# Create a new lambda.
|
67
67
|
#
|
68
68
|
# These lambdas act as closures in their environment.
|
69
69
|
#
|
@@ -73,10 +73,31 @@ module Iode
|
|
73
73
|
# @param [Object...] *sexps
|
74
74
|
# variadic list of S-Expressions for the body
|
75
75
|
#
|
76
|
-
# @return [
|
76
|
+
# @return [Lambda]
|
77
77
|
# a callable lambda
|
78
78
|
def lambda(argnames, *sexps)
|
79
|
-
|
79
|
+
Lambda.new do |*args|
|
80
|
+
Interpreter.new(
|
81
|
+
@env.push_scope(Hash[argnames.zip(args)])
|
82
|
+
).progn(*sexps)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Create a new macro.
|
87
|
+
#
|
88
|
+
# Macros are acually just a special case of lambda and also close their
|
89
|
+
# environment and can be passed as arguments.
|
90
|
+
#
|
91
|
+
# @param [Array] argnames
|
92
|
+
# a list of argument names as macro inputs
|
93
|
+
#
|
94
|
+
# @param [Object...] *sexps
|
95
|
+
# variadic list of S-Expressions for the body
|
96
|
+
#
|
97
|
+
# @return [Macro]
|
98
|
+
# a callable macro
|
99
|
+
def macro(argnames, *sexps)
|
100
|
+
Macro.new do |*args|
|
80
101
|
Interpreter.new(
|
81
102
|
@env.push_scope(Hash[argnames.zip(args)])
|
82
103
|
).progn(*sexps)
|
@@ -116,6 +137,8 @@ module Iode
|
|
116
137
|
nil
|
117
138
|
when :quote
|
118
139
|
car(cdr(sexp))
|
140
|
+
when :quasiquote
|
141
|
+
car(cdr(sexp))
|
119
142
|
when :if
|
120
143
|
if eval(car(cdr(sexp)))
|
121
144
|
eval(car(cdr(cdr(sexp))))
|
@@ -130,8 +153,18 @@ module Iode
|
|
130
153
|
@env.define(car(cdr(sexp)), eval(car(cdr(cdr(sexp)))))
|
131
154
|
when :lambda
|
132
155
|
lambda(car(cdr(sexp)), *cdr(cdr(sexp)))
|
156
|
+
when :macro
|
157
|
+
macro(car(cdr(sexp)), *cdr(cdr(sexp)))
|
158
|
+
when :apply
|
159
|
+
eval([car(cdr(sexp)), *car(cdr(cdr(sexp)))])
|
133
160
|
else
|
134
|
-
|
161
|
+
callee = eval(car(sexp))
|
162
|
+
case callee
|
163
|
+
when Macro
|
164
|
+
eval(apply(callee, cdr(sexp)))
|
165
|
+
else
|
166
|
+
apply(callee, cdr(sexp).map(&method(:eval)))
|
167
|
+
end
|
135
168
|
end
|
136
169
|
when Symbol
|
137
170
|
@env[sexp]
|
data/lib/iode/lambda.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# iode: lambda.rb
|
2
|
+
#
|
3
|
+
# Copyright 2014 Chris Corbyn <chris@w3style.co.uk>
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module Iode
|
18
|
+
# Class that represents a lambda function in iode.
|
19
|
+
class Lambda < Proc
|
20
|
+
end
|
21
|
+
end
|
data/lib/iode/macro.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# iode: macro.rb
|
2
|
+
#
|
3
|
+
# Copyright 2014 Chris Corbyn <chris@w3style.co.uk>
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module Iode
|
18
|
+
# Class that represents a macro function in iode.
|
19
|
+
class Macro < Lambda
|
20
|
+
end
|
21
|
+
end
|
data/lib/iode/reader.rb
CHANGED
@@ -28,6 +28,7 @@ module Iode
|
|
28
28
|
# syntax
|
29
29
|
rule("(")
|
30
30
|
rule(")")
|
31
|
+
rule("'")
|
31
32
|
|
32
33
|
# fractions as literals
|
33
34
|
rule(:rational => /[0-9]+\/[0-9]+/).as{|n| Rational(n)}
|
@@ -43,7 +44,7 @@ module Iode
|
|
43
44
|
end
|
44
45
|
|
45
46
|
# variables/symbols
|
46
|
-
rule(symbol: /[^\(\)\s;]+/).as do |v|
|
47
|
+
rule(symbol: /[^\(\)\s;'"`:]+/).as do |v|
|
47
48
|
case v
|
48
49
|
when "nil"
|
49
50
|
nil
|
@@ -75,6 +76,7 @@ module Iode
|
|
75
76
|
# s-exprs
|
76
77
|
rule(:sexp) do |r|
|
77
78
|
r[:atom]
|
79
|
+
r["'", :sexp].as {|_, sexp| [:quote, sexp]}
|
78
80
|
r["(", :sexp_list, ")"].as {|_, list, _| list}
|
79
81
|
end
|
80
82
|
|
data/lib/iode/version.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.4
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Chris Corbyn
|
@@ -14,55 +13,50 @@ dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: whittle
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 0.0.8
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 0.0.8
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: bundler
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- - ~>
|
31
|
+
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '1.5'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '1.5'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rake
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
|
-
description:
|
63
|
-
|
64
|
-
|
65
|
-
|
55
|
+
description: |2
|
56
|
+
Iode is a work in progress real language on LLVM.
|
57
|
+
This Ruby Gem exists solely so the author can experiment with new language
|
58
|
+
features before committing those ideas to the real language. It is not
|
59
|
+
intended for general use, nor is it intended to be fast or concise.
|
66
60
|
email:
|
67
61
|
- chris@w3style.co.uk
|
68
62
|
executables:
|
@@ -70,7 +64,7 @@ executables:
|
|
70
64
|
extensions: []
|
71
65
|
extra_rdoc_files: []
|
72
66
|
files:
|
73
|
-
- .gitignore
|
67
|
+
- ".gitignore"
|
74
68
|
- Gemfile
|
75
69
|
- LICENSE.txt
|
76
70
|
- README.md
|
@@ -83,33 +77,35 @@ files:
|
|
83
77
|
- lib/iode/core/lists.rb
|
84
78
|
- lib/iode/core/math.rb
|
85
79
|
- lib/iode/core/output.rb
|
80
|
+
- lib/iode/core/strings.rb
|
86
81
|
- lib/iode/interpreter.rb
|
82
|
+
- lib/iode/lambda.rb
|
83
|
+
- lib/iode/macro.rb
|
87
84
|
- lib/iode/reader.rb
|
88
85
|
- lib/iode/scope.rb
|
89
86
|
- lib/iode/version.rb
|
90
87
|
homepage: https://github.com/d11wtq/iode-rb
|
91
88
|
licenses:
|
92
89
|
- MIT
|
90
|
+
metadata: {}
|
93
91
|
post_install_message:
|
94
92
|
rdoc_options: []
|
95
93
|
require_paths:
|
96
94
|
- lib
|
97
95
|
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
-
none: false
|
99
96
|
requirements:
|
100
|
-
- -
|
97
|
+
- - ">="
|
101
98
|
- !ruby/object:Gem::Version
|
102
99
|
version: '0'
|
103
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
-
none: false
|
105
101
|
requirements:
|
106
|
-
- -
|
102
|
+
- - ">="
|
107
103
|
- !ruby/object:Gem::Version
|
108
104
|
version: '0'
|
109
105
|
requirements: []
|
110
106
|
rubyforge_project:
|
111
|
-
rubygems_version:
|
107
|
+
rubygems_version: 2.2.0
|
112
108
|
signing_key:
|
113
|
-
specification_version:
|
109
|
+
specification_version: 4
|
114
110
|
summary: An experimental lisp-family language hosted on Ruby
|
115
111
|
test_files: []
|