#!/usr/bin/ruby ############################################################# # Copyright (C) by Steve Litt, all rights reserved # Licensed under version 1 of the # Litt Scripting Language Development Tools License # See COPYING file # Or COPYING.LSLDTL.1.0 # Or see http://www.troubleshooters.com/licenses/LSLDTL/COPYING.LSLDTL.1.0 # # Node.rb version 0.01, pre-alpha, written by Steve Litt 12/7/2005 # Node.rb version 0.02, pre-alpha, written by Steve Litt 12/7/2005 # Added WalkerReverse # # # ABSOLUTELY NO WARRANTY, USE AT YOUR OWN RISK! ############################################################# class Node < Object def initialize(nam, type, value) super() @name = nam @type = type @value = value @attribs = {} @parent = nil @prevsibling = nil @nextsibling = nil @firstchild = nil @lastchild = nil end attr_reader :name, :type, :value attr_writer :name, :type, :value attr_reader :parent, :prevsibling, :nextsibling, :firstchild, :lastchild def setAttributes(attribs) @attribs = attribs; end def getAttributes() return @attribs; end def hasAttributes() return @attribs != nil; end def setAttribute(key, value) @attribs[key] = value; end def getAttribute(key) return @attribs[key]; end def hasAttribute(key) return @attribs[key] != nil; end protected attr_writer :parent, :prevsibling, :nextsibling, :firstchild, :lastchild def setParent(parent) @parent = parent node = self while node.prevsibling node = node.prevsibling end @parent.firstchild = node node = self while node.nextsibling node = node.nextsibling end @parent.lastchild = node @parent end public def insertSiblingAfterYou(newnode) nextSibTemp = self.nextsibling self.nextsibling = newnode newnode.parent = self.parent newnode.prevsibling = self newnode.nextsibling = nextSibTemp nextSibTemp.prevsibling = newnode if nextSibTemp self.parent.lastchild = newnode unless nextSibTemp self.parent.firstchild = newnode unless self.parent.firstchild return newnode end def insertSiblingBeforeYou(newnode) prevSibTemp = self.prevsibling self.prevsibling = newnode newnode.parent = self.parent newnode.nextsibling = self newnode.prevsibling = prevSibTemp prevSibTemp.nextsibling = newnode if prevSibTemp self.parent.firstchild = newnode unless prevSibTemp self.parent.lastchild = newnode unless self.parent.lastchild return newnode end def insertFirstChild(newnode) firstChildTemp = self.firstchild self.firstchild = newnode newnode.parent = self newnode.prevsibling = nil newnode.nextsibling = firstChildTemp firstChildTemp.prevsibling = newnode if firstChildTemp self.lastchild = newnode unless self.lastchild return newnode end def insertLastChild(newnode) lastChildTemp = self.lastchild self.lastchild = newnode newnode.parent = self newnode.nextsibling = nil newnode.prevsibling = lastChildTemp lastChildTemp.nextsibling = newnode if lastChildTemp self.firstchild = newnode unless self.firstchild return newnode end def deleteSelf() prev = self.prevsibling nextt = self.nextsibling if prev nextt.prevsibling = prev if nextt else self.parent.firstchild = nextt if self.parent nextt.prevsibling = nil if nextt end if nextt prev.nextsibling = nextt if prev else self.parent.lastchild = prev if self.parent prev.nextsibling = nil if prev end if !prev and !nextt and self.parent self.parent.firstchild = nil self.parent.lastchild = nil end self end end class WalkerReverse; def initialize(top, entrycallback, exitcallback) @top = top @entrycallback = entrycallback @exitcallback = exitcallback end def walk node = @top level = 0 ascending = false done = false while(not done) #### TAKE ACTION ON THE NODE unless ascending @entrycallback.call(node, level) if @entrycallback end #### WALK TO NEXT NODE if node.firstchild and not ascending # Down if possible node = node.lastchild ascending = false level += 1 elsif node.prevsibling #left if possible @exitcallback.call(node, level) if @exitcallback node = node.prevsibling ascending = false elsif node.parent #up if possible @exitcallback.call(node, level) if @exitcallback node = node.parent ascending = true level -= 1 else # can't go up, must be done @exitcallback.call(node, level) if @exitcallback done = true end end end end class Walker; def initialize(top, entrycallback, exitcallback) @top = top @entrycallback = entrycallback @exitcallback = exitcallback end def walk node = @top level = 0 ascending = false done = false while(not done) #### TAKE ACTION ON THE NODE unless ascending @entrycallback.call(node, level) if @entrycallback end if node.firstchild and not ascending # down if possible node = node.firstchild ascending = false level += 1 elsif node.nextsibling # else right if possible @exitcallback.call(node, level) if @exitcallback node = node.nextsibling ascending = false elsif node.parent # else up if possible @exitcallback.call(node, level) if @exitcallback node = node.parent ascending = true level -= 1 else # can't go up, must be done. @exitcallback.call(node, level) if @exitcallback done = true end end end end class OutlineParser def initialize @head=Node.new("Header Node", "Head", "Inserted by OutlineParser") @commentchar = '#' @skipblanks = true end attr_reader :commentchar, :skipblanks attr_writer :commentchar, :skipblanks def skipLine?(line) regex_comment = Regexp.new("^\\s*" + @commentchar ) if @skipblanks and line =~ /^\s*$/ return true elsif @commentchar and regex_comment.match(line) return true else return false end end def counttabs(s) answer = s.index(/[^\t]/) answer = 0 if not answer return answer end def parse(filename) @filename = filename #### SLURP OUTLINE lines = [] if filename infile = File.new(@filename, "r") lines = infile.readlines infile.close else while(line = gets) line.chomp! lines.push line end end #### PARSE OUTLINE node = @head prevlevel = 0 prevlevel_nonblank = 0 parentstack = [] parentstack.push(@head) for lineno in 1..lines.length line = lines[lineno-1] unless self.skipLine?(line) level = 1 + self.counttabs(line) if line =~ /^\s*$/ level = prevlevel_nonblank + 1 end newnode = Node.new("", "Node", line.strip); newnode.setAttribute('_lineno', lineno); if level == prevlevel parentstack[level] = parentstack[level].insertSiblingAfterYou(newnode) elsif level == prevlevel + 1 parentstack[level] = parentstack[prevlevel].insertFirstChild(newnode) elsif level < prevlevel parentstack[level] = parentstack[level].insertSiblingAfterYou(newnode) end prevlevel = level prevlevel_nonblank = level unless line =~ /^\s*$/ end end return @head end end