summaryrefslogtreecommitdiffstats
path: root/tools/gn/parser.h
blob: 3348e2d225505033af347634c9befbd73d8f416e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_GN_PARSER_H_
#define TOOLS_GN_PARSER_H_

#include <map>
#include <vector>

#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "tools/gn/err.h"
#include "tools/gn/parse_tree.h"

class Parser;
typedef scoped_ptr<ParseNode> (Parser::*PrefixFunc)(Token token);
typedef scoped_ptr<ParseNode> (Parser::*InfixFunc)(scoped_ptr<ParseNode> left,
                                                   Token token);

extern const char kGrammar_Help[];

struct ParserHelper {
  PrefixFunc prefix;
  InfixFunc infix;
  int precedence;
};

// Parses a series of tokens. The resulting AST will refer to the tokens passed
// to the input, so the tokens an the file data they refer to must outlive your
// use of the ParseNode.
class Parser {
 public:
  // Will return a null pointer and set the err on error.
  static scoped_ptr<ParseNode> Parse(const std::vector<Token>& tokens,
                                     Err* err);

  // Alternative to parsing that assumes the input is an expression.
  static scoped_ptr<ParseNode> ParseExpression(const std::vector<Token>& tokens,
                                               Err* err);

  // Alternative to parsing that assumes the input is a literal value.
  static scoped_ptr<ParseNode> ParseValue(const std::vector<Token>& tokens,
                                          Err* err);

 private:
  // Vector must be valid for lifetime of call.
  Parser(const std::vector<Token>& tokens, Err* err);
  ~Parser();

  scoped_ptr<ParseNode> ParseExpression();

  // Parses an expression with the given precedence or higher.
  scoped_ptr<ParseNode> ParseExpression(int precedence);

  // |PrefixFunc|s used in parsing expressions.
  scoped_ptr<ParseNode> Literal(Token token);
  scoped_ptr<ParseNode> Name(Token token);
  scoped_ptr<ParseNode> Group(Token token);
  scoped_ptr<ParseNode> Not(Token token);
  scoped_ptr<ParseNode> List(Token token);
  scoped_ptr<ParseNode> BlockComment(Token token);

  // |InfixFunc|s used in parsing expressions.
  scoped_ptr<ParseNode> BinaryOperator(scoped_ptr<ParseNode> left, Token token);
  scoped_ptr<ParseNode> IdentifierOrCall(scoped_ptr<ParseNode> left,
                                         Token token);
  scoped_ptr<ParseNode> Assignment(scoped_ptr<ParseNode> left, Token token);
  scoped_ptr<ParseNode> Subscript(scoped_ptr<ParseNode> left, Token token);
  scoped_ptr<ParseNode> DotOperator(scoped_ptr<ParseNode> left, Token token);

  // Helper to parse a comma separated list, optionally allowing trailing
  // commas (allowed in [] lists, not in function calls).
  scoped_ptr<ListNode> ParseList(Token start_token,
                                 Token::Type stop_before,
                                 bool allow_trailing_comma);

  scoped_ptr<ParseNode> ParseFile();
  scoped_ptr<ParseNode> ParseStatement();
  scoped_ptr<BlockNode> ParseBlock();
  scoped_ptr<ParseNode> ParseCondition();

  // Generates a pre- and post-order traversal of the tree.
  void TraverseOrder(const ParseNode* root,
                     std::vector<const ParseNode*>* pre,
                     std::vector<const ParseNode*>* post);

  // Attach comments to nearby syntax.
  void AssignComments(ParseNode* file);

  bool IsAssignment(const ParseNode* node) const;
  bool IsStatementBreak(Token::Type token_type) const;

  bool LookAhead(Token::Type type);
  bool Match(Token::Type type);
  Token Consume(Token::Type type, const char* error_message);
  Token Consume(Token::Type* types,
                size_t num_types,
                const char* error_message);
  Token Consume();

  const Token& cur_token() const { return tokens_[cur_]; }

  bool done() const { return at_end() || has_error(); }
  bool at_end() const { return cur_ >= tokens_.size(); }
  bool has_error() const { return err_->has_error(); }

  std::vector<Token> tokens_;
  std::vector<Token> line_comment_tokens_;
  std::vector<Token> suffix_comment_tokens_;

  static ParserHelper expressions_[Token::NUM_TYPES];

  Err* err_;

  // Current index into the tokens.
  size_t cur_;

  FRIEND_TEST_ALL_PREFIXES(Parser, BinaryOp);
  FRIEND_TEST_ALL_PREFIXES(Parser, Block);
  FRIEND_TEST_ALL_PREFIXES(Parser, Condition);
  FRIEND_TEST_ALL_PREFIXES(Parser, Expression);
  FRIEND_TEST_ALL_PREFIXES(Parser, FunctionCall);
  FRIEND_TEST_ALL_PREFIXES(Parser, List);
  FRIEND_TEST_ALL_PREFIXES(Parser, ParenExpression);
  FRIEND_TEST_ALL_PREFIXES(Parser, UnaryOp);

  DISALLOW_COPY_AND_ASSIGN(Parser);
};

#endif  // TOOLS_GN_PARSER_H_