Class: SQLTree::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/sql_tree/parser.rb

Instance Method Summary collapse

Instance Method Details

#consume(check) ⇒ Object



11
12
13
# File 'lib/sql_tree/parser.rb', line 11

def consume(check)
  error(current_token) unless check == next_token
end

#current_tokenObject



3
4
5
# File 'lib/sql_tree/parser.rb', line 3

def current_token
  @current_token
end

#debugObject



23
24
25
# File 'lib/sql_tree/parser.rb', line 23

def debug
  p @tokens.inspect
end

#error(token) ⇒ Object



19
20
21
# File 'lib/sql_tree/parser.rb', line 19

def error(token)
  raise "Unexpected token: #{token.inspect}"
end

#next_tokenObject



7
8
9
# File 'lib/sql_tree/parser.rb', line 7

def next_token
  @current_token = @tokens.shift
end

#parse(tokens, options = {:as => :query}) ⇒ Object



27
28
29
30
31
32
33
34
35
36
# File 'lib/sql_tree/parser.rb', line 27

def parse(tokens, options = {:as => :query})
  if tokens.kind_of?(String)
    tokenizer = SQLTree::Tokenizer.new
    @tokens   = tokenizer.tokenize(tokens)
  else
    @tokens   = tokens
  end
  
  send("parse_#{options[:as]}".to_sym)
end

#parse_comparison_expressionObject



120
121
122
123
124
125
126
# File 'lib/sql_tree/parser.rb', line 120

def parse_comparison_expression
  expr = parse_primary_arithmetic_expression    
  while [SQLTree::Token::EQ, SQLTree::Token::NE, SQLTree::Token::GT, SQLTree::Token::GTE, SQLTree::Token::LT, SQLTree::Token::LTE].include?(peek_token)
    expr = SQLTree::Node::ComparisonExpression.new(next_token.literal, expr, parse_primary_arithmetic_expression)   
  end
  return expr
end

#parse_expressionObject



99
100
101
# File 'lib/sql_tree/parser.rb', line 99

def parse_expression
  parse_logical_expression
end

#parse_fieldObject



180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/sql_tree/parser.rb', line 180

def parse_field
  lhs = next_token
  lhs = (lhs == SQLTree::Token::MULTIPLY) ? :all : lhs.literal
  
  if peek_token == SQLTree::Token::DOT
    consume(SQLTree::Token::DOT)
    rhs = next_token
    rhs = (rhs == SQLTree::Token::MULTIPLY) ? :all : rhs.literal      
    SQLTree::Node::Field.new(rhs, lhs)
  else
    SQLTree::Node::Field.new(lhs)
  end
end

#parse_from_clauseObject



152
153
154
155
156
157
158
159
160
161
# File 'lib/sql_tree/parser.rb', line 152

def parse_from_clause
  consume(SQLTree::Token::FROM)
  from_expressions = [parse_from_expression]
  while peek_token == SQLTree::Token::COMMA
    consume(SQLTree::Token::COMMA)
    from_expressions << parse_from_expression
  end 

  return from_expressions    
end

#parse_from_expressionObject



163
164
165
166
167
168
169
# File 'lib/sql_tree/parser.rb', line 163

def parse_from_expression
  from_expression = case peek_token
    when SQLTree::Token::Variable;  parse_table_import
    else;                           error(peek_token)
  end
  return from_expression
end

#parse_function_callObject



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/sql_tree/parser.rb', line 140

def parse_function_call
  
  expr = SQLTree::Node::FunctionExpression.new(next_token.literal)
  consume(SQLTree::Token::LPAREN)
  until peek_token == SQLTree::Token::RPAREN
    expr.arguments << parse_expression
    consume(SQLTree::Token::COMMA) if peek_token == SQLTree::Token::COMMA
  end
  consume(SQLTree::Token::RPAREN)
  return expr
end

#parse_logical_expressionObject



128
129
130
131
132
133
134
# File 'lib/sql_tree/parser.rb', line 128

def parse_logical_expression
  expr = parse_comparison_expression
  while [SQLTree::Token::AND, SQLTree::Token::OR].include?(peek_token)
    expr = SQLTree::Node::LogicalExpression.new(next_token.literal, [expr, parse_comparison_expression])   
  end 
  return expr
end

#parse_logical_not_expressionObject



136
137
138
# File 'lib/sql_tree/parser.rb', line 136

def parse_logical_not_expression  
  
end

#parse_primary_arithmetic_expressionObject



112
113
114
115
116
117
118
# File 'lib/sql_tree/parser.rb', line 112

def parse_primary_arithmetic_expression
  expr = parse_secondary_arithmetic_expression
  while [SQLTree::Token::PLUS, SQLTree::Token::MINUS].include?(peek_token)
    expr = SQLTree::Node::ArithmeticExpression.new(next_token.literal, expr, parse_secondary_arithmetic_expression)
  end
  return expr    
end

#parse_queryObject



38
39
40
41
42
43
# File 'lib/sql_tree/parser.rb', line 38

def parse_query
  case peek_token
  when SQLTree::Token::SELECT; parse_select_query
  else raise "Could not parse query"
  end
end

#parse_secondary_arithmetic_expressionObject



103
104
105
106
107
108
109
# File 'lib/sql_tree/parser.rb', line 103

def parse_secondary_arithmetic_expression
  expr = parse_single_expression
  while [SQLTree::Token::PLUS, SQLTree::Token::MINUS].include?(peek_token)
    expr = SQLTree::Node::ArithmeticExpression.new(next_token.literal, expr, parse_single_expression)
  end
  return expr    
end

#parse_select_clauseObject



61
62
63
64
65
66
67
68
# File 'lib/sql_tree/parser.rb', line 61

def parse_select_clause
  expressions = [parse_select_expression]
  while peek_token == SQLTree::Token::COMMA
    consume(SQLTree::Token::COMMA)
    expressions << parse_select_expression
  end
  return expressions
end

#parse_select_expressionObject



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/sql_tree/parser.rb', line 70

def parse_select_expression
  if peek_token == SQLTree::Token::MULTIPLY
    consume(SQLTree::Token::MULTIPLY)
    return SQLTree::Node::ALL_FIELDS 
  else
    expr = SQLTree::Node::SelectExpression.new(parse_expression)
    if peek_token == SQLTree::Token::AS
      consume(SQLTree::Token::AS)
      expr.variable = parse_variable_name
    end
    return expr
  end
end

#parse_select_queryObject



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/sql_tree/parser.rb', line 45

def parse_select_query
  select_node = SQLTree::Node::SelectQuery.new
  consume(SQLTree::Token::SELECT)
  
  if peek_token == SQLTree::Token::DISTINCT
    consume(SQLTree::Token::DISTINCT)
    select_node.distinct = true
  end
  
  select_node.select = parse_select_clause 
  select_node.from   = parse_from_clause   if peek_token == SQLTree::Token::FROM
  select_node.where  = parse_where_clause  if peek_token == SQLTree::Token::WHERE
  
  return select_node
end

#parse_single_expressionObject



84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/sql_tree/parser.rb', line 84

def parse_single_expression
  if SQLTree::Token::LPAREN === peek_token(1)
    consume(SQLTree::Token::LPAREN)
    expr = parse_expression
    consume(SQLTree::Token::RPAREN)
    return expr
  elsif SQLTree::Token::Variable === peek_token(1)  && peek_token(2) == SQLTree::Token::LPAREN
    return parse_function_call
  elsif SQLTree::Token::Variable === peek_token(1)
    return parse_variable
  else
    return parse_value
  end    
end

#parse_table_importObject



171
172
173
174
175
176
177
178
# File 'lib/sql_tree/parser.rb', line 171

def parse_table_import
  table_import = SQLTree::Node::TableImport.new(next_token.literal)
  if peek_token == SQLTree::Token::AS || SQLTree::Token::Variable === peek_token
    consume(SQLTree::Token::AS) if peek_token == SQLTree::Token::AS
    table_import.variable = parse_variable
  end
  return table_import
end

#parse_valueObject



206
207
208
# File 'lib/sql_tree/parser.rb', line 206

def parse_value
  SQLTree::Node::Value.new(next_token.literal)
end

#parse_variableObject



198
199
200
201
202
203
204
# File 'lib/sql_tree/parser.rb', line 198

def parse_variable
  if peek_token(2) == SQLTree::Token::DOT
    parse_field
  else
    parse_variable_name
  end
end

#parse_variable_nameObject



194
195
196
# File 'lib/sql_tree/parser.rb', line 194

def parse_variable_name
  return SQLTree::Node::Variable.new(next_token.literal)
end

#parse_where_clauseObject



211
212
# File 'lib/sql_tree/parser.rb', line 211

def parse_where_clause
end

#peek_token(distance = 1) ⇒ Object



15
16
17
# File 'lib/sql_tree/parser.rb', line 15

def peek_token(distance = 1)
  @tokens[distance - 1]
end