Object
Voodoo parser. The parser reads Voodoo source code and turns it into Ruby objects.
The public interface to Parser consists of the methods new and parse_top_level
Example usage:
require 'voodoo/parser' File.open('example.voo') do |infile| parser = Voodoo::Parser.new infile while (element = parser.parse_top_level) puts element.inspect end end
Creates a parser using the specified object as input. The input object must support a method getc, which must return the next character of the input, or nil to indicate the end of the input has been reached.
# File voodoo/parser.rb, line 31 def initialize input @input = input @input_name = input.respond_to?(:path) ? input.path : nil @start_line = @line = 1 @start_column = @column = 0 @lookahead = nil @text = '' end
Parses statements up to “end X”. kind should indicate the type of body being parsed: :block, :conditional, :function, or :group. Returns an array of statements.
# File voodoo/parser.rb, line 167 def parse_body kind wrap_exceptions do body = [] errors = [] case kind when :function kind_text = 'function definition' else kind_text = kind.to_s end # Groups are allowed to contain top-level statements. # All other kinds aren't. top_level = kind == :group done = false until done begin with_position do statement = parse_top_level_nonvalidating if statement == nil done = true parse_error "End of input while inside #{kind_text}", nil elsif statement[0] == :end # Done parsing body done = true elsif kind == :conditional && statement[0] == :else # Done parsing body, but there is another one coming up body << statement done = true else # Should be a normal statement. Validate it, then add it to body begin if top_level Validator.validate_top_level statement else Validator.validate_statement statement end body << statement rescue Validator::ValidationError => e magic_word = statement[0] if !top_level && Validator::TOP_LEVELS.member?(magic_word) && !Validator::STATEMENTS.member?(magic_word) parse_error "#{magic_word} is only allowed at top-level" else parse_error e.message end end end end rescue => e # Got some kind of error. Still try to parse the rest of the body. errors << e end end # Raise error if we had just one. # If we had more than one, raise a MultipleErrors instance. if errors.length == 1 raise errors[0] elsif errors.length > 1 raise MultipleErrors.new errors end body end end
Parses an escape sequence. This method should be called while the lookahead is the escape character (backslash). It decodes the escape sequence and returns the result as a string.
# File voodoo/parser.rb, line 239 def parse_escape wrap_exceptions do result = nil consume case lookahead when :eof parse_error "Unexpected end of input in escape sequence", nil when "\\", "\"", " " result = lookahead consume when "n" # \n is newline consume result = "\n" when "r" # \r is carriage return consume result = "\r" when "x" # \xXX is byte with hex value XX code = @input.read 2 @column = @column + 2 consume @text << code result = [code].pack('H2') when "\n" # \<newline> is line continuation character consume # Skip indentation of next line while lookahead =~ /\s/ consume end result = '' else # Default to just passing on next character result = lookahead consume end result end end
Parses a number. This method should be called while the lookahead is the first character of the number.
# File voodoo/parser.rb, line 284 def parse_number wrap_exceptions do text = lookahead consume while lookahead =~ /\d/ text << lookahead consume end text.to_i end end
Parses a string. This method should be called while the lookahead is the opening double quote.
# File voodoo/parser.rb, line 299 def parse_string wrap_exceptions do consume result = '' while true case lookahead when "\"" consume break when "\\" result << parse_escape else result << lookahead consume end end result end end
Parses a symbol. This method should be called while the lookahead is the first character of the symbol name.
# File voodoo/parser.rb, line 322 def parse_symbol parse_symbol1 '' end
Continues parsing a symbol. name the part of the symbol that has already been parsed.
# File voodoo/parser.rb, line 328 def parse_symbol1 name wrap_exceptions do while lookahead != :eof case lookahead when "\\" name << parse_escape when /\w|-/ name << lookahead consume when ':' # Colon parsed as last character of the symbol name name << lookahead consume break else break end end name.to_sym end end
Parses a top-level element. Returns an array containing the parts of the element.
Some examples (Voodoo code, Ruby return values in comments):
section functions # [:section, :functions] call foo x 12 # [:call, :foo, :x, 12] set x add x 42 # [:set, :x, :add, :x, 42] set-byte @x 1 10 # [:"set-byte", [:"@", :x], 1, 10] ifeq x y set z equal else set z not-equal end if # [:ifeq, [:x, :y], [[:set, :z, :equal]], [[:set, :z, :"not-equal"]]] foo: # [:label, :foo] function x y let z add x y return z end function # [:function, [:x, :y], [:let, :z, :add, :x, :y], [:return, :z]]
# File voodoo/parser.rb, line 152 def parse_top_level wrap_exceptions do @text = '' # Skip whitespace, comments, and empty lines skip_to_next_top_level validate_top_level do parse_top_level_nonvalidating end end end
Generated with the Darkfish Rdoc Generator 2.