Skip to content

Instantly share code, notes, and snippets.

@kdwinter
Forked from jolts/gist:77138
Created March 10, 2009 21:16
Show Gist options
  • Save kdwinter/77143 to your computer and use it in GitHub Desktop.
Save kdwinter/77143 to your computer and use it in GitHub Desktop.
#!/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
while str.reverse.shift
unless str[/end/]
next
else
index = str
end
end
return false 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment