lucio 0.0.7
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/.autotest +3 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +2 -0
- data/CHANGELOG.md +1 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +15 -0
- data/README.md +67 -0
- data/Rakefile +42 -0
- data/TODO.md +32 -0
- data/VERSION +1 -0
- data/bin/lucio +9 -0
- data/bin/repl.rb +39 -0
- data/lib/lucio/grammar.rb +37 -0
- data/lib/lucio/lexicon.rb +25 -0
- data/lib/lucio/list.rb +22 -0
- data/lib/lucio/lucio.rb +29 -0
- data/lib/lucio/operators/attribution.rb +10 -0
- data/lib/lucio/operators/conditional.rb +20 -0
- data/lib/lucio/operators/division.rb +16 -0
- data/lib/lucio/operators/equality.rb +11 -0
- data/lib/lucio/operators/macro.rb +15 -0
- data/lib/lucio/operators/multiplication.rb +16 -0
- data/lib/lucio/operators/operator.rb +29 -0
- data/lib/lucio/operators/subtraction.rb +18 -0
- data/lib/lucio/operators/sum.rb +13 -0
- data/lib/lucio/operators.rb +9 -0
- data/lib/lucio/runner.rb +60 -0
- data/lib/lucio.rb +1 -0
- data/lib/lucio_syntax.treetop +92 -0
- data/lucio.gemspec +104 -0
- data/spec/all_the_fun_spec.rb +21 -0
- data/spec/division_spec.rb +19 -0
- data/spec/eval_spec.rb +116 -0
- data/spec/lucio_spec.rb +25 -0
- data/spec/multiplication_spec.rb +19 -0
- data/spec/parser_spec.rb +105 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/subtraction_spec.rb +19 -0
- data/spec/sum_spec.rb +19 -0
- data/spec/variable_spec.rb +13 -0
- metadata +186 -0
data/.autotest
ADDED
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
|
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem 'polyglot'
|
4
|
+
gem 'treetop'
|
5
|
+
|
6
|
+
gem 'simplecov', '>= 0.4.0', :require => false, :group => :test
|
7
|
+
|
8
|
+
# Add dependencies to develop your gem here.
|
9
|
+
# Include everything needed to run rake, tests, features, etc.
|
10
|
+
group :development, :test do
|
11
|
+
gem 'rspec'
|
12
|
+
gem 'ZenTest'
|
13
|
+
gem 'diff-lcs'
|
14
|
+
gem "yard", "~> 0.6.0"
|
15
|
+
gem "bundler", "~> 1.0.0"
|
16
|
+
gem "jeweler", "~> 1.6.4"
|
17
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
ZenTest (4.5.0)
|
5
|
+
diff-lcs (1.1.2)
|
6
|
+
git (1.2.5)
|
7
|
+
jeweler (1.6.4)
|
8
|
+
bundler (~> 1.0)
|
9
|
+
git (>= 1.2.5)
|
10
|
+
rake
|
11
|
+
polyglot (0.3.1)
|
12
|
+
rake (0.9.2)
|
13
|
+
rspec (2.6.0)
|
14
|
+
rspec-core (~> 2.6.0)
|
15
|
+
rspec-expectations (~> 2.6.0)
|
16
|
+
rspec-mocks (~> 2.6.0)
|
17
|
+
rspec-core (2.6.4)
|
18
|
+
rspec-expectations (2.6.0)
|
19
|
+
diff-lcs (~> 1.1.2)
|
20
|
+
rspec-mocks (2.6.0)
|
21
|
+
simplecov (0.4.2)
|
22
|
+
simplecov-html (~> 0.4.4)
|
23
|
+
simplecov-html (0.4.5)
|
24
|
+
treetop (1.4.9)
|
25
|
+
polyglot (>= 0.3.1)
|
26
|
+
yard (0.6.8)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
x86-mingw32
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
ZenTest
|
34
|
+
bundler (~> 1.0.0)
|
35
|
+
diff-lcs
|
36
|
+
jeweler (~> 1.6.4)
|
37
|
+
polyglot
|
38
|
+
rspec
|
39
|
+
simplecov (>= 0.4.0)
|
40
|
+
treetop
|
41
|
+
yard (~> 0.6.0)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Open Source Initiative OSI - The MIT License (MIT):Licensing
|
2
|
+
|
3
|
+
The MIT License (MIT)
|
4
|
+
Copyright (c) 2011 P Balduino, R Lorca
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
7
|
+
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
8
|
+
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
11
|
+
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
13
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
14
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
15
|
+
DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Lucio (en)
|
2
|
+
|
3
|
+
## What?
|
4
|
+
Lucio is **intended to be** a Lisp-like language developed in Ruby only for knowledge and fun. No profit intended.
|
5
|
+
|
6
|
+
## Why?
|
7
|
+
From Latin, Lucius means _Light_, because this development is enlightening my (poor) knowledge about programming languages, parsing and related subjects.
|
8
|
+
|
9
|
+
Lucio is also the name of one of the most important teachers I had, and I found this as a kind of homage.
|
10
|
+
|
11
|
+
The last, but not least, reason is to practice TDD, since I'm developing all the code using test-first.
|
12
|
+
|
13
|
+
## When?
|
14
|
+
Lucio is developed in my almost nonexistent spare time as a way to keep me learning and passionate with software development.
|
15
|
+
|
16
|
+
## Who?
|
17
|
+
I'm just an ordinary software developer, passionate and curious. If you want to collaborate, fork this and start to code. Simple.
|
18
|
+
|
19
|
+
## Small sample
|
20
|
+
(/ (* (+ 1 2) (+3 4)) 2)
|
21
|
+
=> 10.5
|
22
|
+
|
23
|
+
(eql? (* (+ 1 2) 3) 9)
|
24
|
+
=> true
|
25
|
+
|
26
|
+
(if (eql? 10.5 (/ (* (+ 1 2) (+3 4)) 2))
|
27
|
+
("great"))
|
28
|
+
=> "great"
|
29
|
+
|
30
|
+
(if (eql? 0 (/ (* (+ 1 2) (+3 4)) 2))
|
31
|
+
("great")
|
32
|
+
("ouch")
|
33
|
+
=> "ouch"
|
34
|
+
|
35
|
+
# Lucio (pt\_BR)
|
36
|
+
|
37
|
+
## O que é?
|
38
|
+
Lucio **tem a intenção de ser** um dialeto Lisp desenvolvido inicialmente em Ruby apenas por diversão e aprendizado, sem qualquer intenção de lucro financeiro.
|
39
|
+
|
40
|
+
## Por que?
|
41
|
+
Em Latim, Lucius significa _Luz_, ou _Iluminação_, porque esse projeto está iluminando meu (pobre) conhecimento sobre linguagens de programação, interpretadores e assuntos relacionados.
|
42
|
+
|
43
|
+
Lucio é também o nome de um dos mais importantes professores que já tive, e encontrei nesse projeto uma forma de homenageá-lo.
|
44
|
+
|
45
|
+
O último motivo, mas não menos importante, é poder praticar TDD, partindo do princípio que estou desenvolvendo **todo** o código utilizando essa metodologia.
|
46
|
+
|
47
|
+
## Quando?
|
48
|
+
Lucio está sendo desenvolvido em meu quase inexistente tempo livre como uma forma de me manter sempre aprendendo coisas novas e motivado a continuar desenvolvendo.
|
49
|
+
|
50
|
+
## Quem?
|
51
|
+
Sou apenas um rapaz latino-americano sem dinheiro no bolso nem amigos importantes, mas que realmente adora o que faz e muito curioso. Se você quiser participar e colaborar, crie um fork e comece a codificar. Simples assim.
|
52
|
+
|
53
|
+
## Exemplos simples
|
54
|
+
(/ (* (+ 1 2) (+3 4)) 2)
|
55
|
+
=> 10.5
|
56
|
+
|
57
|
+
(eql? (* (+ 1 2) 3) 9)
|
58
|
+
=> true
|
59
|
+
|
60
|
+
(if (eql? 10.5 (/ (* (+ 1 2) (+3 4)) 2))
|
61
|
+
("great"))
|
62
|
+
=> "great"
|
63
|
+
|
64
|
+
(if (eql? 0 (/ (* (+ 1 2) (+3 4)) 2))
|
65
|
+
("great")
|
66
|
+
("ouch")
|
67
|
+
=> "ouch"
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "lucio"
|
18
|
+
gem.homepage = "https://github.com/pbalduino/lucio"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Lucio is a LISP-like language created just for fun}
|
21
|
+
gem.description = %Q{Lucio is intended to be a Lisp-like language developed in Ruby only for knowledge and fun.}
|
22
|
+
gem.email = "pbalduino+github@gmail.com"
|
23
|
+
gem.authors = ["pbalduino"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'yard'
|
42
|
+
YARD::Rake::YardocTask.new
|
data/TODO.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# TODO
|
2
|
+
|
3
|
+
## Introdução
|
4
|
+
|
5
|
+
1. Toda a comunicação será feita através desse arquivo, das mensagens de commit e do código.
|
6
|
+
|
7
|
+
1. Dúvidas, intenções e próximos passos serão incluidos aqui.
|
8
|
+
|
9
|
+
1. Commits mal explicados ou sem uma mensagem clara e objetiva serão revertidos.
|
10
|
+
|
11
|
+
1. ???
|
12
|
+
|
13
|
+
1. Profit
|
14
|
+
|
15
|
+
## Tarefas
|
16
|
+
|
17
|
+
* Podemos fazer de duas formas: apagar as linhas de mensagens que foram resolvidas ou podemos simplesmente <strike>riscá-las</strike> e mantê-las por aqui, como uma forma rudimentar de histórico para quem não quiser/puder ver o versionamento do arquivo. O quê você prefere?
|
18
|
+
|
19
|
+
* Escrever testes para casos especiais ou que ainda levantem dúvidas sobre o funcionamento do parser.
|
20
|
+
|
21
|
+
* Finalizada uma versão funcional do parser, criar testes para resolver pequenas expressões matemáticas e fazer com que o Runner as execute.
|
22
|
+
|
23
|
+
* Minha primeira idéia foi de usar a classe Lexicon como uma espécie de dicionário de funções e operadores, onde ficariam as funções existentes e as novas. O Runner vai executar a expressão correspondente ao operador utilizando valores simples da lista. Caso seja encontrada uma lista dentro da lista atual, ela será passada recursivamente ao Runner até que retorne um valor simples.
|
24
|
+
|
25
|
+
* Exemplo:
|
26
|
+
<pre>
|
27
|
+
(eql? (+ 1 2) 3)
|
28
|
+
|
|
29
|
+
+--> runner: eql? (lista) 3 +-> eql? 3 3 -> true
|
30
|
+
| |
|
31
|
+
+-----> runner + 1 2 --> returns 3 --+
|
32
|
+
</pre>
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.7
|
data/bin/lucio
ADDED
data/bin/repl.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH << (File.expand_path(File.dirname(__FILE__)) + '/../lib')
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'lucio'
|
6
|
+
|
7
|
+
QUIT = '.q'
|
8
|
+
|
9
|
+
module Lucio
|
10
|
+
class Repl
|
11
|
+
def self.run
|
12
|
+
exit = false
|
13
|
+
|
14
|
+
puts <<lisp
|
15
|
+
# lucio interactive console
|
16
|
+
-------------------------
|
17
|
+
# type a lucio expression and press ENTER
|
18
|
+
# type .q and press ENTER to exit
|
19
|
+
|
20
|
+
lisp
|
21
|
+
while !exit
|
22
|
+
print 'lucio: '
|
23
|
+
command = (gets).chomp
|
24
|
+
exit = (command == QUIT)
|
25
|
+
unless exit
|
26
|
+
begin
|
27
|
+
print '=> '
|
28
|
+
p Lucio.eval(command)
|
29
|
+
rescue Exception => msg
|
30
|
+
puts "Error: #{msg}"
|
31
|
+
end
|
32
|
+
puts ''
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
puts '# bye!'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'lucio/operators'
|
2
|
+
|
3
|
+
module Lucio
|
4
|
+
class Lexicon
|
5
|
+
def initialize
|
6
|
+
fill_operator_list
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(operator)
|
10
|
+
ret = @operator_list[operator]
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
def fill_operator_list
|
15
|
+
@operator_list = {}
|
16
|
+
@operator_list['+'] = Operator::Sum.new
|
17
|
+
@operator_list['*'] = Operator::Multiplication.new
|
18
|
+
@operator_list['/'] = Operator::Division.new
|
19
|
+
@operator_list['-'] = Operator::Subtraction.new
|
20
|
+
@operator_list['eql?'] = Operator::Equality.new
|
21
|
+
@operator_list['if'] = Operator::Conditional.new
|
22
|
+
@operator_list['let'] = Operator::Attribution.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/lucio/list.rb
ADDED
@@ -0,0 +1,22 @@
|
|
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/lucio.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'lucio/runner'
|
2
|
+
require 'lucio/lexicon'
|
3
|
+
require 'lucio/list'
|
4
|
+
require 'polyglot'
|
5
|
+
require 'treetop'
|
6
|
+
require 'lucio_syntax'
|
7
|
+
|
8
|
+
module Lucio
|
9
|
+
def self.parse(str, debug = false)
|
10
|
+
parser = LucioParser.new
|
11
|
+
result = parser.parse str
|
12
|
+
|
13
|
+
puts "\n#{parser.failure_reason}" unless result || !debug
|
14
|
+
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.eval(str)
|
19
|
+
parse(str).eval
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.literal(str)
|
23
|
+
Lucio.eval(str).to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.behead(list)
|
27
|
+
[list[0], list.drop(1)]
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
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
|
+
|
@@ -0,0 +1,16 @@
|
|
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
|
+
|
@@ -0,0 +1,16 @@
|
|
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
|
+
|
@@ -0,0 +1,29 @@
|
|
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
|
@@ -0,0 +1,18 @@
|
|
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
|
+
|
@@ -0,0 +1,9 @@
|
|
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'
|
data/lib/lucio/runner.rb
ADDED
@@ -0,0 +1,60 @@
|
|
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.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'lucio/lucio'
|