lucio 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|