require_relative '../ast_generator' require_relative '../language' require_relative '../parsers/common' require_relative '../parsers/expression' require_relative '../resource' require_relative 'filter' require_relative 'model' module BELParser module Expression def self.parse( input, spec = BELParser::Language.default_specification, namespaces = {}) parser = Parser.new(input, Expression.filter, spec, namespaces) parser.parse end def self.parse_parameters( input, spec = BELParser::Language.default_specification, namespaces = {}) parser = Parser.new(input, Expression.parameter_filter, spec, namespaces) parser.parse end def self.parse_terms( input, spec = BELParser::Language.default_specification, namespaces = {}) parser = Parser.new(input, Expression.term_filter, spec, namespaces) parser.parse end def self.parse_statements( input, spec = BELParser::Language.default_specification, namespaces = {}) parser = Parser.new(input, Expression.statement_filter, spec, namespaces) parser.parse end # Parser for BEL expressions that return common objects. class Parser include BELParser::Expression::Model::Converters include BELParser::Parsers::AST def initialize( input, filter = Expression.filter, spec = BELParser::Language.default_specification, namespaces = {}) @input = input @filter = filter @spec = spec @namespaces = namespaces end def parse case @input when ::String # conflicts with ...AST::String results = parse_string(@input, @filter) return nil if results.nil? convert_ast( @spec, @namespaces, results.first) when Array convert_multiple( parse_array(@input, @filter), @spec, @namespaces) when IO, StringIO convert_stream( parse_io(@input, @filter), @spec, @namespaces) else raise ArgumentError, %(expected "input" to be one of String, Array, IO: #{@input.class}) end end private def convert_ast(spec, namespaces, ast) case ast when Parameter ast_to_parameter(ast, namespaces) when Term ast_to_term(ast, spec, namespaces) when Statement, ObservedTerm, SimpleStatement, NestedStatement ast_to_statement(ast, spec, namespaces) else nil end end def convert_multiple(asts, spec, namespaces) mult = method(:convert_ast).to_proc.curry[spec][namespaces] asts.lazy.map do |ast| if ast.respond_to?(:each) ast.map(&mult) else convert_ast(spec, namespaces, ast) end end end def convert_stream(asts, spec, namespaces) mult = method(:convert_ast).to_proc.curry[spec][namespaces] asts.lazy.flat_map do |ast| if ast.respond_to?(:each) ast.map(&mult) else convert_ast(spec, namespaces, ast) end end end def parse_string(string, filter) enum = filter.each( BELParser::ASTGenerator.new(StringIO.new(string))) num, line, results = enum.first if block_given? yield results nil else results end end def parse_array(array, filter) if block_given? array.each do |expression| yield parse_string(expression.to_s, filter) end nil else array.map do |expression| parse_string(expression.to_s, filter) end end end def parse_io(io, filter) if block_given? enum = filter.each(BELParser::ASTGenerator.new(io)) enum.each do |(num, line, results)| yield results end nil else enum_for(:parse_io, io, filter) end end end end end if __FILE__ == $PROGRAM_NAME namespaces = Hash[ ARGV.map do |ns| keyword, uri = ns.split('=') [keyword, BELParser::Expression::Model::Namespace.new(keyword, uri, nil)] end.compact ] BELParser::Expression.parse( $stdin, BELParser::Language.latest_supported_specification, namespaces ).each do |obj| puts " #{obj.class.name.split('::')[-1]}: #{obj}" end end