class Parser
Attributes
src[R]
Public Class Methods
new( src, lang_config )
click to toggle source
# File lib/mulparse/parser.rb, line 24 def initialize( src, lang_config ) # Initialize a parser and set lang_config and other parsing configurations @src = src # src must be loaded from a text stream not a binary one if lang_config.class == String then # Open predefined lang-config @lang_config = YAML.load( IO.read( "#{File.absolute_path( File.expand_path( File.join( File.dirname( __FILE__ ), '..' ) ) )}" \ "/mulparse/lang-configs/#{lang_config}.yaml" ) ) else # Else use user provided lang-config @lang_config = lang_config end @position = 0 # Store the current Component @current = Component.new( finish: true ) end
Public Instance Methods
each( ) { |current| ... }
click to toggle source
# File lib/mulparse/parser.rb, line 51 def each( &block ) # Implements each method defined in Enumerable. # This method passes the next component parsed # in the srouce. The component is in the form # of a Component. loop do # Either finish the currentCN or open a new one on each iteration # Get the next start delimiter and its corresponding lcEntry next_start, start_entry = get_next_start() # Keep track of the existance of the finish attribute has_finish = @current.finish && @current.finish != true # A true value indicates the root Component if has_finish then # If finsih regex provided prepare closing regex closing_regex = @current.finish if closing_regex.is_a?( String ) then # Format in mirror to the closing_regex if mirror is provided if @current.hash then # Process hash argument if provided closing_regex = Regexp.new( closing_regex % Hash.new { |_, key| Regexp.escape( @current.hash[ @current.start_match[ key ] ] || @current.start_match[ key ] ) } ) else # Else process normally closing_regex = Regexp.new( closing_regex % Hash.new { |_, key| Regexp.escape( @current.start_match[ key ] ) } ) end end # Match for next closing delimiter next_finish = closing_regex.match( @src, @position ) raise UnmatchedException.new( @current.name, @src[ 0..@current.start_match.end( 0 ) ].count( "\n" ) + 1 ) unless next_finish # Ensure "escape" capture is valid until next_finish[ :escape ].length.even? # Match until length of "escape" capture is even next_finish = closing_regex.match( @src, next_finish.end( 0 ) ) end if closing_regex.names.include?( "escape" ) end if !next_start then # If done parsing yield last Component @current.finish_match = next_finish yield @current break end break if !next_start # Break if pasrsing is complete if @current&.parent && ( has_finish && ( @current.unestable || next_finish.begin( 0 ) < next_start.begin( 0 ) ) ) then # If current Component should be finished then finish it begin @position = next_finish.end( 0 ) # Update position rescue NoMethodError # Raise UnmatchedException if next_finish is nil raise UnmatchedException.new( @current.name, @src[ 0..@current.start_match.end( 0 ) ].count( "\n" ) + 1 ) end # Update parsing data @current.finish_match = next_finish # Yield finished Component yield @current # Set current Component to the previous's parent @current = @current.parent else # Else new Component is found set it as current @current = Component.new( next_start, @current, start_entry ) @position = next_start.end( 0 ) # Update position # Yield if Component uses syntactic sugar unestability unless @current.finish && @current.finish != true then yield @current @current = @current.parent end end end end
line()
click to toggle source
External/Internal Utility Methods
# File lib/mulparse/parser.rb, line 180 def line # Return number of lines already parsed return @src[ 0..@position ].count( "\n" ) end
Protected Instance Methods
get_next_start()
click to toggle source
Internal Utility Methods
# File lib/mulparse/parser.rb, line 191 def get_next_start # This method finds the nearest match of a # components starting delimiter in the @src. # Returns nil if there are no more matches. next_start = nil # Store the next starting delimiter lcEntry = nil # Store the lang config entry of next_start for i in @lang_config do # Test match against closest starting delimiter on each iteration matchBuffer = i[ :start ].match( @src, @position ) # Get a match next unless matchBuffer # If no match is found then skip to next iteration # Set the value of next_start to the closer match next_start = ( !next_start || matchBuffer.begin( 0 ) < next_start.begin( 0 ) ) ? matchBuffer : next_start if next_start == matchBuffer then lcEntry = i end # Update lcEntry if necessary end return next_start, lcEntry # Return the closest match end