class Utils::Parser
Public Class Methods
parse(file)
click to toggle source
# File lib/karel/utils/parser.rb, line 27 def self.parse(file) commands = Command::NATIVE.dup stack = [Command::Program.new] line_no = 0 File.readlines(file).each do |raw_line| line = raw_line.rstrip.gsub(/ *#.*/, '') line_no += 1 curr_indent = INDENTATION * (stack.length - 1) udf_match = line.match(/^def ([\w]+)$/) if_match = line.match(/^#{curr_indent}if (\!)?([\w?]+)$/) while_match = line.match(/^#{curr_indent}while (\!)?([\w?]+)$/) command_match = line.match(/^#{curr_indent}([\w?]+)$/) if udf_match if commands.key?(udf_match[1]) raise SyntaxError, "Line #{line_no}: command '#{udf_match[1]}' is already defined" end stack.push(Command::UserDefined.new(udf_match[1])) elsif if_match unless commands.key?(if_match[2]) raise SyntaxError, "Line #{line_no}: command '#{if_match[2]}' not recognized" end command = commands[if_match[2]] condition = if_match[1] ? Command::Not.new(command) : command stack.push(Command::If.new(condition)) elsif while_match unless commands.key?(while_match[2]) raise SyntaxError, "Line #{line_no}: command '#{while_match[1]}' not recognized" end command = commands[while_match[2]] condition = while_match[1] ? Command::Not.new(command) : command stack.push(Command::While.new(condition)) elsif command_match if commands.key?(command_match[1]) stack.last.add_statement(commands[command_match[1]]) else raise SyntaxError, "Line #{line_no}: command '#{command_match[1]}' not recognized" end elsif stack.length > 1 prev_indent = INDENTATION * (stack.length - 2) if line.match(/^#{prev_indent}else$/) if stack.last.is_a?(Command::If) begin stack.last.else! rescue ArgumentError => error raise SyntaxError, "Line #{line_no}: #{error.message}" end else raise SyntaxError, "Line #{line_no}: unexpected 'else' statement" end elsif line.match(/^#{prev_indent}end$/) statement = stack.pop if statement.is_a?(Command::UserDefined) commands[statement.name] = statement else stack.last.add_statement(statement) end elsif line =~ /#{curr_indent} / raise SyntaxError, "Line #{line_no}: invalid indentation" else raise SyntaxError, "Line #{line_no}: command '#{line}' not recognized" end elsif line =~ /#{curr_indent} / raise SyntaxError, "Line #{line_no}: inconsistent indentation" elsif line.strip != '' raise SyntaxError, "Line #{line_no}: command '#{line}' not recognized" end end raise SyntaxError, 'Unexpected end of input' if stack.length > 1 stack.pop end