lucio 0.0.7 → 0.0.8
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.
- 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
|