Class: PgVerify::Model::Expression
- Inherits:
-
Object
- Object
- PgVerify::Model::Expression
- Defined in:
- lib/pg-verify/model/expression.rb
Overview
Class used to represent a mathematical expression
Constant Summary collapse
- ASSIGNMENT_OP =
':='
- MAX_ALLOCS_FOR_CHECK =
1000000
Instance Attribute Summary collapse
-
#expression_string ⇒ Object
The entire expression as a string.
Instance Method Summary collapse
- #assigned_variable ⇒ Object
- #assignment? ⇒ Boolean
-
#calc_illegal_allocations(resolved_variables) ⇒ Object
Calcuates an AllocationSet which is populated with all variable allocations which lead to an illegal output value for this expressions variable assignment.
-
#filter_allocation_set(allocation_set) ⇒ Object
Only keeps allocations in the specified allocation set which are possible based on this condition.
-
#initialize(expression_string) ⇒ Expression
constructor
A new instance of Expression.
-
#isolate_assigned_variable ⇒ Object
This method splits off a potential assigned variable and returns the variable which is assigned as a symbol and the remaining expression as a string.
- #term_variables ⇒ Object
- #to_s ⇒ Object
-
#used_variables(expression = @expression_string) ⇒ Object
Finds all variables in the specified this expression and returns them as an unique array of symbols ordered by their occource.
Constructor Details
#initialize(expression_string) ⇒ Expression
Returns a new instance of Expression.
16 17 18 |
# File 'lib/pg-verify/model/expression.rb', line 16 def initialize(expression_string) @expression_string = expression_string end |
Instance Attribute Details
#expression_string ⇒ Object
The entire expression as a string
14 15 16 |
# File 'lib/pg-verify/model/expression.rb', line 14 def expression_string @expression_string end |
Instance Method Details
#assigned_variable ⇒ Object
26 27 28 29 |
# File 'lib/pg-verify/model/expression.rb', line 26 def assigned_variable() var, expression = isolate_assigned_variable() return var end |
#assignment? ⇒ Boolean
36 37 38 |
# File 'lib/pg-verify/model/expression.rb', line 36 def assignment?() return !assigned_variable().nil? end |
#calc_illegal_allocations(resolved_variables) ⇒ Object
Calcuates an AllocationSet which is populated with all variable allocations which lead to an illegal output value for this expressions variable assignment
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/pg-verify/model/expression.rb', line 42 def calc_illegal_allocations(resolved_variables) assigned_var, term = isolate_assigned_variable() raise("Term '#{self}' is not a variable assignment!") if assigned_var.nil? term_vars = used_variables(term) # Resolve the variables used in this expression to actual variable objects assigned_var = resolved_variables.detect {|var| var.name == assigned_var } term_vars = term_vars.map { |varname| resolved_variables.detect { |var| varname == var.name } } # Calculate the number of possible allocations, which is the product of the variable range length num_combinations = term_vars.map(&:range).map(&:count).reduce(&:*) # Set an upper limit to not calculate some huge range forever raise "Search space too large on validation of term '#{self}': #{num_combinations} > #{MAX_ALLOCS_FOR_CHECK}" \ if num_combinations > MAX_ALLOCS_FOR_CHECK # Calculate all combinations of possible variable assignments based on their range allocations = term_vars.map(&:range).map(&:to_a).reduce(&:product).map(&:flatten) # For each combination of variable allocations create an expression by replacing the variable # with its value in that allocation illegal_allocations = allocations.reject { |alloc| values = term_vars.map(&:name).map(&:to_s).zip(alloc).to_h expression = term.gsub(/#{term_vars.map(&:name).join("|")}/, values) resolved_value = eval(expression) assigned_var.range.include?(resolved_value) } puts "#{illegal_allocations}" return AllocationSet.new(term_vars, illegal_allocations) end |
#filter_allocation_set(allocation_set) ⇒ Object
Only keeps allocations in the specified allocation set which are possible based on this condition
79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/pg-verify/model/expression.rb', line 79 def filter_allocation_set(allocation_set) # Only keep allocations for which this condition evaluates to true allocation_set.allocations.select { |alloc| values = allocation_set.variables.map(&:name).map(&:to_s).zip(alloc).to_h term = @expression_string.gsub(/#{allocation_set.variables.map(&:name).join("|")}/, values) result = eval(term) raise "Expression #{self} for allocation #{alloc} (#{term}) evaluated to #{result} which is not a boolean" \ unless result == true || result == false result == true } end |
#isolate_assigned_variable ⇒ Object
This method splits off a potential assigned variable and returns the variable which is assigned as a symbol and the remaining expression as a string.
93 94 95 96 97 98 |
# File 'lib/pg-verify/model/expression.rb', line 93 def isolate_assigned_variable() var = used_variables().first match = @expression_string[/(#{var}\s*#{ASSIGNMENT_OP})/, 1] return nil, @expression_string if match.nil? return var, @expression_string.gsub(match, '').strip end |
#term_variables ⇒ Object
31 32 33 34 |
# File 'lib/pg-verify/model/expression.rb', line 31 def term_variables() var, expression = isolate_assigned_variable() return used_variables(expression) end |
#to_s ⇒ Object
100 101 102 |
# File 'lib/pg-verify/model/expression.rb', line 100 def to_s() @expression_string end |
#used_variables(expression = @expression_string) ⇒ Object
Finds all variables in the specified this expression and returns them as an unique array of symbols ordered by their occource
22 23 24 |
# File 'lib/pg-verify/model/expression.rb', line 22 def used_variables(expression=@expression_string) expression.scan(/[a-zA-Z_][a-zA-Z0-9_]*/).uniq.map(&:to_sym) end |