Created
March 10, 2009 21:13
Revisions
-
jolts created this gist
Mar 10, 2009 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,155 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../lib/rules' class ParseError < RuntimeError; end module Parser extend self def is_valid_rule?(str) $valid_rules.each do |key, regex| return true if str.match(regex) end raise ParseError, "'#{str}' unable to parse line: '#{@pos}'" false end def is_terminated?(str) str.match(/^end$\z/) ? true : false end def match_rule(str) $valid_rules.each { |key, regex| return key if str.match(regex) } false end def is_valid_args?(str) unless lambda { str.match(/(\d+\,)+\d+/) str.match(/\w+\(\w+\)/) str.match(/\(\)$/) } raise ParseError, "'#{str}' is not a valid method call, unable to parse line: '#{@pos}'" end end def is_block? (str, rule) if rule == :if_stmt or rule == :for_stmt or str.match(/end$/) or str.match(/do$/) true end end def parse_list(str) tokens = [/^list../, //] line = str.clone end def get_endposition # Returns an integer with index of the most outer end and put it in a # instance variable str = Array.new @string until str.empty? index = str.index("end") str.shift end 0 unless index end def parse_block(str, rule) block_tokens = {:in => /in/, :operator => /(==|=|!=|<=|>=)/, :left_token => /if|foreach\s+(\w+)\s+/, :right_token => /if|foreach\s+\w+\s+\w+\s+(.+)/, :end => /end/ } rule = match_rule str current_rule = {rule => []} until @pos == @end_pos block_tokens.each do |key, regex| if str.match(regex) if key == :operator current_rule[rule] << str[regex] elsif rule == :left_token current_rule[rule].insert(0, str[regex]) elsif rule == :right_token current_rule[rule] << str[regex] else current_rule[rule] << {key => str[regex].strip} end end @pos = @end_pos end end current_rule end def tokenize_rule(str, hash=nil) rule = match_rule @current_row hash = {rule => []} unless hash tokens = {:operator => /(==|=|!=|<=|>=)/, :internal_var => /^\$.+/, :variable => /(^\w+)/, :num => /\s+(\d+)/, :string => /(("|')(.+)("|'))/, :end => /end/} tokens.each do |key, regex| if str.match(regex) if key == :operator hash[rule] << str[regex] else if key == :variable and hash[rule][0] == ["print"] then; next; end hash[rule] << {key => str[regex]} end end end hash end def parse_func_call(str) current_rule = {:func_call => []} current_rule[:func_call] << str[/^(\w+\.\w+|\w+)/].split(/\./) current_rule = tokenize_rule str, current_rule current_rule end def tokenize(str, rule) if str.match(/do$/) current_rule = parse_block str, rule elsif rule == :func_call current_rule = parse_func_call str elsif is_valid_rule? str current_rule = tokenize_rule str elsif rule == :list current_rule = parse_list str, rule end current_rule end def parse(str) result = [] @string = str.clone.strip.split(/\n/) # We work on a copy of the string to parse @string.each do |row| rule = match_rule(row) @pos = @string.index(row) @end_pos = get_endposition if is_block? row, rule @current_row = row if rule puts rule current_rule = tokenize row, rule is_valid_args? row if rule == :func_call result << current_rule # Is ment to parse things lower down the parse-tree, like # expressions, variables assignments etc first, and then # gsub them out of stringing # Split string depending on rule and and put in an hash end end # Returns an array, where each element is a hash with key as a rule and # string to evaluate by evaluator result end end