require_relative 'lvalue' module Sexp # ------------------------------------------------------------------ # Abstract class Root c.node_type, :value => c.name, :tree => c } } end end # ------------------------------------------------------------------ # Node lists class IdentifierList 2 end def has_rhs expressions && expressions.length > 1 end def lhs_node expressions && expressions[0] end def rhs_node expressions[1] end # override in sub classes to make `traverse` method to yield # `node_value` to block. Block may use `node_value`, or use # `node_type` to determine, how to access AST properties on `node` # # @return [String] non nil value to yield in pre-order def expression_prefix nil end # @return [String] non nil value to yield in in-order def expression_val nil end # @return [String] non nil value to yield in post-order def expression_postfix nil end # walk down binary tree for the expresssion, and yield # 'expression_prefix', 'expxression_val', and 'expression_postfix' # # @param [String] variable contructed in `blk` during `traversal` # @returns [String] memo constructured during the traversal def traverse( memo="", &blk ) memo = yield memo, node_type, self, expression_prefix if blk && expression_prefix memo = lhs_node.traverse( memo, &blk ) if lhs_node memo = yield memo, node_type, self, expression_val if blk && expression_val memo = rhs_node.traverse( memo, &blk ) if has_rhs memo = yield memo, node_type, self, expression_postfix if blk && expression_postfix memo end end class InfixExpression < AbstactExpression # during traverse show operator in between 'lhs' and 'rhs' def expression_val operator end # # @return [String] operator to use (nil if no rhs, else rhs.operator) def operator return nil if !has_rhs rhs_operators = expressions[1].recursive_select( Sexp::Operator ) return rhs_operators && rhs_operators.any? && rhs_operators.first.node_value end end class PrimaryExpression < InfixExpression # AbstractExpression.traverse: postfix expression does not recurse # to UnitExpressions, instead yield block iterates using 'attribute_accessors' def expressions # expressions = recursive_select( Sexp::AbstactExpression ) super.select { |e| !e.is_a?(Sexp::UnitExpression) } end # AbstactExpression.travers yield if non-nil def expression_postfix return "has-attribute-accessors" if has_attribute_accessors end # Access record by field name or by value # @return [AbstactExpression:Array] to acccess record fields def attribute_accessors deffi = elements.select{ |e| e.is_a?( Sexp::UnitExpression )}.first return unless deffi && !deffi.text_value.empty? deffi = deffi.recursive_select( Sexp::AbstactExpression ) return deffi end # @return [boolean] true if expression defines record accessor def has_attribute_accessors attribute_accessors && attribute_accessors.any? end end class MultitiveExpression < InfixExpression end class LValue < Root # AbstractExpression.travers: no automatic traversal def expressions nil end # @return [AbstactExpression] for the LValue def expression recursive_select( Sexp::AbstactExpression).first end # implements lvalue include TlaParserS::LValue # Implement traverse down for 'recurse_lvalue'. In my case recurse # 'Sexp::UnitExpression', which define record access by value or by name # # @return [nil|RecordField] down next level in hierarchy def lvalue_down down = recursive_select( Sexp::UnitExpression ).first # down = recursive_select( Sexp::RecordField ).first # return nil unless down # down.recursive_select( Sexp::RecordField ).first end end class UnitExpression < AbstactExpression # implements lvalue include TlaParserS::LValue # Implement traversal for 'recurse_lvalue' # @return [nil|AbstractExpression] down next level in hierarchy def lvalue_down down = recursive_select( Sexp::AbstactExpression ).first end end class OperatorExpression < AbstactExpression # @return [String] operator name as expression value --> # `AbstactExpression` traverse yields in-order def expression_val operator_name end def operator_name recursive_select( Sexp::Identifier ).first.node_value end # @return [Expression:Array] list or arguments def arguments recursive_select( Sexp::Expression ) end def record_field_node recursive_select( Sexp::RecordField ).first end def record_field node = record_field_node return nil unless node node.node_value end # @return [Array] empty array to quit recursion in 'AbstactExpression' def expressions [] end end class PrefixExpression < AbstactExpression # during traverse: show operator before 'expression_val' def expression_prefix operator end def operator_node recursive_select( Sexp::Operator ).first end def operator operator_node.text_value end end class SimpleExpression < AbstactExpression # do not automatically recurse during 'traverse' def lhs_node nil end # def expression_value # text_value # end def expression_val text_value end end class ChooseExpression < SimpleExpression # @return [BoundInExpression] root node for x \in S def binds_node recursive_select( Sexp::BoundInExpression ).first end # Choose defines 'choose_expression' in left hand size # in binary tree modeling expression. # # @return [AbstractExpression] synxtax tree node for the quentified expression def choose_expression expressions.first end # For documentation purposes symbol table context needs a name # (For procedures, and macros name is ovbious. For a set # expression we define name set a string "Set+" # # @return [String] name identifying context in symbol table def name "Choose-in-#{binds_node.bind_set.text_value}" end # @return [Hash:Array] see 'symbol_definition' def symbol_definitions [symbol_definition] end # @return [Hash] of symbol_definition {:node_type,:value,:tree} # for the bind variabe in choose def symbol_definition { :node_type => node_type, :value => binds_node.bind_var.expression_val, :tree=>binds_node } end end # Parse goal class Expression < AbstactExpression end class QuantifyExpression < PrefixExpression # do not automatically recurse during 'traverse' def lhs_node nil end def binds_nodes recursive_select( Sexp::BindsInExpression ).first.recursive_select( Sexp::BoundInExpression ) end # Quantification defines 'quantified_expression' in left hand size # in binary tree modeling expression. # # @return [AbstractExpression] synxtax tree node for the quentified expression def quantified_expression expressions.first end # For documentation purposes symbol table context needs a name # (For procedures, and macros name is ovbious. For a set # expression we define name set a string "Set+" # # @return [String] name identifying context in symbol table def name "Quantification-??" end # Some variables in 'constructor_expression' (most likely) refer # to variable defined in set constructor generate. Return name of # this variables. # # @return [Array] of one hash with ':node_type',':value' properties def symbol_definitions binds_nodes.map do |binds_node| { :node_type => node_type, :value => binds_node.bind_var.expression_val, :tree=>binds_node } end end end class BoundInExpression < Root def bind_var elements.select{ |e| e.is_a?( Sexp::Identifier ) }.first end def bind_set elements.select{ |e| e.is_a?( Sexp::Expression ) }.first end end class BindsInExpression < Root end class SetExpressionDef < Root end class ParenthesisExpression < AbstactExpression def expression_prefix "(" end def expression_postfix ")" end end class RecordExcept < AbstactExpression def expressions nil end def lhs_node nil end def rhs_node nil end def expression_val "exprsssion" end def record_identifier recursive_select( Sexp::RecordExceptIdentifier ).first.recursive_select( Sexp::Identifier ).first.expression_val end def record_field_definitions # rigth recursion results to empty RecordExceptField -node recursive_select( Sexp::RecordExceptField ).select{ |f| f.elements && f.elements.any? } end end class RecordExceptField < Root def lvalue_expression recursive_select( Sexp::LValue ).first end def rvalue_expression # first is expression for lvalue recursive_select( Sexp::Expression ).last end end class RecordExceptIdentifier < Root end class RecordDefinition < AbstactExpression # output during 'AbstactExpression.traverse' def expression_val "[]" end # @return [RecordElement:Array] of record field definitions def record_fields ret = recursive_select( Sexp::RecordElement ) ret end end class RecordField < AbstactExpression # implements lvalue include TlaParserS::LValue # Implement traversal for 'recurse_lvalue' # @return [nil|RecordField] down next level in hierarchy def lvalue_down down = recursive_select( Sexp::RecordField ).first return nil unless down down.recursive_select( Sexp::RecordField ).first end # # @return [String] identifier name for lvalue # def lvalue # # default recursion creates string for expression lvalue # recurse_lvalue # end # AbstactExpression.traverse calls once: collect rec.id.field, # expression value is the lvalue def expression_val # return A, A.b, A.b[c] recurse_lvalue end end class RecordFieldName < RecordField # implements lvalue include TlaParserS::LValue # # @return [String] for record value return '[record_field]' # def record_field_value # "[#{record_name}]" # end end class SequenceExpression < AbstactExpression # AbstactExpression.travers def expression_val "<<>>" end # @return [Expression:Array] of sequence expressions def tuples recursive_select( Sexp::Expression ) end end class AbstractSetExpression < AbstactExpression # AbstactExpression.traverse quit traversing the expression def lhs_node nil end # AbstactExpression.traverse calls in yield def expression_val true end # Return set generator ( x \in Set ) for set constructor # # @return [BoundInExpression|nil] syntax tree node defining # generator variable and set def binds_node ret = recursive_select( Sexp::BoundInExpression ).first return nil unless ret ret = ret.recursive_select( Sexp::BoundInExpression ).first # puts ret ret end def set_expression deffi = recursive_select( Sexp::SetExpressionDef ) return nil unless deffi && deffi.any? ret = deffi.first.elements[0] # # ret = deffi.first.recursive_select( Sexp::SetExpression ).first # puts "set_expression=#{ret.inspect}" ret end # For documentation purposes symbol table context needs a name # (For procedures, and macros name is ovbious. For a set # expression we define name set a string "Set+" # # @return [String] name identifying context in symbol table def name "Set-#{binds_node.bind_set.text_value}" end # Some variables in 'set_expression' (most likely) refer to # variable defined in set constructor generate. Return name of # this variables. # # @return [Array] of one hash with ':node_type',':value' properties def symbol_definitions return [] unless binds_node [ { :node_type => node_type, :value => binds_node.bind_var.expression_val, :tree=>binds_node } ] end end class SetExpressionMap < AbstractSetExpression end class SetExpression < AbstractSetExpression end class FieldBy < AbstactExpression # AbstractExpression.traverse - do not recurse will evaluate separetetely def lhs_node nil end def rhs_node nil end end class FieldByName < FieldBy # @return [AbstactExpression] defining the name def field_name_expression recursive_select( Sexp::AbstactExpression ).first end def expression_val field_name_expression && field_name_expression.expression_val end # implements lvalue include TlaParserS::LValue def lvalue_down down = recursive_select( Sexp::UnitExpression ).first # down = recursive_select( Sexp::RecordField ).first # return nil unless down # down.recursive_select( Sexp::RecordField ).first end end class FieldByValue < FieldBy def expression_val field_value_expression && field_value_expression.expression_val end def field_value_expression recursive_select( Sexp::AbstactExpression ).first end # # @return [AbstactExpression] defining the value # def val_expression # recursive_select( Sexp::AbstactExpression ).first # end # implements lvalue include TlaParserS::LValue def lvalue_down down = recursive_select( Sexp::UnitExpression ).first # down = recursive_select( Sexp::RecordField ).first # return nil unless down # down.recursive_select( Sexp::RecordField ).first end end class UnaryExpression < PrefixExpression end class AdditiveExpression < InfixExpression end class Identifier < SimpleExpression # implements lvalue include TlaParserS::LValue # No need to recurse down from identifier def lvalue_down nil end # @return [String] identifier name for lvalue def lvalue node_value end end class Self < Identifier end class OriginalValue < SimpleExpression # implements lvalue include TlaParserS::LValue # No need to recurse down from identifier def lvalue_down nil end # @return [String] identifier name for lvalue def lvalue node_value end end class StringValue < SimpleExpression end class IntegerValue < SimpleExpression def expression_val retun 0 if text_value.nil? text_value.to_i end end # ------------------------------------------------------------------ # statements # Tree node with 'Label' and Unlabeled statement class Statement "name", :parameters => parameters, :body => body, } end # Symbols defined in this node # # @return [Hash:Array] symbol hash with ':node_type', :value, # :tree properties def symbol_definitions parameter_def = parameters return [] unless parameter_def parameter_def[:value] end end class Macro < Callable end class Procedure < Callable end class OperatorDef < Callable # For operator no body: def body_node tree_nodes = recursive_select(Sexp::Expression) return tree_nodes.first if tree_nodes end end # ------------------------------------------------------------------ # Variable class VariableDef < Define # def name recursive_select(Sexp::Identifier).first.node_value end # @return [Expression] tree node for init expression def init tree_nodes = recursive_select(Sexp::Expression).first end # Return entries for symbol table. In this case, add just variable # definition. # @return [Array] of 1 hash with :node_type, :value -properties def symbol_definitions [ { :node_type => node_type, :value => name } ] end end class RecordElement < Root def element_name recursive_select( Sexp::Identifier ).first end def element_expression recursive_select( Sexp::Expression ).first end end # ------------------------------------------------------------------ # simple class ReservedWord < Root end class Operator < Root end # class Body < RootContainer # end class VariableDeclaration < RootContainer end end