require "./parser" class Specs property assignments : Hash(String, String) def initialize @assignments = Hash(String, String).new end def parse_hashglob(tree) # hashglob = hash hashglob | any hashglob | any | hash str = String.build do |str| case tree when Pegasus::Generated::TerminalTree str << tree.string when Pegasus::Generated::NonterminalTree tree.children.each do |it| str << parse_hashglob it end end end str end def parse_freetext(tree) # tabs hashglob cr freetext? case tree when Pegasus::Generated::TerminalTree raise "freetext: should not be terminal" when Pegasus::Generated::NonterminalTree current_line = parse_hashglob tree.children[1] current_line = current_line.lstrip(" ").rstrip(" ") str = String.build do |str| str << current_line str << "\n" if tree.children.size == 4 str << parse_freetext tree.children[3] end end str end end def parse_list_items(tree) # tabs dash glob cr listitem? | tabs comment cr listitem case tree when Pegasus::Generated::TerminalTree raise "parse_list_items: should not be terminal" when Pegasus::Generated::NonterminalTree if tree.children[1] == Pegasus::Generated::NonterminalTree str = String.build do |str| str << parse_list_items tree.children[3] end str else current_line = parse_glob tree.children[2] current_line = current_line.lstrip(" ").rstrip(" ") str = String.build do |str| str << current_line str << "\n" if tree.children.size == 5 str << parse_list_items tree.children[4] end end str end end end def parse_list(tree) # string colon cr listitem name = parse_string tree.children[0] value = parse_list_items tree.children[3] if name.nil? return end if value.nil? return end @assignments[name] = value end def parse_freetextblock(tree) # at multiplealphanum cr freetext name = parse_multiplealphanum tree.children[1] value = parse_freetext tree.children[3] if name.nil? return end if value.nil? return end @assignments[name] = value end def parse_glob (tree) # glob = any glob | any str = String.build do |str| case tree when Pegasus::Generated::TerminalTree str << tree.string when Pegasus::Generated::NonterminalTree tree.children.each do |it| str << parse_glob it end end end str end def parse_multiplealphanum(tree) # multiplealphanum = alphanum multiplealphanum? # alphanum = string | numbers str = String.build do |str| case tree when Pegasus::Generated::TerminalTree str << tree.string when Pegasus::Generated::NonterminalTree tree.children.each do |it| str << parse_multiplealphanum it end end end str end def parse_string(tree) case tree when Pegasus::Generated::TerminalTree return tree.string else raise "this should be a string but this is non terminal" end end def parse_assignment(tree) # string colon glob name = parse_string tree.children[0] value = parse_glob tree.children[2] value = value.lstrip(" ").rstrip(" ") if name.nil? return end if value.nil? return end @assignments[name] = value end def parse_tree(tree) case tree when Pegasus::Generated::TerminalTree # do nothing when Pegasus::Generated::NonterminalTree case tree.name when "freetextblock" ; parse_freetextblock tree when "freetext" ; parse_freetext tree when "assignment" ; parse_assignment tree when "list" ; parse_list tree when "comment" # do nothing else tree.children.each { |it| parse_tree(it) } end end end def rewrite # replaces all occurences of %{variable} by the content of @assignments[variable] @assignments.map do |k, v| reg = /%\{([^}]*)\}/ while v =~ reg x = reg.match(v) unless x.nil? var = x.captures() v = v.gsub "%{#{var[0]}}", "#{@assignments[var[0]]}" end end @assignments[k] = v end end def self.parse(file_name : String) : Specs | Nil begin content = File.read(file_name) content = content.rchop specs = Specs.new tree = Pegasus::Generated.process(content) specs.parse_tree tree specs.rewrite specs rescue e puts "Exception: #{e}" nil end end end