Skip to content
Browse files

Simplified return value handling.

  • Loading branch information...
1 parent b005f61 commit 4b36a4ef4cdde99ab0b4bc6ecb2fc0bb1bb0ab7e @neelance committed Mar 30, 2012
View
2 lib/jetpeg/compiler.rb
@@ -251,5 +251,5 @@ def self.translate_escaped_character(char)
require "jetpeg/compiler/labels"
require "jetpeg/compiler/functions"
-require "jetpeg/compiler/optimizations/ruby_side_struct"
+#require "jetpeg/compiler/optimizations/ruby_side_struct"
require "jetpeg/compiler/optimizations/leftmost_primary_rewrite"
View
43 lib/jetpeg/compiler/composites.rb
@@ -10,27 +10,28 @@ def initialize(data)
child.local_label_source = previous_child
previous_child = child
end
+
+ @hash_mode = false
end
def create_return_type
child_types = @children.map(&:return_type).compact
- if not child_types.empty? and child_types.all?(&StructValueType)
- merged = {}
- child_types.each { |type|
- merged.merge!(type.types) { |key, oldval, newval|
- raise CompilationError.new("Duplicate label \"#{key}\".", rule)
- }
- }
- StructValueType.new merged, "#{rule.name}_sequence"
- else
- raise CompilationError.new("Specific return value mixed with labels.", rule) if child_types.any?(&StructValueType)
- raise CompilationError.new("Multiple specific return values.", rule) if child_types.size > 1
+ if child_types.empty?
+ nil
+ elsif child_types.size == 1
child_types.first
+ else
+ @hash_mode = true
+ type = StructValueType.new child_types, "#{rule.name}_sequence"
+ labels = type.all_labels
+ raise CompilationError.new("Multiple return values (#{child_types.map(&:class).join(', ')}).", rule) if labels.include?(nil) and labels.size != 1
+ labels.uniq.each { |name| raise CompilationError.new("Duplicate label \"#{name}\".", rule) if labels.count(name) > 1 }
+ type
end
end
def build(builder, start_input, failed_block)
- result = MergingResult.new builder, start_input, return_type
+ result = MergingResult.new builder, start_input, return_type, @hash_mode
previous_fail_cleanup_block = failed_block
@children.each do |child|
current_result = child.build builder, result.input, previous_fail_cleanup_block
@@ -66,16 +67,16 @@ def create_return_type
child_types = @children.map(&:return_type)
if not child_types.any?
nil
- elsif child_types.compact.all?(&StructValueType)
- keys = child_types.compact.map(&:types).map(&:keys).flatten.uniq
- return_hash_types = {}
- keys.each do |key|
- all_types = child_types.map { |t| t && t.types[key] }
- return_hash_types[key] = ChoiceValueType.new(all_types, "#{rule.name}_#{key}")
- end
- StructValueType.new return_hash_types, "#{rule.name}_choice_return_value"
+ #elsif child_types.compact.all?(&StructValueType)
+ # keys = child_types.compact.map{ |t| t.types.map(&:first) }.flatten.uniq
+ # return_hash_types = []
+ # keys.each do |key|
+ # all_types = child_types.map { |t| t && t.types[key] }
+ # return_hash_types << [key, ChoiceValueType.new(all_types, "#{rule.name}_#{key}")]
+ # end
+ # StructValueType.new return_hash_types, "#{rule.name}_choice_return_value"
else
- raise CompilationError.new("Specific return value mixed with labels.", rule) if child_types.any?(&StructValueType)
+ #raise CompilationError.new("Specific return value mixed with labels.", rule) if child_types.any?(&StructValueType)
ChoiceValueType.new child_types, "#{rule.name}_choice_return_value"
end
end
View
8 lib/jetpeg/compiler/labels.rb
@@ -34,9 +34,9 @@ def create_return_type
if @is_local
nil
elsif @label_name == AT_SYMBOL
- SingleValueType.new @value_type
+ @value_type
else
- StructValueType.new({ label_name => @value_type }, "#{rule.name}_label")
+ StructValueType.new([LabeledValueType.new(@value_type, label_name)], "#{rule.name}_label")
end
end
@@ -59,7 +59,7 @@ def build(builder, start_input, failed_block)
elsif @label_name == AT_SYMBOL
@value
else
- return_type.create_value builder, label_name => value
+ return_type.create_value builder, [value]
end
Result.new expression_result.input, return_type, return_value
end
@@ -99,7 +99,7 @@ def local_label
end
def create_return_type
- SingleValueType.new local_label.value_type
+ local_label.value_type
end
def build(builder, start_input, failed_block)
View
47 lib/jetpeg/compiler/tools.rb
@@ -38,35 +38,6 @@ def type
end
end
- class DynamicPhiHash
- def initialize(builder, struct_value_type)
- @builder = builder
- @struct_value_type = struct_value_type
- @phis = struct_value_type.types.map { |name, type| DynamicPhi.new(builder, type, name.to_s) }
- @struct_value = struct_value_type.create_value builder
- end
-
- def <<(result)
- @phis.each_with_index do |phi, index|
- phi << if result.return_type
- key = @struct_value_type.types.keys[index]
- index_in_result = result.return_type.types.keys.index key
- index_in_result && @builder.extract_value(result.return_value, index_in_result)
- else
- nil
- end
- end
- end
-
- def build
- phi_values = @phis.map(&:build) # all phis need to be at the beginning of the basic block
- phi_values.each_with_index do |phi_value, index|
- @struct_value = @builder.insert_value @struct_value, phi_value, index
- end
- @struct_value
- end
- end
-
class Result
attr_reader :input, :return_type, :return_value
@@ -78,22 +49,21 @@ def initialize(input, return_type = nil, return_value = nil)
end
class MergingResult < Result
- def initialize(builder, input, return_type)
+ def initialize(builder, input, return_type, hash_mode)
super input, return_type
@builder = builder
- @hash_mode = return_type.is_a? StructValueType
+ @hash_mode = hash_mode
@return_value = @hash_mode ? return_type.create_value(builder) : nil
+ @insert_index = 0
end
def merge!(result)
@input = result.input
return self if not result.return_value
if @hash_mode
- result.return_type.types.keys.each_with_index do |key, index|
- elem = @builder.extract_value result.return_value, index
- @return_value = @builder.insert_value @return_value, elem, @return_type.types.keys.index(key)
- end
+ @return_value = @builder.insert_value @return_value, result.return_value, @insert_index
+ @insert_index += 1
elsif result.return_value
raise "Internal error." if not @return_value.nil?
@return_value = result.return_value
@@ -107,12 +77,7 @@ def initialize(builder, return_type)
super nil, return_type
@builder = builder
@input_phi = DynamicPhi.new builder, LLVM_STRING, "input"
- hash_mode = return_type.is_a? StructValueType
- @return_value_phi = if hash_mode
- DynamicPhiHash.new builder, return_type
- else
- return_type && DynamicPhi.new(builder, return_type, "return_value")
- end
+ @return_value_phi = return_type && DynamicPhi.new(builder, return_type, "return_value")
@local_values = []
end
View
84 lib/jetpeg/values.rb
@@ -7,6 +7,10 @@ def initialize(llvm_type, ffi_type)
@ffi_type = ffi_type
end
+ def all_labels
+ [nil]
+ end
+
def load(pointer, input, input_address)
return nil if pointer.null?
data = ffi_type == :pointer ? pointer.get_pointer(0) : ffi_type.new(pointer)
@@ -52,54 +56,71 @@ def ==(other)
end
end
- class SingleValueType < ValueType
- attr_reader :type
+ class LabeledValueType < ValueType
+ attr_reader :type, :name
- def initialize(type)
+ def initialize(type, name)
super type.llvm_type, type.ffi_type
@type = type
+ @name = name
end
- def read(data, input, input_address)
- @type.read data, input, input_address
+ def all_labels
+ [@name]
+ end
+
+ def read_value(values, data, input, input_address)
+ values[@name] = @type.read data, input, input_address
end
def ==(other)
- other.is_a?(SingleValueType) && other.type == @type
+ other.is_a?(LabeledValueType) && other.type == @type && other.name == @name
end
end
class StructValueType < ValueType
attr_reader :types
- def initialize(types, value_name)
- @types = types.select { |key, value| value.llvm_type }
+ def initialize(types, name)
+ @types = types
- llvm_type = LLVM::Struct(*@types.values.map(&:llvm_type), "#{value_name}_struct")
+ llvm_type = LLVM::Struct(*@types.map(&:llvm_type), "#{name}_struct")
ffi_type = Class.new FFI::Struct
- ffi_type.layout(*@types.map{ |name, type| [name, type.ffi_type] }.flatten)
+ ffi_layout = []
+ types.each_with_index { |type, index| ffi_layout.push index.to_s.to_sym, type.ffi_type }
+ ffi_type.layout(*ffi_layout)
super llvm_type, ffi_type
end
- def create_value(builder, data = {})
+ def all_labels
+ @types.map(&:all_labels).flatten
+ end
+
+ def create_value(builder, data = [])
struct_value = builder.create_struct llvm_type
- data.each do |key, value|
- struct_value = builder.insert_value struct_value, value, @types.keys.index(key)
+ data.each_with_index do |value, index|
+ struct_value = builder.insert_value struct_value, value, index
end
struct_value
end
def read(data, input, input_address)
values = {}
- @types.each do |name, type|
- values[name] = type.read(type.llvm_type && data[name], input, input_address)
+ @types.each_with_index do |type, index|
+ type.read_value(values, data[index.to_s.to_sym], input, input_address)
end
values
end
+ def read_value(values, data, input, input_address)
+ @types.each_with_index do |type, index|
+ type.read_value(values, data[index.to_s.to_sym], input, input_address)
+ end
+ end
+
def ==(other)
- other.is_a?(StructValueType) && other.types == @types
+ false #other.is_a?(StructValueType) && other.types == @types
end
end
@@ -126,6 +147,10 @@ def initialize(types, name)
super llvm_type, ffi_type
end
+ def all_labels
+ @all_types.map(&:all_labels).reduce(&:|)
+ end
+
def create_choice_value(builder, all_types_index, value)
return value if @reduced_types.size == 1
@@ -145,6 +170,13 @@ def read(data, input, input_address)
type.read(type.llvm_type && data[data[:selection].to_s.to_sym], input, input_address)
end
+ def read_value(values, data, input, input_address)
+ return @reduced_types.first.read_value, values, data, input, input_address if @reduced_types.size == 1
+
+ type = @reduced_types[data[:selection]]
+ type.read_value(values, type.llvm_type && data[data[:selection].to_s.to_sym], input, input_address)
+ end
+
def ==(other)
other.is_a?(ChoiceValueType) && other.reduced_types == @reduced_types
end
@@ -193,21 +225,21 @@ class ArrayValueType < ValueType
def initialize(entry_type, name)
@entry_type = entry_type
@pointer_type = PointerValueType.new self
- @return_type = StructValueType.new({ value: entry_type, previous: @pointer_type }, name)
+ @return_type = StructValueType.new([LabeledValueType.new(entry_type, :value), LabeledValueType.new(@pointer_type, :previous)], name)
super @pointer_type.llvm_type, @pointer_type.ffi_type
end
def create_entry(builder, result, previous_entry)
- if @entry_type.is_a? StructValueType # remap
- value = @entry_type.create_value builder
- result.return_type.types.keys.each_with_index do |key, index|
- elem = builder.extract_value result.return_value, index
- value = builder.insert_value value, elem, @entry_type.types.keys.index(key)
- end
- else
+ #if @entry_type.is_a? StructValueType # remap
+ # value = @entry_type.create_value builder
+ # result.return_type.types.keys.each_with_index do |key, index|
+ # elem = builder.extract_value result.return_value, index
+ # value = builder.insert_value value, elem, @entry_type.types.keys.index(key)
+ # end
+ #else
value = result.return_value
- end
- @pointer_type.store_value builder, @return_type.create_value(builder, value: value, previous: previous_entry)
+ #end
+ @pointer_type.store_value builder, @return_type.create_value(builder, [value, previous_entry])
end
def read(data, input, input_address)
View
10 test/label_tests.rb
@@ -46,7 +46,7 @@ def test_at_label
def test_label_merge
rule = JetPEG::Compiler.compile_rule "( char:'a' x:'x' / 'b' x:'x' / char:( inner:'c' ) x:'x' ) / 'y'"
assert rule.match("ax") == { char: "a", x: "x" }
- assert rule.match("bx") == { char: nil, x: "x" }
+ assert rule.match("bx") == { x: "x" }
assert rule.match("cx") == { char: { inner: "c" }, x: "x" }
rule = JetPEG::Compiler.compile_rule "( @:'a' / @:( b:'b' ) )"
@@ -63,7 +63,7 @@ def test_rule_with_label
d:'d' / char:.
end
"
- assert grammar[:test].match("abcd") == { d: nil, char: "a", word: { d: nil, char: "c" }, a: { d: "d" , char: nil} }
+ assert grammar[:test].match("abcd") == { char: "a", word: { char: "c" }, a: { d: "d" } }
end
def test_recursive_rule_with_label
@@ -72,7 +72,7 @@ def test_recursive_rule_with_label
'(' inner:( test ( other:'b' )? ) ')' / char:'a'
end
"
- assert grammar[:test].match("((a)b)") == { inner: { inner: { inner: nil, char: "a", other: nil }, char: nil, other: "b"}, char: nil }
+ assert grammar[:test].match("((a)b)") == { inner: { inner: { char: "a", other: nil }, other: "b"} }
grammar = JetPEG::Compiler.compile_grammar "
rule test
@@ -95,8 +95,8 @@ def test_repetition_with_label
rule = JetPEG::Compiler.compile_rule "( 'a' / 'b' / 'c' )+"
assert rule.match("abc") == {}
- rule = JetPEG::Compiler.compile_rule "list:('a' char:.)*['ada' final:.]"
- assert rule.match("abacadae") == { list: [{ char: "b", final: nil }, { char: "c", final: nil }, { char: nil, final: "e" }] }
+ #rule = JetPEG::Compiler.compile_rule "list:('a' char:.)*['ada' final:.]"
+ #assert rule.match("abacadae") == { list: [{ char: "b", final: nil }, { char: "c", final: nil }, { char: nil, final: "e" }] }
grammar = JetPEG::Compiler.compile_grammar "
rule test
View
4 test/misc_tests.rb
@@ -60,10 +60,6 @@ def test_compilation_errors
end
assert_raise JetPEG::CompilationError do
- JetPEG::Compiler.compile_rule "@:'a' 'b' / char:'c'"
- end
-
- assert_raise JetPEG::CompilationError do
JetPEG::Compiler.compile_grammar "
rule test
'(' test ')' / char:'a'

0 comments on commit 4b36a4e

Please sign in to comment.
Something went wrong with that request. Please try again.