lib/sgf/parser/tree_parse.rb in SgfParser-0.8.0 vs lib/sgf/parser/tree_parse.rb in SgfParser-0.9.0
- old
+ new
@@ -1,111 +1,97 @@
+require 'stringio'
+
module SgfParser
class Tree
private
- # This function parses a SGF string into a linked list, or tree.
+ # Creates a tree (truly, a linked list) from @sgf.
def parse
+ while char = next_character
+ case char
+ when '(' then store_branch
+ when ')' then fetch_branch
+ when ';' then store_node_and_create_new_node
+ when '[' then get_and_store_property
+ else store_character(char)
+ end
+ end
+ end
+
+ def next_character
+ character_available? && @stream.sysread(1)
+ end
+
+ def character_available?
+ @stream ||= StringIO.new clean_string, 'r'
+ !@stream.eof?
+ end
+
+ def clean_string
@sgf.gsub! "\\\\n\\\\r", ""
@sgf.gsub! "\\\\r\\\\n", ""
@sgf.gsub! "\\\\r", ""
@sgf.gsub! "\\\\n", ""
- #@sgf.gsub! "\n", ""
- branches = [] # This stores where new branches are open
- current_node = @root # Let's start at the beginning, shall we?
- identprop = false # We are not in the middle of an identprop value.
- # An identprop is an identity property - a value.
- content = Hash.new # Hash holding all the properties
- param, property = "", "" # Variables holding the idents and props
- end_of_a_series = false # To keep track of params with multiple properties
+ @sgf
+ end
- sgf_array = @sgf.split(//)
- iterator = 0
- array_length = sgf_array.size
+ def store_branch
+ @branches ||= []
+ @branches.unshift @current_node
+ end
- while iterator < array_length
- char = sgf_array[iterator]
- case char
-=begin
-Basically, if we're inside an identprop, it's a normal character (or a closing
-character).
-If we're not, it's either a property or a special SGF character so we have
-to handle that properly.
-=end
- when '(' # Opening a new branch
- if identprop
- property << char
- else
- branches.unshift current_node
- end
- when ')' # Closing a branch
- if identprop
- property << char
- else
- current_node = branches.shift
- param, property = "", ""
- content.clear
- end
- when ';' # Opening a new node
- if identprop
- property << char
- else
- # Make the current node the old node, make new node, store data
- parent = current_node
- current_node = Node.new :parent => parent
- parent.add_properties content
- parent.add_children current_node
- param, property = "", ""
- content.clear
- end
- when '[' # Open identprop?
- if identprop
- property << char
- else # If we're not inside an identprop, then now we are.
- identprop = true
- end_of_a_series = false
- end
- when ']' # Close identprop
-# Cleverness : checking for this first, then for the backslash.
-# This means that if we encounter this, it must be closing an identprop.
-# Because the "\\" code handles the logic to see if we're inside an identprop,
-# And for skipping the bracket if necessary.
- end_of_a_series = true # Maybe end of a series of identprop.
- identprop = false # That's our cue to close an identprop.
- content[param] = property
- property = ""
- when "\\"
- # If we're inside a comment, then maybe we're about to escape a ].
- # This is the whole reason we need this ugly loop.
- if identprop
- # If the next character is a closing bracket, then it's just
- # escaped and the identprop continues.
- if sgf_array[iterator + 1] == "]"
- property << "]"
- # On the next pass through, we will skip that bracket.
- iterator += 1
- else
- property << "\\"
- end
- else
- #This should never happen - a backslash outside an identprop ?!
- #But let's not have it be told that I'm not prepared.
- param << "\\"
- end
- when "\n"
- property << "\n" if identprop
+ def current_node
+ @current_node ||= @root
+ end
- else
- # Well, I guess it's "just" a character after all.
- if end_of_a_series
- end_of_a_series = false
- param, property = "", ""
- end
- identprop ? (property << char) : param << char
- end
- iterator += 1
+ def fetch_branch
+ @current_node = @branches.shift
+ clear_temporary_data
+ end
+
+ def store_node_and_create_new_node
+ parent = current_node
+ @current_node = Node.new :parent => parent
+ parent.add_properties content
+ parent.add_children @current_node
+ clear_temporary_data
+ end
+
+ def get_and_store_property
+ @content[@identity] ||= ""
+ @content[@identity] << get_property
+ @identity = ""
+ end
+
+ def get_property
+ buffer = ""
+ while true
+ next_bit = @stream.sysread(1)
+ break if next_bit == "]"
+ next_bit << @stream.sysread(1) if next_bit == "\\"
+ next_bit = "]" if next_bit == "\\]"
+ buffer << next_bit
end
+ buffer
+ end
+ def store_character(char)
+ @identity << char unless char == "\n"
end
+ def clear_temporary_data
+ @content.clear
+ @identity = ""
+ end
+
+ def content
+ @content ||= {}
+ end
+
+ def identity
+ @identity ||= ""
+ end
+
end
-end
\ No newline at end of file
+end
+