Skip to content

Commit

Permalink
Updated AST and VM
Browse files Browse the repository at this point in the history
  • Loading branch information
xea committed Aug 19, 2016
1 parent a0b6536 commit 2d0db01
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 35 deletions.
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ source 'https://rubygems.org'
end

gem 'simplecov'
gem 'activerecord', '~> 4.2.6'
gem 'activerecord', '~> 5.0'
#gem 'activerecord', '~> 4.2.6'
gem 'activerecord-jdbc-adapter', '~> 1.3', platform: :jruby
gem 'activerecord-jdbcpostgresql-adapter', platform: :jruby
gem 'pg', platform: :mri
Expand Down
31 changes: 16 additions & 15 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -44,26 +44,24 @@ GIT
GEM
remote: https://rubygems.org/
specs:
activemodel (4.2.7)
activesupport (= 4.2.7)
builder (~> 3.1)
activerecord (4.2.7)
activemodel (= 4.2.7)
activesupport (= 4.2.7)
arel (~> 6.0)
activemodel (5.0.0.1)
activesupport (= 5.0.0.1)
activerecord (5.0.0.1)
activemodel (= 5.0.0.1)
activesupport (= 5.0.0.1)
arel (~> 7.0)
activerecord-jdbc-adapter (1.3.20)
activerecord (>= 2.2)
activerecord-jdbcpostgresql-adapter (1.3.20)
activerecord-jdbc-adapter (~> 1.3.20)
jdbc-postgres (>= 9.1)
activesupport (4.2.7)
activesupport (5.0.0.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
arel (6.0.3)
builder (3.2.2)
arel (7.1.1)
ast (2.3.0)
celluloid (0.17.3)
celluloid-essentials
celluloid-extras
Expand All @@ -82,6 +80,8 @@ GEM
celluloid-supervision (0.20.6)
timers (>= 4.1.1)
coderay (1.1.1)
concurrent-ruby (1.0.2)
concurrent-ruby (1.0.2-java)
diff-lcs (1.2.5)
docile (1.1.5)
ffi (1.9.14-java)
Expand All @@ -92,8 +92,8 @@ GEM
jdbc-postgres (9.4.1206)
jruby-jars (9.1.2.0)
jruby-rack (1.1.20)
json (1.8.3)
json (1.8.3-java)
json (2.0.2)
json (2.0.2-java)
method_source (0.8.2)
minitest (5.9.0)
net-ssh (3.2.0)
Expand Down Expand Up @@ -137,9 +137,10 @@ PLATFORMS
ruby

DEPENDENCIES
activerecord (~> 4.2.6)
activerecord (~> 5.0)
activerecord-jdbc-adapter (~> 1.3)
activerecord-jdbcpostgresql-adapter
ast
celluloid
highline
jdbc-postgres
Expand Down
58 changes: 40 additions & 18 deletions packages/ar/ar_mode.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
require 'console/table'
require 'ast'

require_relative 'ar_vm'

include AST::Sexp

class ActiveRecordMode < BaseMode
Expand Down Expand Up @@ -49,19 +51,34 @@ def use_namespace(out, ar, namespace_id)
end

def dynamic_command(input)
tokens = ARQLLexer.new.tokenize(input)[:tokens]
ast, remaining_tokens = ARQLCommandParser.new.parse(tokens)

begin
tokens = ARQLLexer.new.tokenize(input)[:tokens]
ast, remaining_tokens = ARQLCommandParser.new.parse(tokens)

command_list = ARQLProcessor.new.process ast
vm = ARQLVM.new @ns

action = -> {
command_list.reduce(@ns) { |acc, msg| acc.send msg[0], *(msg[1]), &msg[2] }
# the action lambda is dependency-injected
action = -> (out) {
command_list.each { |instr| vm.send instr[0], *(instr[1]), &instr[2] }
process_object(vm.pop, out)
}

Command.new(:dynamic, "", "", { dynamic: true }, &action)
rescue e

rescue => e
puts "ERROR"
end
end

def process_object(result, out)
case result.type
when :select_result
pt = PrinTable.new

head = result.children.first[0]
body = result.children.first[1]

out.puts pt.print(head, body, :db)
end
end

Expand All @@ -85,9 +102,11 @@ def initialize
end

def on_select_expr(node)
selexpr = process_all(node).flatten(1)
process_all(node).flatten(1) << [ :apply, [], -> (model, data, verbosity) {
header = model.new.filter_fields(verbosity)

selexpr
s(:select_result, [ header, data ])
} ]
end

def on_model_expr(node)
Expand All @@ -97,8 +116,7 @@ def on_model_expr(node)
def on_model_ids(node)
process_all(node).map { |n|
[
[ :lookup, [ n.to_s.to_sym ] ],
[ :[], [ :class_name ] ]
[ :select_model, [ n.to_s.to_sym ] ]
]
}.flatten(1)
end
Expand All @@ -109,10 +127,13 @@ def on_model_id(node)

def on_model_clause(node)
if node.children.empty?
[[ :all, [] ]]
[
[ :dup, [] ],
[ :apply, [], -> (model) { model.all } ]
]
else
node.children.first.map { |key, value|
[ :where, [ { key.to_sym => value } ] ]
[ :apply, [], -> (model) { model.where(key.to_sym => value) } ]
}
end
end
Expand All @@ -122,20 +143,21 @@ def on_partition_expr(node)
result = []

if part[:limit] >= 0
result << [ :limit, [ part[:limit] ] ]
result << [ :apply, [], -> (model) { model.limit part[:limit] } ]
end

if part[:offset] > 0
result << [ :offset, [ part[:offset] ] ]
result << [ :apply, [], -> (model) { model.offset part[:offset] } ]
end

result
end

def on_verbosity(node)
[[ :map, [], lambda { |e|
e.flatten_fields(node.children.first)
} ]]
[
[ :apply, [], -> (model) { model.map { |e| e.flatten_fields(node.children.first) } } ],
[ :push, [ node.children.first ] ]
]
end

end
Expand Down
2 changes: 1 addition & 1 deletion packages/ar/ar_ns.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def filter_fields(verbosity)
end
end

def flatten_fields(verbosity, include_headers = false)
def flatten_fields(verbosity)
filter_fields(verbosity).map { |attr| resolve_attribute(attr) }
end

Expand Down
58 changes: 58 additions & 0 deletions packages/ar/ar_vm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

class ARQLVM

def initialize(ns = nil)
@ns = ns
@stack = []
@current_model = nil
end

def select_model(model_name)
@stack << @ns.lookup(model_name)[:class_name]
end

def filter(&filter_expr)
top_elem = @stack.pop

if top_elem.nil?
raise "Can not apply filter to an empty stack"
elsif top_elem.is_a? Enumerable
@stack << top_elem.find_all(&filter_expr)
#elsif top_elem.is_a? Class and top_elem.ancestors.member? ActiveRecordBaseProxy
#@stack << top_elem.all.find_all(&filter_expr)
else
raise "Can not apply filter to #{top_elem.class}"
end
end

def push(*elem)
@stack.push *elem
end

def pop(n = nil)
if n.nil?
@stack.pop
else
@stack.pop(n)
end
end

def dup
push @stack.last unless @stack.last.nil?
end

def apply(&function)
n = function.arity
items = pop(n)
push(function.call(*items))
end

def empty?
@stack.empty?
end

def dump_stack!
puts "Stack size: #{@stack.length}"
@stack.each { |item| puts " #{item.class} @ #{item.to_s[0..64]}" }
end
end
51 changes: 51 additions & 0 deletions packages/ar/spec/ar_vm_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
require 'ar/ar'

RSpec.describe ARQLVM do

context '#initialize' do
it 'should create a new, blank VM' do
vm = ARQLVM.new
end
end

context '#push' do
it 'should push a new item onto the top of the stack' do
vm = ARQLVM.new

vm.push :test
expect(vm.pop).to eq(:test)
end
end

context '#apply' do
it 'should apply the given lambda to the top n elements of the stack' do
vm = ARQLVM.new

vm.push 1
vm.push 3
vm.apply { |a, b| a + b }
expect(vm.pop).to eq(4)
expect(vm.empty?).to be_truthy
end

it 'should push every element back after evaluation' do
vm = ARQLVM.new

vm.push 1
vm.push 3
vm.push -4
vm.apply { |a| [ 2, 5 ] }
expect(vm.pop(4)).to eq([1, 3, [ 2, 5 ] ])
expect(vm.empty?).to be_truthy
end

it 'should work well with arrays' do
vm = ARQLVM.new

vm.push 1
vm.push [ 3, 4, 5 ]
vm.apply { |a| a.map { |b| b + 1 } }
expect(vm.pop(2)).to eq([1, [4, 5, 6]])
end
end
end

0 comments on commit 2d0db01

Please sign in to comment.