Chromium Code Reviews| Index: tools/gn/parser.cc |
| diff --git a/tools/gn/parser.cc b/tools/gn/parser.cc |
| index 2a037fb24fa3a8275d3a05ae8327da902fbabe3c..88907035ade0f4c5725de2e16f6c18647f94dbbe 100644 |
| --- a/tools/gn/parser.cc |
| +++ b/tools/gn/parser.cc |
| @@ -9,14 +9,106 @@ |
| #include "tools/gn/operators.h" |
| #include "tools/gn/token.h" |
| -// grammar: |
| -// |
| -// file := (statement)* |
| -// statement := block | if | assignment |
| -// block := '{' statement* '}' |
| -// if := 'if' '(' expr ')' statement [ else ] |
| -// else := 'else' (if | statement)* |
| -// assignment := ident {'=' | '+=' | '-='} expr |
| +const char kSyntax_Help[] = |
| + "GN build language syntax\n" |
| + "\n" |
| + " This help topic defines the syntax of the GN build language.\n" |
| + "\n" |
| + "Tokens\n" |
| + "\n" |
| + " GN build files are read as sequences of tokens. While splitting the\n" |
| + " file into tokens, the next token is the longest sequence of characters\n" |
| + " that form a valid token.\n" |
| + "\n" |
| + "White space and comments\n" |
| + "\n" |
| + " White space is comprised of spaces (U+0020), horizontal tabs (U+0009),\n" |
| + " carriage returns (U+000D), and newlines (U+000A).\n" |
| + "\n" |
| + " Comments start at the character \"#\" and stop at the end of the line.\n" |
|
Dirk Pranke
2015/03/26 01:29:47
If you wanted to be picky, how is the "end of the
|
| + "\n" |
| + " White space and comments are ignored except that they may separate\n" |
| + " tokens that would otherwise combine into a single token.\n" |
| + "\n" |
| + "Identifiers\n" |
| + "\n" |
| + " Identifiers name variables and functions.\n" |
| + "\n" |
| + " identifier = letter { letter | digit } .\n" |
| + " letter = \"A\" ... \"Z\" | \"a\" ... \"z\" | \"_\" .\n" |
| + " digit = \"0\" ... \"9\" .\n" |
| + "\n" |
| + "Keywords\n" |
| + "\n" |
| + " The following keywords are reserved and may not be used as\n" |
| + " identifiers:\n" |
| + "\n" |
| + " else false if true\n" |
| + "\n" |
| + "Integer literals\n" |
| + "\n" |
| + " An integer literal represents a decimal integer value.\n" |
| + "\n" |
| + " integer = [ \"-\" ] digit { digit } .\n" |
| + "\n" |
| + "String literals\n" |
| + "\n" |
| + " A string literal represents a string value consisting of the quoted\n" |
| + " characters with possible escape sequences and variable expansions.\n" |
| + "\n" |
| + " string = `\"` { char | escape | expansion } `\"` .\n" |
| + " escape = `\\` ( \"$\" | `\"` | char ) .\n" |
| + " expansion = \"$\" ( identifier | \"{\" identifier \"}\" ) .\n" |
| + " char = /* any character except \"$\", `\"`, or newline */ .\n" |
| + "\n" |
| + " After a backslash, certain sequences represent special characters:\n" |
| + "\n" |
| + " \\\" U+0022 quotation mark\n" |
| + " \\$ U+0024 dollar sign\n" |
| + " \\\\ U+005c backslash\n" |
| + "\n" |
| + " All other backslashes represent themselves.\n" |
| + "\n" |
| + "Punctuation\n" |
| + "\n" |
| + " The following character sequences represent punctuation:\n" |
| + "\n" |
| + " + += == != ( )\n" |
| + " - -= < <= [ ]\n" |
| + " ! = > >= { }\n" |
| + " && || . ,\n" |
| + "\n" |
| + "Grammar\n" |
| + "\n" |
| + " The input tokens form a syntax tree following a context-free grammar:\n" |
| + "\n" |
| + " File = StatementList .\n" |
| + "\n" |
| + " Statement = Assignment | Call | Condition .\n" |
| + " Assignment = identifier AssignOp Expr .\n" |
| + " Call = identifier \"(\" ExprList \")\" [ Block ] .\n" |
| + " Condition = \"if\" \"(\" Expr \")\" Block\n" |
| + " [ \"else\" ( Condition | Block ) ] .\n" |
| + " Block = \"{\" StatementList \"}\" .\n" |
| + " StatementList = { Statement } .\n" |
| + "\n" |
| + " Expr = UnaryExpr | Expr BinaryOp Expr .\n" |
| + " UnaryExpr = PrimaryExpr | UnaryOp UnaryExpr .\n" |
| + " PrimaryExpr = identifier | integer | string | Call\n" |
| + " | identifier \"[\" Expr \"]\"\n" |
| + " | identifier \".\" identifier\n" |
| + " | \"(\" Expr \")\" | \"[\" ExprList \"] .\n" |
| + " ExprList = [ Expr { \",\" Expr } [ \",\" ] ] .\n" |
| + "\n" |
| + " AssignOp = \"=\" | \"+=\" | \"-=\" .\n" |
| + " UnaryOp = \"!\" .\n" |
| + " BinaryOp = \"+\" | \"-\" // highest priority\n" |
| + " | \"<\" | \"<=\" | \">\" | \">=\"\n" |
| + " | \"==\" | \"!=\"\n" |
| + " | \"&&\"\n" |
| + " | \"||\" . // lowest priority\n" |
| + "\n" |
| + " All binary operators are left-associative.\n"; |
| enum Precedence { |
| PRECEDENCE_ASSIGNMENT = 1, // Lowest precedence. |
| @@ -257,7 +349,7 @@ scoped_ptr<ParseNode> Parser::Not(Token token) { |
| } |
| scoped_ptr<ParseNode> Parser::List(Token node) { |
| - scoped_ptr<ParseNode> list(ParseList(node, Token::RIGHT_BRACKET, true)); |
| + scoped_ptr<ParseNode> list(ParseList(node, Token::RIGHT_BRACKET)); |
| if (!has_error() && !at_end()) |
| Consume(Token::RIGHT_BRACKET, "Expected ']'"); |
| return list.Pass(); |
| @@ -294,7 +386,7 @@ scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left, |
| if (Match(Token::RIGHT_PAREN)) { |
| // Nothing, just an empty call. |
| } else { |
| - list = ParseList(start_token, Token::RIGHT_PAREN, false); |
| + list = ParseList(start_token, Token::RIGHT_PAREN); |
| if (has_error()) |
| return scoped_ptr<ParseNode>(); |
| Consume(Token::RIGHT_PAREN, "Expected ')' after call"); |
| @@ -378,8 +470,7 @@ scoped_ptr<ParseNode> Parser::DotOperator(scoped_ptr<ParseNode> left, |
| // Does not Consume the start or end token. |
| scoped_ptr<ListNode> Parser::ParseList(Token start_token, |
| - Token::Type stop_before, |
| - bool allow_trailing_comma) { |
| + Token::Type stop_before) { |
| scoped_ptr<ListNode> list(new ListNode); |
| list->set_begin_token(start_token); |
| bool just_got_comma = false; |
| @@ -408,15 +499,11 @@ scoped_ptr<ListNode> Parser::ParseList(Token start_token, |
| if (list->contents().back()->AsBlockComment()) { |
| // If there was a comment inside the list, we don't need a comma to the |
| // next item, so pretend we got one, if we're expecting one. |
| - just_got_comma = allow_trailing_comma; |
| + just_got_comma = true; |
| } else { |
| just_got_comma = Match(Token::COMMA); |
| } |
| } |
| - if (just_got_comma && !allow_trailing_comma) { |
| - *err_ = Err(cur_token(), "Trailing comma"); |
| - return scoped_ptr<ListNode>(); |
| - } |
| list->set_end(make_scoped_ptr(new EndNode(cur_token()))); |
| return list.Pass(); |
| } |