iode 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|