require 'bel_parser/parsers/ast/node' module BELParser module Language module Semantics class SignatureMapping include SemanticsFunction private_class_method :new # Map {BELParser::Parsers::AST::Term term} to BEL signatures defined # by a {BELParser::Language::Specification}. The mapping includes both # successful and failed signature matches. def self.map(term_ast, spec, namespaces) unless term_ast.is_a?(BELParser::Parsers::AST::Term) raise( ArgumentError, "term_ast: expected BELParser::Parsers::AST::Term") end function_name = term_ast.function.identifier.string_literal function = spec.function(function_name.to_sym) match = BELParser::Language::Semantics.method(:match) successes, failures = function.signatures .map { |sig| [sig, match.call(term_ast, sig.semantic_ast, spec)] } .partition { |(sig, results)| results.all?(&:success?) } if successes.empty? SignatureMappingWarning.new(term_ast, spec, failures) else SignatureMappingSuccess.new(term_ast, spec, successes, failures) end end end class SignatureMappingSuccess < SemanticsResult attr_reader :success_signatures attr_reader :failure_signatures def initialize(expression_node, spec, successes, failures) super(expression_node, spec) @success_signatures = successes @failure_signatures = failures end def to_s sig_list = success_signatures .map { |(sig, results)| sig.string_form } .join("\n ") <<-MSG.gsub(/ {12}/, '').gsub(/\n$/, '') Term matches function signatures: #{sig_list} MSG end end class SignatureMappingWarning < SemanticsWarning attr_reader :failure_signatures def initialize(expression_node, spec, failure_signatures) super(expression_node, spec) @failure_signatures = failure_signatures end def to_s sig_list = failure_signatures .map { |(sig, results)| sig.string_form } .join("\n ") <<-MSG.gsub(/ {12}/, '').gsub(/\n$/, '') Term did not conform to function signatures: #{sig_list} MSG end end end end end