lib/sql_tree/parser.rb in sql_tree-0.1.0 vs lib/sql_tree/parser.rb in sql_tree-0.1.1
- old
+ new
@@ -1,60 +1,116 @@
+# The <tt>SQLTree::Parser</tt> class is used to construct a syntax tree
+# using <tt>SQLTree::Node</tt> instances from a tree of tokens.
+#
+# This class does only kickstart the parsing process and manages the
+# token stream that is being parsed. The actual parsing of the nodes
+# occurs in the <tt>parse</tt> class method of the different node classes.
class SQLTree::Parser
+ # The <tt>SQLTree::Parser::UnexpectedToken</tt> exception is thrown
+ # when the parser meets a token that it not expect.
+ #
+ # This exceptions usually means that an SQL syntax error has been found,
+ # however it can also mean that the SQL construct that is being used is
+ # not (yet) supported by this library. Please create an issue on Github
+ # if the latter is the case.
class UnexpectedToken < StandardError
attr_reader :expected_token, :actual_token
- def initialize(actual_token, expected_token = nil)
+ def initialize(actual_token, expected_token = nil) # :nodoc:
@expected_token, @actual_token = expected_token, actual_token
message = "Unexpected token: found #{actual_token.inspect}"
message << ", but expected #{expected_token.inspect}" if expected_token
message << '!'
super(message)
end
end
-
+
+ # Kickstarts the parser by creating a new instance with the provided
+ # string, and calling the <tt>parse!</tt> method on this instance.
+ #
+ # Do not use this method directly, but use the <tt>SQLTree.[]</tt>
+ # method instead to parse SQL strings.
+ #
+ # <tt>sql_string</tt>:: The string to parse
+ # <tt>options</tt>:: Options to pass to the parser
def self.parse(sql_string, options = {})
self.new(sql_string, options).parse!
end
+ # Hash for parser options.
attr_reader :options
- def initialize(tokens, options)
- if tokens.kind_of?(String)
- @tokens = SQLTree::Tokenizer.new.tokenize(tokens)
- else
- @tokens = tokens
- end
+ # Initializes the parser instance.
+ # <tt>tokens</tt>:: The stream of tokens to turn into a syntax tree. If a
+ # string is given, it is tokenized automatically.
+ # <tt>options</tt>:: An optional hash of parser options.
+ def initialize(tokens, options = {})
+ @tokens = tokens.kind_of?(String) ? SQLTree::Tokenizer.tokenize(tokens) : tokens
@options = options
end
+ # Returns the current token that is being parsed.
def current
@current_token
end
+ # Returns the next token on the token queue, and moves the token queue
+ # one position forward. This will update the result of the
+ # <tt>SQLTree::Parser#current</tt> method.
def next
@current_token = @tokens.shift
end
- def consume(*checks)
+ # Consumes the current token(s), which will make the parser continue to the
+ # next token (see <tt>SQLTree::Parser#next</tt>).
+ #
+ # This method will also check if the consumed token is of the expected type.
+ # It will raise a <tt>SQLTree::Parser::UnexpectedToken</tt> exception if the
+ # consumed token is not of the expected type
+ #
+ # <tt>*checks</tt>:: a list of token types to consume.
+ def consume(*checks) # :raises: SQLTree::Parser::UnexpectedToken
checks.each do |check|
- raise UnexpectedToken.new(self.current, check) unless check == self.next
+ raise UnexpectedToken.new(self.current, check) unless check === self.next
end
end
- def peek(distance = 1)
- @tokens[distance - 1]
+ # Looks at the next token on the token queue without consuming it.
+ #
+ # The token queue will not be adjusted, will is the case when using
+ # <tt>SQLTree::Parser#next</tt>.
+ #
+ # <tt>lookahead</tt>:: the number of positions to look ahead. Defaults to 1.
+ def peek(lookahead = 1)
+ @tokens[lookahead - 1]
end
- def peek_tokens(amount)
- @tokens[0, amount]
+ # Peeks multiple tokens at the same time.
+ #
+ # This method will return an array of the requested number of tokens,
+ # except for when the token stream is nearing its end. In this case, the
+ # number of tokens returned can be less than requested.
+ # <tt>lookahead_amount</tt>:: the amount of tokens to return from the
+ # front of the token queue.
+ def peek_multiple(lookahead_amount)
+ @tokens[0, lookahead_amount]
end
+ # Prints the current list of tokens to $stdout for inspection.
def debug
puts @tokens.inspect
end
+ # Parser a complete SQL query into a tree of <tt>SQLTree::Node</tt> instances.
+ #
+ # Currently, SELECT, INSERT, UPDATE and DELETE queries are supported for
+ # the most part. This emthod should not be called directly, but is called
+ # by the <tt>SQLTree.[]</tt> method, e.g.:
+ #
+ # tree = SQLTree['SELECT * FROM table WHERE 1=1']
+ #
def parse!
case self.peek
when SQLTree::Token::SELECT then SQLTree::Node::SelectQuery.parse(self)
when SQLTree::Token::INSERT then SQLTree::Node::InsertQuery.parse(self)
when SQLTree::Token::DELETE then SQLTree::Node::DeleteQuery.parse(self)