Skip to content

Instantly share code, notes, and snippets.

@jolts
Created March 10, 2009 21:13

Revisions

  1. jolts created this gist Mar 10, 2009.
    155 changes: 155 additions & 0 deletions gistfile1
    Original 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