lucio 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -9
- data/Gemfile.lock +3 -11
- data/README.md +9 -9
- data/Rakefile +0 -3
- data/VERSION +1 -1
- data/bin/lucio +1 -1
- data/bin/repl.rb +19 -21
- data/lib/lucio.rb +2 -0
- data/lib/lucio/lexicon.rb +12 -20
- data/lib/lucio/lucio.rb +48 -18
- data/lucio.gemspec +17 -42
- data/spec/add_spec.rb +34 -0
- data/spec/behead_spec.rb +12 -0
- data/spec/divide_spec.rb +26 -0
- data/spec/empty_list_spec.rb +23 -0
- data/spec/internal_spec.rb +13 -0
- data/spec/let_spec.rb +29 -0
- data/spec/minus_spec.rb +27 -0
- data/spec/readme_examples_spec.rb +32 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/times_spec.rb +34 -0
- metadata +31 -80
- data/.autotest +0 -3
- data/TODO.md +0 -32
- data/lib/lucio/grammar.rb +0 -37
- data/lib/lucio/list.rb +0 -22
- data/lib/lucio/operators.rb +0 -9
- data/lib/lucio/operators/attribution.rb +0 -10
- data/lib/lucio/operators/conditional.rb +0 -20
- data/lib/lucio/operators/division.rb +0 -16
- data/lib/lucio/operators/equality.rb +0 -11
- data/lib/lucio/operators/macro.rb +0 -15
- data/lib/lucio/operators/multiplication.rb +0 -16
- data/lib/lucio/operators/operator.rb +0 -29
- data/lib/lucio/operators/subtraction.rb +0 -18
- data/lib/lucio/operators/sum.rb +0 -13
- data/lib/lucio/runner.rb +0 -60
- data/lib/lucio_syntax.treetop +0 -92
- data/spec/all_the_fun_spec.rb +0 -21
- data/spec/division_spec.rb +0 -19
- data/spec/eval_spec.rb +0 -116
- data/spec/lucio_spec.rb +0 -25
- data/spec/multiplication_spec.rb +0 -19
- data/spec/parser_spec.rb +0 -105
- data/spec/subtraction_spec.rb +0 -19
- data/spec/sum_spec.rb +0 -19
- data/spec/variable_spec.rb +0 -13
data/lib/lucio/grammar.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'lucio'
|
2
|
-
|
3
|
-
module Lucio
|
4
|
-
class Grammar < Treetop::Runtime::SyntaxNode
|
5
|
-
def eval
|
6
|
-
Lucio::Runner.run make_tree(elements)
|
7
|
-
end
|
8
|
-
|
9
|
-
private
|
10
|
-
def make_tree(el)
|
11
|
-
x = make_list(el)
|
12
|
-
h = nil
|
13
|
-
h, x = Lucio.behead(x) if x[0] == '\''
|
14
|
-
|
15
|
-
Kernel::eval("Lucio::List.new(tree = #{x.inject('') {|x, y| x += "'#{y}',"}.strip.chop.gsub(/'\(',/, '[').gsub(/[,]?'\)'/, ']')}, evaluable = #{!h})")
|
16
|
-
end
|
17
|
-
|
18
|
-
def make_list(el, list = [])
|
19
|
-
el.each do |e|
|
20
|
-
methods = e.public_methods.reject{|i| i.to_s.chr != 'v'}.map{|i| i.to_s}.sort
|
21
|
-
if methods.include?('value')
|
22
|
-
list << e.value
|
23
|
-
else
|
24
|
-
unless e.empty? || e.text_value.strip.empty?
|
25
|
-
if e.nonterminal?
|
26
|
-
list = make_list(e.elements, list)
|
27
|
-
else
|
28
|
-
list << e.text_value
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
list
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
data/lib/lucio/list.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
module Lucio
|
2
|
-
class List
|
3
|
-
attr :tree, :evaluable
|
4
|
-
|
5
|
-
def initialize(tree, evaluable = true)
|
6
|
-
@tree = tree
|
7
|
-
@evaluable = evaluable
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_s
|
11
|
-
flat(tree)
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
def flat(list)
|
16
|
-
result = "#{'(' if list.empty?}#{list.inject('(') do |result, item|
|
17
|
-
result += "#{item} "
|
18
|
-
end.chop})"
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
data/lib/lucio/operators.rb
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
require 'lucio/operators/operator'
|
2
|
-
|
3
|
-
require 'lucio/operators/sum'
|
4
|
-
require 'lucio/operators/multiplication'
|
5
|
-
require 'lucio/operators/division'
|
6
|
-
require 'lucio/operators/subtraction'
|
7
|
-
require 'lucio/operators/equality'
|
8
|
-
require 'lucio/operators/conditional'
|
9
|
-
require 'lucio/operators/attribution'
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'lucio/operators/macro'
|
2
|
-
|
3
|
-
module Lucio
|
4
|
-
module Operator
|
5
|
-
class Conditional < Macro
|
6
|
-
def execute(lexicon, list)
|
7
|
-
tree = list.tree
|
8
|
-
condition = Lucio::Runner.run List.new(tree[0]), lexicon
|
9
|
-
|
10
|
-
if condition
|
11
|
-
Lucio::Runner.run List.new(tree[1]), lexicon
|
12
|
-
else
|
13
|
-
Lucio::Runner.run(List.new(tree[2]), lexicon) if tree.size > 2
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'lucio/operators/function'
|
2
|
-
|
3
|
-
module Lucio
|
4
|
-
module Operator
|
5
|
-
class Division < Function
|
6
|
-
def execute(lexicon, *items)
|
7
|
-
if items.size == 0
|
8
|
-
0
|
9
|
-
else
|
10
|
-
items.inject {|result, item| result = result / item.to_f }
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'lucio/operators/function'
|
2
|
-
|
3
|
-
module Lucio
|
4
|
-
module Operator
|
5
|
-
class Multiplication < Function
|
6
|
-
def execute(lexicon, *items)
|
7
|
-
if items.size == 0
|
8
|
-
0
|
9
|
-
else
|
10
|
-
items.inject(1) {|multiplication, item| multiplication *= item }
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module Lucio
|
2
|
-
module Operator
|
3
|
-
class Operator
|
4
|
-
attr :type
|
5
|
-
|
6
|
-
def type
|
7
|
-
@type
|
8
|
-
end
|
9
|
-
|
10
|
-
def execute(*items)
|
11
|
-
raise "Incomplete operator"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class Function
|
16
|
-
def initialize
|
17
|
-
super.type = :function
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class Macro
|
22
|
-
def initialize
|
23
|
-
super.type = :macro
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'lucio/operators/function'
|
2
|
-
|
3
|
-
module Lucio
|
4
|
-
module Operator
|
5
|
-
class Subtraction < Function
|
6
|
-
def execute(lexicon, *items)
|
7
|
-
p lexicon, items
|
8
|
-
if items.size == 0
|
9
|
-
0
|
10
|
-
else
|
11
|
-
head, tail = Lucio.behead(items)
|
12
|
-
tail.empty? ? (head * -1) : tail.inject(head) {|subtraction, item| subtraction -= item }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
data/lib/lucio/operators/sum.rb
DELETED
data/lib/lucio/runner.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
module Lucio
|
2
|
-
class Runner
|
3
|
-
def self.run(obj_tree, lexicon = Lexicon.new)
|
4
|
-
tree = obj_tree.tree
|
5
|
-
|
6
|
-
if obj_tree.evaluable
|
7
|
-
case
|
8
|
-
when tree.empty?
|
9
|
-
nil
|
10
|
-
when tree.size == 1
|
11
|
-
item = tree[0]
|
12
|
-
instruction = lexicon.get item
|
13
|
-
if instruction
|
14
|
-
instruction.execute lexicon
|
15
|
-
else
|
16
|
-
begin
|
17
|
-
eval(item)
|
18
|
-
rescue Exception => e
|
19
|
-
raise "Invalid or unknown symbol: #{item}", e.backtrace
|
20
|
-
end
|
21
|
-
end
|
22
|
-
else
|
23
|
-
operator, list = Lucio.behead(tree)
|
24
|
-
start, tail = Lucio.behead(list)
|
25
|
-
|
26
|
-
instruction = lexicon.get operator
|
27
|
-
|
28
|
-
raise "Invalid or unknown operator: #{operator}" unless instruction
|
29
|
-
|
30
|
-
if instruction.type == :function
|
31
|
-
if(start.kind_of? Array)
|
32
|
-
first = run List.new(start), lexicon
|
33
|
-
else
|
34
|
-
first = eval start
|
35
|
-
end
|
36
|
-
|
37
|
-
if tail.empty?
|
38
|
-
instruction.execute(lexicon, first)
|
39
|
-
else
|
40
|
-
tail.inject(first) do |result, item|
|
41
|
-
if item.kind_of? Array
|
42
|
-
i = run List.new(item), lexicon
|
43
|
-
else
|
44
|
-
i = eval item
|
45
|
-
end
|
46
|
-
|
47
|
-
instruction.execute(lexicon, result, i)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
elsif instruction.type == :macro
|
52
|
-
instruction.execute lexicon, List.new(list)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
else
|
56
|
-
obj_tree
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
data/lib/lucio_syntax.treetop
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'lucio/grammar'
|
2
|
-
|
3
|
-
grammar Lucio
|
4
|
-
|
5
|
-
rule lucio
|
6
|
-
(whitespace / (quote? list))* <Grammar>
|
7
|
-
end
|
8
|
-
|
9
|
-
rule list
|
10
|
-
lparen (whitespace / operator)? (value)* rparen
|
11
|
-
end
|
12
|
-
|
13
|
-
rule value
|
14
|
-
list / string / number / boolean / operator / vector / whitespace
|
15
|
-
end
|
16
|
-
|
17
|
-
rule quote
|
18
|
-
'\''
|
19
|
-
end
|
20
|
-
|
21
|
-
rule rparen
|
22
|
-
')'
|
23
|
-
end
|
24
|
-
|
25
|
-
rule lparen
|
26
|
-
'('
|
27
|
-
end
|
28
|
-
|
29
|
-
rule whitespace
|
30
|
-
[ \n\r\t,]+
|
31
|
-
end
|
32
|
-
|
33
|
-
rule vector
|
34
|
-
'[' (value)* ']'
|
35
|
-
end
|
36
|
-
|
37
|
-
rule operator
|
38
|
-
((([a-zA-Z] ([-]? [a-zA-Z0-9])* [?]?) !('+' / '-' / '/' / '*')) / ('+' / '-' / '/' / '*')) {
|
39
|
-
def value
|
40
|
-
text_value
|
41
|
-
end
|
42
|
-
}
|
43
|
-
end
|
44
|
-
|
45
|
-
rule number
|
46
|
-
decimal / integer {
|
47
|
-
def value
|
48
|
-
f = text_value.to_f
|
49
|
-
i = text_value.to_i
|
50
|
-
(f - i == 0 ? i : f)
|
51
|
-
end
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
rule decimal
|
56
|
-
integer '.' [0-9]+ {
|
57
|
-
def value
|
58
|
-
text_value.to_f
|
59
|
-
end
|
60
|
-
}
|
61
|
-
end
|
62
|
-
|
63
|
-
rule integer
|
64
|
-
'-'? unsigned_integer
|
65
|
-
end
|
66
|
-
|
67
|
-
rule unsigned_integer
|
68
|
-
'0' / [1-9] [0-9]*
|
69
|
-
end
|
70
|
-
|
71
|
-
rule string
|
72
|
-
'"' [^"]* '"' {
|
73
|
-
def value
|
74
|
-
text_value
|
75
|
-
end
|
76
|
-
}
|
77
|
-
end
|
78
|
-
#'
|
79
|
-
rule boolean
|
80
|
-
true / false
|
81
|
-
end
|
82
|
-
|
83
|
-
rule true
|
84
|
-
'true'
|
85
|
-
end
|
86
|
-
|
87
|
-
rule false
|
88
|
-
'false'
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
data/spec/all_the_fun_spec.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'lucio'
|
3
|
-
|
4
|
-
describe "All the fun" do
|
5
|
-
it "should have all the fun" do
|
6
|
-
Lucio.literal("'(lisp programmers have all defun)").should == '(lisp programmers have all defun)'
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should work too =P" do
|
10
|
-
Lucio.literal("'(a b c)").should == '(a b c)'
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should work with numbers" do
|
14
|
-
Lucio.literal("'(1 2 3)").should == '(1 2 3)'
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should work with mixed values too" do
|
18
|
-
Lucio.literal("'(a b c 1 2 3)").should == '(a b c 1 2 3)'
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
data/spec/division_spec.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'lucio'
|
3
|
-
|
4
|
-
describe Lucio::Operator::Division do
|
5
|
-
it "an empty list should return zero" do
|
6
|
-
Lucio.eval('(/)').should == 0
|
7
|
-
end
|
8
|
-
|
9
|
-
it "a list with one item should return that item" do
|
10
|
-
Lucio.eval('(/ 1)').should == 1
|
11
|
-
Lucio.eval('(/ 2)').should == 2
|
12
|
-
end
|
13
|
-
|
14
|
-
it "a list with more than one item should eval all items" do
|
15
|
-
Lucio.eval('(/ 8 4)').should == 2
|
16
|
-
Lucio.eval('(/ 8 4 2)').should == 1
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
data/spec/eval_spec.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'lucio'
|
3
|
-
|
4
|
-
describe Lucio do
|
5
|
-
|
6
|
-
context 'empty list' do
|
7
|
-
it 'should return nil' do
|
8
|
-
Lucio.eval('()').should == nil
|
9
|
-
Lucio.eval('( )').should == nil
|
10
|
-
Lucio.eval('( )').should == nil
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
context 'sum operation' do
|
15
|
-
it 'should return a numeric value' do
|
16
|
-
Lucio.eval('(1)').should == 1
|
17
|
-
Lucio.eval('(+ 1 2)').should == 3
|
18
|
-
Lucio.eval('(+ 1 2 3 4 5 6)').should == 21
|
19
|
-
Lucio.eval('(+ 1 (+ 2 3))').should == 6
|
20
|
-
|
21
|
-
Lucio.eval('(+)').should == 0
|
22
|
-
|
23
|
-
lambda { Lucio.eval('(invalid)') }.should raise_error
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
context 'more than one type of operation' do
|
28
|
-
it 'should return a numeric value' do
|
29
|
-
Lucio.eval('(/ (* (+ 1 2) (+3 4)) 2)').should == 10.5
|
30
|
-
Lucio.eval('(- 10.5 (/ (* (+ 1 2) (+3 4)) 2))').should == 0
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
context 'builtin function' do
|
35
|
-
it 'compare two values using a function' do
|
36
|
-
Lucio.eval('(eql? (* (+ 1 2) 3) 9)').should be_true
|
37
|
-
Lucio.eval('(eql? (/ (* (+ 1 2) (+3 4)) 2) 10)').should be_false
|
38
|
-
Lucio.eval(<<lisp
|
39
|
-
(eql?
|
40
|
-
(/
|
41
|
-
(*
|
42
|
-
(+ 1 2)
|
43
|
-
(+3 4))
|
44
|
-
2)
|
45
|
-
10)
|
46
|
-
lisp
|
47
|
-
).should be_false
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'macro' do
|
52
|
-
it 'runs a simple if' do
|
53
|
-
Lucio.eval(<<lisp
|
54
|
-
(if (eql? 1 1)
|
55
|
-
("ok"))
|
56
|
-
lisp
|
57
|
-
).should == 'ok'
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'a simple if without else returns nil when false' do
|
61
|
-
Lucio.eval('(if (eql? 1 2)("nope"))').should == nil
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'runs a if with else' do
|
65
|
-
Lucio.eval(<<lisp
|
66
|
-
(if (eql? 1 1)
|
67
|
-
("ok")
|
68
|
-
("nope"))
|
69
|
-
lisp
|
70
|
-
).should == 'ok'
|
71
|
-
|
72
|
-
Lucio.eval(<<lisp
|
73
|
-
(if (eql? 2 1)
|
74
|
-
("nope")
|
75
|
-
("ok"))
|
76
|
-
lisp
|
77
|
-
).should == 'ok'
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'runs a function before a macro' do
|
81
|
-
Lucio.eval(<<lisp
|
82
|
-
(+ 1 2 3 (if (eql? (+ 1 1) 2) (4) (5)))
|
83
|
-
lisp
|
84
|
-
).should == 10
|
85
|
-
|
86
|
-
Lucio.eval(<<lisp
|
87
|
-
(eql? (+ 1 2 3 (if (eql? (+ 1 1) 2) (4) (5))) 10)
|
88
|
-
lisp
|
89
|
-
).should be_true
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'runs a macro before a function ' do
|
93
|
-
code = <<lisp
|
94
|
-
(if (eql? (+ 1 1) 2) (+ 1 2 3 4) (0))
|
95
|
-
lisp
|
96
|
-
Lucio.eval(code).should == 10
|
97
|
-
|
98
|
-
Lucio.eval(<<lisp
|
99
|
-
(if (eql? (+ 1 1) 2)
|
100
|
-
(eql? (+ 1 2 3 (4) (5)) 15)
|
101
|
-
(false))
|
102
|
-
lisp
|
103
|
-
).should be_true
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
context 'quoted list' do
|
108
|
-
|
109
|
-
it 'a quoted empty list should return an empty list' do
|
110
|
-
Lucio.literal("'()").should == '()'
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|