Skip to content

Commit

Permalink
Refactor Expression::ElementRef class
Browse files Browse the repository at this point in the history
  • Loading branch information
v0dro committed Jan 16, 2018
1 parent a31144b commit 583d859
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 84 deletions.
222 changes: 140 additions & 82 deletions lib/rubex/ast/expression.rb
Original file line number Diff line number Diff line change
Expand Up @@ -344,114 +344,172 @@ def c_code local_scope
end # class Unary

class ElementRef < Base
attr_reader :entry, :pos, :type, :name, :object_ptr
# FIXME: get rid of this object_ptr for good.
attr_reader :entry, :pos, :type, :name, :object_ptr, :subexprs
extend Forwardable
def_delegators :@element_ref, :generate_disposal_code, :generate_evaluation_code,
:analyse_statement, :generate_element_ref_code,
:generate_assignment_code, :has_temp, :c_code, :allocate_temp,
:allocate_temps, :release_temp, :release_temps, :to_ruby_object,
:from_ruby_object

def initialize name, pos
@name, @pos = name, pos
@subexprs = []
end

# FIXME: This method needs to be implemented for all exprs that are
# possible LHS candidates.
# def analyse_declaration rhs, local_scope
# analyse_statement local_scope
# @has_temp = false
# end

def analyse_statement local_scope, struct_scope=nil
if struct_scope.nil?
@entry = local_scope.find @name
else
@entry = struct_scope[@name]
end

@object_ptr = true if @entry.type.cptr? && @entry.type.type.object?
@entry = struct_scope.nil? ? local_scope.find(@name) : struct_scope[@name]
@type = @entry.type.object? ? @entry.type : @entry.type.type

if @type.object? && !@object_ptr
@has_temp = true
@pos.analyse_statement local_scope
if !(@type.ruby_array?)
@pos = @pos.to_ruby_object
end
@subexprs << @pos
else
@pos.analyse_statement local_scope
end
@element_ref = proper_analysed_type
@element_ref.analyse_statement local_scope
super(local_scope)
end

# This method will be called when [] ruby method or C array element
# reference is called.
# TODO: refactor this by creating separate classes for ruby object, object
# ptr, c type.
def generate_evaluation_code code, local_scope
if @type.object? && !@object_ptr
if @type.ruby_array?
code << "#{@c_code} = RARRAY_AREF(#{@entry.c_name}, #{@pos.c_code(local_scope)});"
elsif @type.ruby_hash?
@pos.generate_evaluation_code code, local_scope
code << "#{@c_code} = rb_hash_aref(#{@entry.c_name}, #{@pos.c_code(local_scope)});"
private

def proper_analysed_type
if ruby_object_c_array?
@object_ptr = true
CVarElementRef.new(self)
else
if ruby_array?
RubyArrayElementRef.new(self)
elsif ruby_hash?
RubyHashElementRef.new(self)
elsif generic_ruby_object?
RubyObjectElementRef.new(self)
else
@pos.generate_evaluation_code code, local_scope
code << "#{@c_code} = rb_funcall(#{@entry.c_name}, rb_intern(\"[]\"), 1, "
code << "#{@pos.c_code(local_scope)});"
CVarElementRef.new(self)
end
code.nl
@pos.generate_disposal_code code
else
@pos.generate_evaluation_code code, local_scope
@c_code = "#{@entry.c_name}[#{@pos.c_code(local_scope)}]"
end
end
end

def generate_disposal_code code
if @type.object? && !@object_ptr
code << "#{@c_code} = 0;"
code.nl
end
def ruby_array?
@type.ruby_array?
end

# This method will be called when []= ruby method or C array assignment
# takes place.
def generate_assignment_code rhs, code, local_scope
if @type.object? && !@object_ptr
@pos.generate_evaluation_code code, local_scope
if @type.ruby_hash?
code << "rb_hash_aset(#{@entry.c_name}, #{@pos.c_code(local_scope)}, #{rhs.c_code(local_scope)});"
else
code << "rb_funcall(#{@entry.c_name}, rb_intern(\"[]=\"), 2, "
code << "#{@pos.c_code(local_scope)}, #{rhs.c_code(local_scope)});"
end
@pos.generate_disposal_code code
else
code << "#{@entry.c_name}[#{@pos.c_code(local_scope)}] = "
code << "#{rhs.c_code(local_scope)};"
end
code.nl
def ruby_hash?
@type.ruby_hash?
end

# FIXME: This is jugaad. Change.
def generate_element_ref_code expr, code, local_scope
if @type.object? && !@object_ptr
@pos.generate_evaluation_code code, local_scope
str = "#{@c_code} = rb_funcall(#{expr.c_code(local_scope)}."
str << "#{@entry.c_name}, rb_intern(\"[]\"), 1, "
str << "#{@pos.c_code(local_scope)});"
code << str
code.nl
@pos.generate_disposal_code code
else
generate_evaluation_code code, local_scope
end
def generic_ruby_object?
@type.object?
end

def ruby_object_c_array?
@entry.type.cptr? && @entry.type.type.object?
end
end # class ElementRef

class AnalysedElementRef < Base
attr_reader :entry, :pos, :type, :name, :object_ptr, :subexprs
def initialize element_ref
@element_ref = element_ref
@pos = @element_ref.pos
@entry = @element_ref.entry
@name = @element_ref.name
@subexprs = @element_ref.subexprs
@object_ptr = @element_ref.object_ptr
@type = @element_ref.type
end

def analyse_statement local_scope
@pos.analyse_statement local_scope
end

def c_code local_scope
code = super
code << @c_code
code
end
end # class ElementRef
end

class RubyObjectElementRef < AnalysedElementRef
def analyse_statement local_scope
super
@has_temp = true
@pos = @pos.to_ruby_object
@subexprs << @pos
end

def generate_evaluation_code code, local_scope
@pos.generate_evaluation_code code, local_scope
code << "#{@c_code} = rb_funcall(#{@entry.c_name}, rb_intern(\"[]\"), 1, "
code << "#{@pos.c_code(local_scope)});"
code.nl
@pos.generate_disposal_code code
end

def generate_disposal_code code
code << "#{@c_code} = 0;"
code.nl
end

def generate_element_ref_code expr, code, local_scope
@pos.generate_evaluation_code code, local_scope
str = "#{@c_code} = rb_funcall(#{expr.c_code(local_scope)}."
str << "#{@entry.c_name}, rb_intern(\"[]\"), 1, "
str << "#{@pos.c_code(local_scope)});"
code << str
code.nl
@pos.generate_disposal_code code
end

def generate_assignment_code rhs, code, local_scope
@pos.generate_evaluation_code code, local_scope
code << "rb_funcall(#{@entry.c_name}, rb_intern(\"[]=\"), 2,"
code << "#{@pos.c_code(local_scope)}, #{rhs.c_code(local_scope)});"
code.nl
@pos.generate_disposal_code code
end
end

class RubyArrayElementRef < RubyObjectElementRef
def generate_evaluation_code code, local_scope
@pos.generate_evaluation_code code, local_scope
code << "#{@c_code} = RARRAY_AREF(#{@entry.c_name}, #{@pos.c_code(local_scope)});"
code.nl
@pos.generate_disposal_code code
end
end # class RubyArrayElementRef

class RubyHashElementRef < RubyObjectElementRef
def generate_evaluation_code code, local_scope
@pos.generate_evaluation_code code, local_scope
code << "#{@c_code} = rb_hash_aref(#{@entry.c_name}, #{@pos.c_code(local_scope)});"
@pos.generate_disposal_code code
end

def generate_assignment_code rhs, code, local_scope
@pos.generate_evaluation_code code, local_scope
code << "rb_hash_aset(#{@entry.c_name}, #{@pos.c_code(local_scope)},"
code << "#{rhs.c_code(local_scope)});"
@pos.generate_disposal_code code
end
end # class RubyHashElementRef

class CVarElementRef < AnalysedElementRef
def analyse_statement local_scope
@pos.analyse_statement local_scope
end

def generate_evaluation_code code, local_scope
@pos.generate_evaluation_code code, local_scope
@c_code = "#{@entry.c_name}[#{@pos.c_code(local_scope)}]"
end

def generate_element_ref_code expr, code, local_scope
generate_evaluation_code code, local_scope
end

def generate_assignment_code rhs, code, local_scope
@pos.generate_evaluation_code code, local_scope
code << "#{@entry.c_name}[#{@pos.c_code(local_scope)}] = "
code << "#{rhs.c_code(local_scope)};"
@pos.generate_disposal_code code
end
end # class CVarElementRef

class Self < Base
def c_code local_scope
Expand Down
3 changes: 2 additions & 1 deletion spec/ruby_operators_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'spec_helper'

describe Rubex do
describe Rubex, hell: true do
test_case = "ruby_operators"

context "Case: #{test_case}" do
Expand All @@ -17,6 +17,7 @@
context ".compile" do
it "compiles to valid C file" do
t,c,e = Rubex::Compiler.compile(@path + '.rubex', test: true)
puts c
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/var_declarions_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'spec_helper'

describe Rubex do
describe Rubex do
test_case = "var_declarations"

context "Case: #{test_case}" do
Expand Down

0 comments on commit 583d859

Please sign in to comment.