Inversion::Parser::
State
class
Parse state object class. State
objects keep track of where in the parse tree new nodes should be appended, and manages inclusion.
- include_stack R
The stack of templates that have been loaded for this state; for loop detection.
- node_stack R
The stack of containers
- options R
The parse options in effect for this parse state
- template RW
The template object for this parser state
new( template, options={} )
Create a new State
object
def initialize( template, options={} )
@template = template
@options = options.dup
@tree = []
@node_stack = [ @tree ]
@include_stack = []
end
Append operator: add nodes to the correct part of the parse tree.
def <<( node )
node.before_appending( self )
self.node_stack.last << node
if node.is_container?
self.node_stack.push( node )
else
node.after_appending( self )
end
return self
rescue Inversion::ParseError => err
raise err, "%s at %s" % [ err.message, node.location ]
end
Append another Array of nodes onto this state’s node tree.
def append_tree( newtree )
newtree.each do |node|
self.node_stack.last << node
end
end
Clear any parsed nodes from the state, leaving the options and include_stack
intact.
def clear_nodes
@tree = []
@node_stack = [ @tree ]
end
Return the node that is currently being appended to, or ‘nil` if there aren’t any opened container nodes.
def current_node
return self.node_stack.last
end
initialize_copy( original )
Copy constructor – duplicate inner structures.
def initialize_copy( original )
@template = original.template
@options = original.options.dup
@tree = @tree.map( &:dup )
@node_stack = [ @tree ]
@include_stack = original.include_stack.dup
end
Load a subtemplate from the specified ‘path`, checking for recursive-dependency.
def load_subtemplate( path )
if self.include_stack.include?( path )
stack_desc = ( self.include_stack + [path] ).join( ' --> ' )
msg = "Recursive load of %p detected: from %s" % [ path, stack_desc ]
self.log.error( msg )
raise Inversion::StackError, msg
end
substate = self.dup
substate.clear_nodes
substate.include_stack.push( path )
return Inversion::Template.load( path, substate, self.options )
end
Pop one level off of the node stack and return it.
def pop
closed_node = self.node_stack.pop
raise Inversion::ParseError, "unbalanced end: no open tag" if
self.node_stack.empty?
closed_node.after_appending( self )
return closed_node
end
Returns the tree if it’s well formed.
def tree
unless self.is_well_formed?
raise Inversion::ParseError, "Unclosed container tag: %s, from %s" %
[ self.node_stack.last.tagname, self.node_stack.last.location ]
end
return @tree
end