PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/DICK.B1/IronPython/Compiler/Parser.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 3130 lines | 2384 code | 426 blank | 320 comment | 508 complexity | 1df9e36645a8faea79f2dae701aef7fb MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.IO;
  19. using Microsoft.Scripting;
  20. using Microsoft.Scripting.Runtime;
  21. using Microsoft.Scripting.Utils;
  22. using IronPython.Compiler.Ast;
  23. using IronPython.Hosting;
  24. using IronPython.Runtime;
  25. using IronPython.Runtime.Types;
  26. #if CLR2
  27. using Microsoft.Scripting.Math;
  28. #else
  29. using System.Numerics;
  30. #endif
  31. namespace IronPython.Compiler {
  32. public class Parser : IDisposable { // TODO: remove IDisposable
  33. // immutable properties:
  34. private readonly Tokenizer _tokenizer;
  35. // mutable properties:
  36. private ErrorSink _errors;
  37. private ParserSink _sink;
  38. // resettable properties:
  39. private SourceUnit _sourceUnit;
  40. /// <summary>
  41. /// Language features initialized on parser construction and possibly updated during parsing.
  42. /// The code can set the language features (e.g. "from __future__ import division").
  43. /// </summary>
  44. private ModuleOptions _languageFeatures;
  45. // state:
  46. private TokenWithSpan _token;
  47. private TokenWithSpan _lookahead;
  48. private Stack<FunctionDefinition> _functions;
  49. private bool _fromFutureAllowed;
  50. private string _privatePrefix;
  51. private bool _parsingStarted, _allowIncomplete;
  52. private bool _inLoop, _inFinally, _isGenerator, _returnWithValue;
  53. private SourceCodeReader _sourceReader;
  54. private int _errorCode;
  55. private readonly CompilerContext _context;
  56. private static readonly char[] newLineChar = new char[] { '\n' };
  57. private static readonly char[] whiteSpace = { ' ', '\t' };
  58. #region Construction
  59. private Parser(CompilerContext context, Tokenizer tokenizer, ErrorSink errorSink, ParserSink parserSink, ModuleOptions languageFeatures) {
  60. ContractUtils.RequiresNotNull(tokenizer, "tokenizer");
  61. ContractUtils.RequiresNotNull(errorSink, "errorSink");
  62. ContractUtils.RequiresNotNull(parserSink, "parserSink");
  63. tokenizer.ErrorSink = new TokenizerErrorSink(this);
  64. _tokenizer = tokenizer;
  65. _errors = errorSink;
  66. _sink = parserSink;
  67. _context = context;
  68. Reset(tokenizer.SourceUnit, languageFeatures);
  69. }
  70. public static Parser CreateParser(CompilerContext context, PythonOptions options) {
  71. return CreateParserWorker(context, options, false);
  72. }
  73. [Obsolete("pass verbatim via PythonCompilerOptions in PythonOptions")]
  74. public static Parser CreateParser(CompilerContext context, PythonOptions options, bool verbatim) {
  75. return CreateParserWorker(context, options, verbatim);
  76. }
  77. private static Parser CreateParserWorker(CompilerContext context, PythonOptions options, bool verbatim) {
  78. ContractUtils.RequiresNotNull(context, "context");
  79. ContractUtils.RequiresNotNull(options, "options");
  80. PythonCompilerOptions compilerOptions = context.Options as PythonCompilerOptions;
  81. if (options == null) {
  82. throw new ArgumentException(Resources.PythonContextRequired);
  83. }
  84. SourceCodeReader reader;
  85. try {
  86. reader = context.SourceUnit.GetReader();
  87. if (compilerOptions.SkipFirstLine) {
  88. reader.ReadLine();
  89. }
  90. } catch (IOException e) {
  91. context.Errors.Add(context.SourceUnit, e.Message, SourceSpan.Invalid, 0, Severity.Error);
  92. throw;
  93. }
  94. Tokenizer tokenizer = new Tokenizer(context.Errors, compilerOptions, verbatim);
  95. tokenizer.Initialize(null, reader, context.SourceUnit, SourceLocation.MinValue);
  96. tokenizer.IndentationInconsistencySeverity = options.IndentationInconsistencySeverity;
  97. Parser result = new Parser(context, tokenizer, context.Errors, context.ParserSink, compilerOptions.Module);
  98. result._sourceReader = reader;
  99. return result;
  100. }
  101. #endregion
  102. #region Public parser interface
  103. public PythonAst ParseFile(bool makeModule) {
  104. return ParseFile(makeModule, false);
  105. }
  106. //single_input: Newline | simple_stmt | compound_stmt Newline
  107. //eval_input: testlist Newline* ENDMARKER
  108. //file_input: (Newline | stmt)* ENDMARKER
  109. public PythonAst ParseFile(bool makeModule, bool returnValue) {
  110. try {
  111. return ParseFileWorker(makeModule, returnValue);
  112. } catch (BadSourceException bse) {
  113. throw BadSourceError(bse);
  114. }
  115. }
  116. //[stmt_list] Newline | compound_stmt Newline
  117. //stmt_list ::= simple_stmt (";" simple_stmt)* [";"]
  118. //compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
  119. //Returns a simple or coumpound_stmt or null if input is incomplete
  120. /// <summary>
  121. /// Parse one or more lines of interactive input
  122. /// </summary>
  123. /// <returns>null if input is not yet valid but could be with more lines</returns>
  124. public PythonAst ParseInteractiveCode(out ScriptCodeParseResult properties) {
  125. bool parsingMultiLineCmpdStmt;
  126. bool isEmptyStmt = false;
  127. properties = ScriptCodeParseResult.Complete;
  128. StartParsing();
  129. Statement ret = InternalParseInteractiveInput(out parsingMultiLineCmpdStmt, out isEmptyStmt);
  130. if (_errorCode == 0) {
  131. if (isEmptyStmt) {
  132. properties = ScriptCodeParseResult.Empty;
  133. } else if (parsingMultiLineCmpdStmt) {
  134. properties = ScriptCodeParseResult.IncompleteStatement;
  135. }
  136. if (isEmptyStmt) {
  137. return null;
  138. }
  139. return new PythonAst(ret, false, _languageFeatures, true, _context);
  140. } else {
  141. if ((_errorCode & ErrorCodes.IncompleteMask) != 0) {
  142. if ((_errorCode & ErrorCodes.IncompleteToken) != 0) {
  143. properties = ScriptCodeParseResult.IncompleteToken;
  144. return null;
  145. }
  146. if ((_errorCode & ErrorCodes.IncompleteStatement) != 0) {
  147. if (parsingMultiLineCmpdStmt) {
  148. properties = ScriptCodeParseResult.IncompleteStatement;
  149. } else {
  150. properties = ScriptCodeParseResult.IncompleteToken;
  151. }
  152. return null;
  153. }
  154. }
  155. properties = ScriptCodeParseResult.Invalid;
  156. return null;
  157. }
  158. }
  159. public PythonAst ParseSingleStatement() {
  160. try {
  161. StartParsing();
  162. MaybeEatNewLine();
  163. Statement statement = ParseStmt();
  164. EatEndOfInput();
  165. return new PythonAst(statement, false, _languageFeatures, true, _context);
  166. } catch (BadSourceException bse) {
  167. throw BadSourceError(bse);
  168. }
  169. }
  170. public PythonAst ParseTopExpression() {
  171. try {
  172. // TODO: move from source unit .TrimStart(' ', '\t')
  173. ReturnStatement ret = new ReturnStatement(ParseTestListAsExpression());
  174. ret.SetLoc(SourceSpan.None);
  175. return new PythonAst(ret, false, _languageFeatures, false, _context);
  176. } catch (BadSourceException bse) {
  177. throw BadSourceError(bse);
  178. }
  179. }
  180. /// <summary>
  181. /// Given the interactive text input for a compound statement, calculate what the
  182. /// indentation level of the next line should be
  183. /// </summary>
  184. public static int GetNextAutoIndentSize(string text, int autoIndentTabWidth) {
  185. ContractUtils.RequiresNotNull(text, "text");
  186. Debug.Assert(text[text.Length - 1] == '\n');
  187. string[] lines = text.Split(newLineChar);
  188. if (lines.Length <= 1) return 0;
  189. string lastLine = lines[lines.Length - 2];
  190. // Figure out the number of white-spaces at the start of the last line
  191. int startingSpaces = 0;
  192. while (startingSpaces < lastLine.Length && lastLine[startingSpaces] == ' ')
  193. startingSpaces++;
  194. // Assume the same indent as the previous line
  195. int autoIndentSize = startingSpaces;
  196. // Increase the indent if this looks like the start of a compounds statement.
  197. // Ideally, we would ask the parser to tell us the exact indentation level
  198. if (lastLine.TrimEnd(whiteSpace).EndsWith(":"))
  199. autoIndentSize += autoIndentTabWidth;
  200. return autoIndentSize;
  201. }
  202. public ErrorSink ErrorSink {
  203. get {
  204. return _errors;
  205. }
  206. set {
  207. ContractUtils.RequiresNotNull(value, "value");
  208. _errors = value;
  209. }
  210. }
  211. public ParserSink ParserSink {
  212. get {
  213. return _sink;
  214. }
  215. set {
  216. ContractUtils.RequiresNotNull(value, "value");
  217. _sink = value;
  218. }
  219. }
  220. public int ErrorCode {
  221. get { return _errorCode; }
  222. }
  223. public void Reset(SourceUnit sourceUnit, ModuleOptions languageFeatures) {
  224. ContractUtils.RequiresNotNull(sourceUnit, "sourceUnit");
  225. _sourceUnit = sourceUnit;
  226. _languageFeatures = languageFeatures;
  227. _token = new TokenWithSpan();
  228. _lookahead = new TokenWithSpan();
  229. _fromFutureAllowed = true;
  230. _functions = null;
  231. _privatePrefix = null;
  232. _parsingStarted = false;
  233. _errorCode = 0;
  234. }
  235. public void Reset() {
  236. Reset(_sourceUnit, _languageFeatures);
  237. }
  238. #endregion
  239. #region Error Reporting
  240. private void ReportSyntaxError(TokenWithSpan t) {
  241. ReportSyntaxError(t, ErrorCodes.SyntaxError);
  242. }
  243. private void ReportSyntaxError(TokenWithSpan t, int errorCode) {
  244. ReportSyntaxError(t.Token, t.Span, errorCode, true);
  245. }
  246. private void ReportSyntaxError(Token t, SourceSpan span, int errorCode, bool allowIncomplete) {
  247. SourceLocation start = span.Start;
  248. SourceLocation end = span.End;
  249. if (allowIncomplete && (t.Kind == TokenKind.EndOfFile || (_tokenizer.IsEndOfFile && (t.Kind == TokenKind.Dedent || t.Kind == TokenKind.NLToken)))) {
  250. errorCode |= ErrorCodes.IncompleteStatement;
  251. }
  252. string msg = String.Format(System.Globalization.CultureInfo.InvariantCulture, GetErrorMessage(t, errorCode), t.Image);
  253. ReportSyntaxError(start, end, msg, errorCode);
  254. }
  255. private static string GetErrorMessage(Token t, int errorCode) {
  256. string msg;
  257. if ((errorCode & ~ErrorCodes.IncompleteMask) == ErrorCodes.IndentationError) {
  258. msg = Resources.ExpectedIndentation;
  259. } else if (t.Kind != TokenKind.EndOfFile) {
  260. msg = Resources.UnexpectedToken;
  261. } else {
  262. msg = "unexpected EOF while parsing";
  263. }
  264. return msg;
  265. }
  266. private void ReportSyntaxError(string message) {
  267. ReportSyntaxError(_lookahead.Span.Start, _lookahead.Span.End, message);
  268. }
  269. internal void ReportSyntaxError(SourceLocation start, SourceLocation end, string message) {
  270. ReportSyntaxError(start, end, message, ErrorCodes.SyntaxError);
  271. }
  272. internal void ReportSyntaxError(SourceLocation start, SourceLocation end, string message, int errorCode) {
  273. // save the first one, the next error codes may be induced errors:
  274. if (_errorCode == 0) {
  275. _errorCode = errorCode;
  276. }
  277. _errors.Add(_sourceUnit, message, new SourceSpan(start, end), errorCode, Severity.FatalError);
  278. }
  279. #endregion
  280. #region LL(1) Parsing
  281. private static bool IsPrivateName(string name) {
  282. return name.StartsWith("__") && !name.EndsWith("__");
  283. }
  284. private string FixName(string name) {
  285. if (_privatePrefix != null && IsPrivateName(name)) {
  286. name = string.Format("_{0}{1}", _privatePrefix, name);
  287. }
  288. return name;
  289. }
  290. private string ReadNameMaybeNone() {
  291. // peek for better error recovery
  292. Token t = PeekToken();
  293. if (t == Tokens.NoneToken) {
  294. NextToken();
  295. return "None";
  296. }
  297. NameToken n = t as NameToken;
  298. if (n == null) {
  299. ReportSyntaxError("syntax error");
  300. return null;
  301. }
  302. NextToken();
  303. return FixName(n.Name);
  304. }
  305. private string ReadName() {
  306. NameToken n = PeekToken() as NameToken;
  307. if (n == null) {
  308. ReportSyntaxError(_lookahead);
  309. return null;
  310. }
  311. NextToken();
  312. return FixName(n.Name);
  313. }
  314. //stmt: simple_stmt | compound_stmt
  315. //compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
  316. private Statement ParseStmt() {
  317. switch (PeekToken().Kind) {
  318. case TokenKind.KeywordIf:
  319. return ParseIfStmt();
  320. case TokenKind.KeywordWhile:
  321. return ParseWhileStmt();
  322. case TokenKind.KeywordFor:
  323. return ParseForStmt();
  324. case TokenKind.KeywordTry:
  325. return ParseTryStatement();
  326. case TokenKind.At:
  327. return ParseDecorated();
  328. case TokenKind.KeywordDef:
  329. return ParseFuncDef();
  330. case TokenKind.KeywordClass:
  331. return ParseClassDef();
  332. case TokenKind.KeywordWith:
  333. return ParseWithStmt();
  334. default:
  335. return ParseSimpleStmt();
  336. }
  337. }
  338. //simple_stmt: small_stmt (';' small_stmt)* [';'] Newline
  339. private Statement ParseSimpleStmt() {
  340. Statement s = ParseSmallStmt();
  341. if (MaybeEat(TokenKind.Semicolon)) {
  342. SourceLocation start = s.Start;
  343. List<Statement> l = new List<Statement>();
  344. l.Add(s);
  345. while (true) {
  346. if (MaybeEatNewLine() || MaybeEat(TokenKind.EndOfFile)) {
  347. break;
  348. }
  349. l.Add(ParseSmallStmt());
  350. if (MaybeEat(TokenKind.EndOfFile)) {
  351. // implies a new line
  352. break;
  353. } else if (!MaybeEat(TokenKind.Semicolon)) {
  354. EatNewLine();
  355. break;
  356. }
  357. }
  358. Statement[] stmts = l.ToArray();
  359. SuiteStatement ret = new SuiteStatement(stmts);
  360. ret.SetLoc(start, stmts[stmts.Length - 1].End);
  361. return ret;
  362. } else if (!MaybeEat(TokenKind.EndOfFile) && !EatNewLine()) {
  363. // error handling, make sure we're making forward progress
  364. NextToken();
  365. }
  366. return s;
  367. }
  368. /*
  369. small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
  370. del_stmt: 'del' exprlist
  371. pass_stmt: 'pass'
  372. flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
  373. break_stmt: 'break'
  374. continue_stmt: 'continue'
  375. return_stmt: 'return' [testlist]
  376. yield_stmt: 'yield' testlist
  377. */
  378. private Statement ParseSmallStmt() {
  379. switch (PeekToken().Kind) {
  380. case TokenKind.KeywordPrint:
  381. return ParsePrintStmt();
  382. case TokenKind.KeywordPass:
  383. return FinishSmallStmt(new EmptyStatement());
  384. case TokenKind.KeywordBreak:
  385. if (!_inLoop) {
  386. ReportSyntaxError("'break' outside loop");
  387. }
  388. return FinishSmallStmt(new BreakStatement());
  389. case TokenKind.KeywordContinue:
  390. if (!_inLoop) {
  391. ReportSyntaxError("'continue' not properly in loop");
  392. } else if (_inFinally) {
  393. ReportSyntaxError("'continue' not supported inside 'finally' clause");
  394. }
  395. return FinishSmallStmt(new ContinueStatement());
  396. case TokenKind.KeywordReturn:
  397. return ParseReturnStmt();
  398. case TokenKind.KeywordFrom:
  399. return ParseFromImportStmt();
  400. case TokenKind.KeywordImport:
  401. return ParseImportStmt();
  402. case TokenKind.KeywordGlobal:
  403. return ParseGlobalStmt();
  404. case TokenKind.KeywordRaise:
  405. return ParseRaiseStmt();
  406. case TokenKind.KeywordAssert:
  407. return ParseAssertStmt();
  408. case TokenKind.KeywordExec:
  409. return ParseExecStmt();
  410. case TokenKind.KeywordDel:
  411. return ParseDelStmt();
  412. case TokenKind.KeywordYield:
  413. return ParseYieldStmt();
  414. default:
  415. return ParseExprStmt();
  416. }
  417. }
  418. // del_stmt: "del" target_list
  419. // for error reporting reasons we allow any expression and then report the bad
  420. // delete node when it fails. This is the reason we don't call ParseTargetList.
  421. private Statement ParseDelStmt() {
  422. NextToken();
  423. SourceLocation start = GetStart();
  424. List<Expression> l = ParseExprList();
  425. foreach (Expression e in l) {
  426. string delError = e.CheckDelete();
  427. if (delError != null) {
  428. ReportSyntaxError(e.Span.Start, e.Span.End, delError, ErrorCodes.SyntaxError);
  429. }
  430. }
  431. DelStatement ret = new DelStatement(l.ToArray());
  432. ret.SetLoc(start, GetEnd());
  433. return ret;
  434. }
  435. private Statement ParseReturnStmt() {
  436. if (CurrentFunction == null) {
  437. ReportSyntaxError(IronPython.Resources.MisplacedReturn);
  438. }
  439. NextToken();
  440. Expression expr = null;
  441. SourceLocation start = GetStart();
  442. if (!NeverTestToken(PeekToken())) {
  443. expr = ParseTestListAsExpr(true);
  444. }
  445. if (expr != null) {
  446. _returnWithValue = true;
  447. if (_isGenerator) {
  448. ReportSyntaxError("'return' with argument inside generator");
  449. }
  450. }
  451. ReturnStatement ret = new ReturnStatement(expr);
  452. ret.SetLoc(start, GetEnd());
  453. return ret;
  454. }
  455. private Statement FinishSmallStmt(Statement stmt) {
  456. NextToken();
  457. stmt.SetLoc(GetStart(), GetEnd());
  458. return stmt;
  459. }
  460. private Statement ParseYieldStmt() {
  461. // For yield statements, continue to enforce that it's currently in a function.
  462. // This gives us better syntax error reporting for yield-statements than for yield-expressions.
  463. FunctionDefinition current = CurrentFunction;
  464. if (current == null) {
  465. ReportSyntaxError(IronPython.Resources.MisplacedYield);
  466. }
  467. _isGenerator = true;
  468. if (_returnWithValue) {
  469. ReportSyntaxError("'return' with argument inside generator");
  470. }
  471. Eat(TokenKind.KeywordYield);
  472. // See Pep 342: a yield statement is now just an expression statement around a yield expression.
  473. Expression e = ParseYieldExpression();
  474. Debug.Assert(e != null); // caller already verified we have a yield.
  475. Statement s = new ExpressionStatement(e);
  476. s.SetLoc(e.Span);
  477. return s;
  478. }
  479. /// <summary>
  480. /// Peek if the next token is a 'yield' and parse a yield expression. Else return null.
  481. ///
  482. /// Called w/ yield already eaten.
  483. /// </summary>
  484. /// <returns>A yield expression if present, else null. </returns>
  485. // yield_expression: "yield" [expression_list]
  486. private Expression ParseYieldExpression() {
  487. // Mark that this function is actually a generator.
  488. // If we're in a generator expression, then we don't have a function yet.
  489. // g=((yield i) for i in range(5))
  490. // In that acse, the genexp will mark IsGenerator.
  491. FunctionDefinition current = CurrentFunction;
  492. if (current != null) {
  493. current.IsGenerator = true;
  494. }
  495. SourceLocation start = GetStart();
  496. // Parse expression list after yield. This can be:
  497. // 1) empty, in which case it becomes 'yield None'
  498. // 2) a single expression
  499. // 3) multiple expression, in which case it's wrapped in a tuple.
  500. Expression yieldResult;
  501. bool trailingComma;
  502. List<Expression> l = ParseExpressionList(out trailingComma);
  503. if (l.Count == 0) {
  504. // Check empty expression and convert to 'none'
  505. yieldResult = new ConstantExpression(null);
  506. } else if (l.Count != 1) {
  507. // make a tuple
  508. yieldResult = MakeTupleOrExpr(l, trailingComma);
  509. } else {
  510. // just take the single expression
  511. yieldResult = l[0];
  512. }
  513. Expression yieldExpression = new YieldExpression(yieldResult);
  514. yieldExpression.SetLoc(start, GetEnd());
  515. return yieldExpression;
  516. }
  517. private Statement FinishAssignments(Expression right) {
  518. List<Expression> left = new List<Expression>();
  519. while (MaybeEat(TokenKind.Assign)) {
  520. string assignError = right.CheckAssign();
  521. if (assignError != null) {
  522. ReportSyntaxError(right.Span.Start, right.Span.End, assignError, ErrorCodes.SyntaxError | ErrorCodes.NoCaret);
  523. }
  524. left.Add(right);
  525. if (MaybeEat(TokenKind.KeywordYield)) {
  526. right = ParseYieldExpression();
  527. } else {
  528. bool trailingComma;
  529. var exprs = ParseExpressionList(out trailingComma);
  530. if (exprs.Count == 0) {
  531. ReportSyntaxError(left[0].Start, left[0].End, "invalid syntax");
  532. }
  533. right = MakeTupleOrExpr(exprs, trailingComma);
  534. }
  535. }
  536. Debug.Assert(left.Count > 0);
  537. AssignmentStatement assign = new AssignmentStatement(left.ToArray(), right);
  538. assign.SetLoc(left[0].Start, right.End);
  539. return assign;
  540. }
  541. // expr_stmt: expression_list
  542. // expression_list: expression ( "," expression )* [","]
  543. // assignment_stmt: (target_list "=")+ (expression_list | yield_expression)
  544. // augmented_assignment_stmt ::= target augop (expression_list | yield_expression)
  545. // augop: '+=' | '-=' | '*=' | '/=' | '%=' | '**=' | '>>=' | '<<=' | '&=' | '^=' | '|=' | '//='
  546. private Statement ParseExprStmt() {
  547. Expression ret = ParseTestListAsExpr(false);
  548. if (ret is ErrorExpression) {
  549. NextToken();
  550. }
  551. if (PeekToken(TokenKind.Assign)) {
  552. return FinishAssignments(ret);
  553. } else {
  554. PythonOperator op = GetAssignOperator(PeekToken());
  555. if (op != PythonOperator.None) {
  556. NextToken();
  557. Expression rhs;
  558. if (MaybeEat(TokenKind.KeywordYield)) {
  559. rhs = ParseYieldExpression();
  560. } else {
  561. rhs = ParseTestListAsExpr(false);
  562. }
  563. string assignError = ret.CheckAugmentedAssign();
  564. if (assignError != null) {
  565. ReportSyntaxError(assignError);
  566. }
  567. AugmentedAssignStatement aug = new AugmentedAssignStatement(op, ret, rhs);
  568. aug.SetLoc(ret.Start, GetEnd());
  569. return aug;
  570. } else {
  571. Statement stmt = new ExpressionStatement(ret);
  572. stmt.SetLoc(ret.Span);
  573. return stmt;
  574. }
  575. }
  576. }
  577. private PythonOperator GetAssignOperator(Token t) {
  578. switch (t.Kind) {
  579. case TokenKind.AddEqual: return PythonOperator.Add;
  580. case TokenKind.SubtractEqual: return PythonOperator.Subtract;
  581. case TokenKind.MultiplyEqual: return PythonOperator.Multiply;
  582. case TokenKind.DivideEqual: return TrueDivision ? PythonOperator.TrueDivide : PythonOperator.Divide;
  583. case TokenKind.ModEqual: return PythonOperator.Mod;
  584. case TokenKind.BitwiseAndEqual: return PythonOperator.BitwiseAnd;
  585. case TokenKind.BitwiseOrEqual: return PythonOperator.BitwiseOr;
  586. case TokenKind.ExclusiveOrEqual: return PythonOperator.Xor;
  587. case TokenKind.LeftShiftEqual: return PythonOperator.LeftShift;
  588. case TokenKind.RightShiftEqual: return PythonOperator.RightShift;
  589. case TokenKind.PowerEqual: return PythonOperator.Power;
  590. case TokenKind.FloorDivideEqual: return PythonOperator.FloorDivide;
  591. default: return PythonOperator.None;
  592. }
  593. }
  594. private PythonOperator GetBinaryOperator(OperatorToken token) {
  595. switch (token.Kind) {
  596. case TokenKind.Add: return PythonOperator.Add;
  597. case TokenKind.Subtract: return PythonOperator.Subtract;
  598. case TokenKind.Multiply: return PythonOperator.Multiply;
  599. case TokenKind.Divide: return TrueDivision ? PythonOperator.TrueDivide : PythonOperator.Divide;
  600. case TokenKind.Mod: return PythonOperator.Mod;
  601. case TokenKind.BitwiseAnd: return PythonOperator.BitwiseAnd;
  602. case TokenKind.BitwiseOr: return PythonOperator.BitwiseOr;
  603. case TokenKind.ExclusiveOr: return PythonOperator.Xor;
  604. case TokenKind.LeftShift: return PythonOperator.LeftShift;
  605. case TokenKind.RightShift: return PythonOperator.RightShift;
  606. case TokenKind.Power: return PythonOperator.Power;
  607. case TokenKind.FloorDivide: return PythonOperator.FloorDivide;
  608. default:
  609. string message = String.Format(
  610. System.Globalization.CultureInfo.InvariantCulture,
  611. Resources.UnexpectedToken,
  612. token.Kind);
  613. Debug.Assert(false, message);
  614. throw new ArgumentException(message);
  615. }
  616. }
  617. // import_stmt: 'import' module ['as' name"] (',' module ['as' name])*
  618. // name: identifier
  619. private ImportStatement ParseImportStmt() {
  620. Eat(TokenKind.KeywordImport);
  621. SourceLocation start = GetStart();
  622. List<ModuleName> l = new List<ModuleName>();
  623. List<string> las = new List<string>();
  624. l.Add(ParseModuleName());
  625. las.Add(MaybeParseAsName());
  626. while (MaybeEat(TokenKind.Comma)) {
  627. l.Add(ParseModuleName());
  628. las.Add(MaybeParseAsName());
  629. }
  630. ModuleName[] names = l.ToArray();
  631. var asNames = las.ToArray();
  632. ImportStatement ret = new ImportStatement(names, asNames, AbsoluteImports);
  633. ret.SetLoc(start, GetEnd());
  634. return ret;
  635. }
  636. // module: (identifier '.')* identifier
  637. private ModuleName ParseModuleName() {
  638. SourceLocation start = GetStart();
  639. ModuleName ret = new ModuleName(ReadNames());
  640. ret.SetLoc(start, GetEnd());
  641. return ret;
  642. }
  643. // relative_module: "."* module | "."+
  644. private ModuleName ParseRelativeModuleName() {
  645. SourceLocation start = GetStart();
  646. int dotCount = 0;
  647. while (MaybeEat(TokenKind.Dot)) {
  648. dotCount++;
  649. }
  650. string[] names = ArrayUtils.EmptyStrings;
  651. if (PeekToken() is NameToken) {
  652. names = ReadNames();
  653. }
  654. ModuleName ret;
  655. if (dotCount > 0) {
  656. ret = new RelativeModuleName(names, dotCount);
  657. } else {
  658. if (names.Length == 0) {
  659. ReportSyntaxError(_lookahead.Span.Start, _lookahead.Span.End, "invalid syntax");
  660. }
  661. ret = new ModuleName(names);
  662. }
  663. ret.SetLoc(start, GetEnd());
  664. return ret;
  665. }
  666. private string[] ReadNames() {
  667. List<string> l = new List<string>();
  668. l.Add(ReadName());
  669. while (MaybeEat(TokenKind.Dot)) {
  670. l.Add(ReadName());
  671. }
  672. return l.ToArray();
  673. }
  674. // 'from' relative_module 'import' identifier ['as' name] (',' identifier ['as' name]) *
  675. // 'from' relative_module 'import' '(' identifier ['as' name] (',' identifier ['as' name])* [','] ')'
  676. // 'from' module 'import' "*"
  677. private FromImportStatement ParseFromImportStmt() {
  678. Eat(TokenKind.KeywordFrom);
  679. SourceLocation start = GetStart();
  680. ModuleName dname = ParseRelativeModuleName();
  681. Eat(TokenKind.KeywordImport);
  682. bool ateParen = MaybeEat(TokenKind.LeftParenthesis);
  683. string[] names;
  684. string[] asNames;
  685. bool fromFuture = false;
  686. if (MaybeEat(TokenKind.Multiply)) {
  687. names = (string[])FromImportStatement.Star;
  688. asNames = null;
  689. } else {
  690. List<string> l = new List<string>();
  691. List<string> las = new List<string>();
  692. if (MaybeEat(TokenKind.LeftParenthesis)) {
  693. ParseAsNameList(l, las);
  694. Eat(TokenKind.RightParenthesis);
  695. } else {
  696. ParseAsNameList(l, las);
  697. }
  698. names = l.ToArray();
  699. asNames = las.ToArray();
  700. }
  701. // Process from __future__ statement
  702. if (dname.Names.Count == 1 && dname.Names[0] == "__future__") {
  703. if (!_fromFutureAllowed) {
  704. ReportSyntaxError(IronPython.Resources.MisplacedFuture);
  705. }
  706. if (names == FromImportStatement.Star) {
  707. ReportSyntaxError(IronPython.Resources.NoFutureStar);
  708. }
  709. fromFuture = true;
  710. foreach (string name in names) {
  711. if (name == "division") {
  712. _languageFeatures |= ModuleOptions.TrueDivision;
  713. } else if (name == "with_statement") {
  714. _languageFeatures |= ModuleOptions.WithStatement;
  715. } else if (name == "absolute_import") {
  716. _languageFeatures |= ModuleOptions.AbsoluteImports;
  717. } else if (name == "print_function") {
  718. _languageFeatures |= ModuleOptions.PrintFunction;
  719. _tokenizer.PrintFunction = true;
  720. } else if (name == "unicode_literals") {
  721. _tokenizer.UnicodeLiterals = true;
  722. _languageFeatures |= ModuleOptions.UnicodeLiterals;
  723. } else if (name == "nested_scopes") {
  724. } else if (name == "generators") {
  725. } else {
  726. string strName = name;
  727. fromFuture = false;
  728. if (strName != "braces") {
  729. ReportSyntaxError(IronPython.Resources.UnknownFutureFeature + strName);
  730. } else {
  731. // match CPython error message
  732. ReportSyntaxError(IronPython.Resources.NotAChance);
  733. }
  734. }
  735. }
  736. }
  737. if (ateParen) {
  738. Eat(TokenKind.RightParenthesis);
  739. }
  740. FromImportStatement ret = new FromImportStatement(dname, (string[])names, asNames, fromFuture, AbsoluteImports);
  741. ret.SetLoc(start, GetEnd());
  742. return ret;
  743. }
  744. // import_as_name (',' import_as_name)*
  745. private void ParseAsNameList(List<string> l, List<string> las) {
  746. l.Add(ReadName());
  747. las.Add(MaybeParseAsName());
  748. while (MaybeEat(TokenKind.Comma)) {
  749. if (PeekToken(TokenKind.RightParenthesis)) return; // the list is allowed to end with a ,
  750. l.Add(ReadName());
  751. las.Add(MaybeParseAsName());
  752. }
  753. }
  754. //import_as_name: NAME [NAME NAME]
  755. //dotted_as_name: dotted_name [NAME NAME]
  756. private string MaybeParseAsName() {
  757. if (MaybeEat(TokenKind.KeywordAs)) {
  758. return ReadName();
  759. }
  760. return null;
  761. }
  762. //exec_stmt: 'exec' expr ['in' expression [',' expression]]
  763. private ExecStatement ParseExecStmt() {
  764. Eat(TokenKind.KeywordExec);
  765. SourceLocation start = GetStart();
  766. Expression code, locals = null, globals = null;
  767. code = ParseExpr();
  768. if (MaybeEat(TokenKind.KeywordIn)) {
  769. globals = ParseExpression();
  770. if (MaybeEat(TokenKind.Comma)) {
  771. locals = ParseExpression();
  772. }
  773. }
  774. ExecStatement ret = new ExecStatement(code, locals, globals);
  775. ret.SetLoc(start, GetEnd());
  776. return ret;
  777. }
  778. //global_stmt: 'global' NAME (',' NAME)*
  779. private GlobalStatement ParseGlobalStmt() {
  780. Eat(TokenKind.KeywordGlobal);
  781. SourceLocation start = GetStart();
  782. List<string> l = new List<string>();
  783. l.Add(ReadName());
  784. while (MaybeEat(TokenKind.Comma)) {
  785. l.Add(ReadName());
  786. }
  787. string[] names = l.ToArray();
  788. GlobalStatement ret = new GlobalStatement(names);
  789. ret.SetLoc(start, GetEnd());
  790. return ret;
  791. }
  792. //raise_stmt: 'raise' [expression [',' expression [',' expression]]]
  793. private RaiseStatement ParseRaiseStmt() {
  794. Eat(TokenKind.KeywordRaise);
  795. SourceLocation start = GetStart();
  796. Expression type = null, _value = null, traceback = null;
  797. if (!NeverTestToken(PeekToken())) {
  798. type = ParseExpression();
  799. if (MaybeEat(TokenKind.Comma)) {
  800. _value = ParseExpression();
  801. if (MaybeEat(TokenKind.Comma)) {
  802. traceback = ParseExpression();
  803. }
  804. }
  805. }
  806. RaiseStatement ret = new RaiseStatement(type, _value, traceback);
  807. ret.SetLoc(start, GetEnd());
  808. return ret;
  809. }
  810. //assert_stmt: 'assert' expression [',' expression]
  811. private AssertStatement ParseAssertStmt() {
  812. Eat(TokenKind.KeywordAssert);
  813. SourceLocation start = GetStart();
  814. Expression expr = ParseExpression();
  815. Expression message = null;
  816. if (MaybeEat(TokenKind.Comma)) {
  817. message = ParseExpression();
  818. }
  819. AssertStatement ret = new AssertStatement(expr, message);
  820. ret.SetLoc(start, GetEnd());
  821. return ret;
  822. }
  823. //print_stmt: 'print' ( [ expression (',' expression)* [','] ] | '>>' expression [ (',' expression)+ [','] ] )
  824. private PrintStatement ParsePrintStmt() {
  825. Eat(TokenKind.KeywordPrint);
  826. SourceLocation start = GetStart();
  827. Expression dest = null;
  828. PrintStatement ret;
  829. bool needNonEmptyTestList = false;
  830. if (MaybeEat(TokenKind.RightShift)) {
  831. dest = ParseExpression();
  832. if (MaybeEat(TokenKind.Comma)) {
  833. needNonEmptyTestList = true;
  834. } else {
  835. ret = new PrintStatement(dest, new Expression[0], false);
  836. ret.SetLoc(start, GetEnd());
  837. return ret;
  838. }
  839. }
  840. bool trailingComma;
  841. List<Expression> l = ParseExpressionList(out trailingComma);
  842. if (needNonEmptyTestList && l.Count == 0) {
  843. ReportSyntaxError(_lookahead);
  844. }
  845. Expression[] exprs = l.ToArray();
  846. ret = new PrintStatement(dest, exprs, trailingComma);
  847. ret.SetLoc(start, GetEnd());
  848. return ret;
  849. }
  850. private string SetPrivatePrefix(string name) {
  851. string oldPrefix = _privatePrefix;
  852. _privatePrefix = GetPrivatePrefix(name);
  853. return oldPrefix;
  854. }
  855. internal static string GetPrivatePrefix(string name) {
  856. // Remove any leading underscores before saving the prefix
  857. if (name != null) {
  858. for (int i = 0; i < name.Length; i++) {
  859. if (name[i] != '_') {
  860. return name.Substring(i);
  861. }
  862. }
  863. }
  864. // Name consists of '_'s only, no private prefix mapping
  865. return null;
  866. }
  867. private ErrorExpression Error() {
  868. var res = new ErrorExpression();
  869. res.SetLoc(GetStart(), GetEnd());
  870. return res;
  871. }
  872. private ExpressionStatement ErrorStmt() {
  873. return new ExpressionStatement(Error());
  874. }
  875. //classdef: 'class' NAME ['(' testlist ')'] ':' suite
  876. private ClassDefinition ParseClassDef() {
  877. Eat(TokenKind.KeywordClass);
  878. SourceLocation start = GetStart();
  879. string name = ReadName();
  880. if (name == null) {
  881. // no name, assume there's no class.
  882. return new ClassDefinition(null, new Expression[0], ErrorStmt());
  883. }
  884. Expression[] bases = new Expression[0];
  885. if (MaybeEat(TokenKind.LeftParenthesis)) {
  886. List<Expression> l = ParseTestList();
  887. if (l.Count == 1 && l[0] is ErrorExpression) {
  888. // error handling, classes is incomplete.
  889. return new ClassDefinition(name, new Expression[0], ErrorStmt());
  890. }
  891. bases = l.ToArray();
  892. Eat(TokenKind.RightParenthesis);
  893. }
  894. SourceLocation mid = GetEnd();
  895. // Save private prefix
  896. string savedPrefix = SetPrivatePrefix(name);
  897. // Parse the class body
  898. Statement body = ParseClassOrFuncBody();
  899. // Restore the private prefix
  900. _privatePrefix = savedPrefix;
  901. ClassDefinition ret = new ClassDefinition(name, bases, body);
  902. ret.Header = mid;
  903. ret.SetLoc(start, GetEnd());
  904. return ret;
  905. }
  906. // decorators ::=
  907. // decorator+
  908. // decorator ::=
  909. // "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
  910. private List<Expression> ParseDecorators() {
  911. List<Expression> decorators = new List<Expression>();
  912. while (MaybeEat(TokenKind.At)) {
  913. SourceLocation start = GetStart();
  914. Expression decorator = new NameExpression(ReadName());
  915. decorator.SetLoc(start, GetEnd());
  916. while (MaybeEat(TokenKind.Dot)) {
  917. string name = ReadNameMaybeNone();
  918. decorator = new MemberExpression(decorator, name);
  919. decorator.SetLoc(GetStart(), GetEnd());
  920. }
  921. decorator.SetLoc(start, GetEnd());
  922. if (MaybeEat(TokenKind.LeftParenthesis)) {
  923. _sink.StartParameters(GetSpan());
  924. Arg[] args = FinishArgumentList(null);
  925. decorator = FinishCallExpr(decorator, args);
  926. }
  927. decorator.SetLoc(start, GetEnd());
  928. EatNewLine();
  929. decorators.Add(decorator);
  930. }
  931. return decorators;
  932. }
  933. // funcdef: [decorators] 'def' NAME parameters ':' suite
  934. // 2.6:
  935. // decorated: decorators (classdef | funcdef)
  936. // this gets called with "@" look-ahead
  937. private Statement ParseDecorated() {
  938. List<Expression> decorators = ParseDecorators();
  939. Statement res;
  940. if (PeekToken() == Tokens.KeywordDefToken) {
  941. FunctionDefinition fnc = ParseFuncDef();
  942. fnc.Decorators = decorators.ToArray();
  943. res = fnc;
  944. } else if (PeekToken() == Tokens.KeywordClassToken) {
  945. ClassDefinition cls = ParseClassDef();
  946. cls.Decorators = decorators.ToArray();
  947. res = cls;
  948. } else {
  949. res = new EmptyStatement();
  950. ReportSyntaxError(_lookahead);
  951. }
  952. return res;
  953. }
  954. // funcdef: [decorators] 'def' NAME parameters ':' suite
  955. // parameters: '(' [varargslist] ')'
  956. // this gets called with "def" as the look-ahead
  957. private FunctionDefinition ParseFuncDef() {
  958. Eat(TokenKind.KeywordDef);
  959. SourceLocation start = GetStart();
  960. string name = ReadName();
  961. Eat(TokenKind.LeftParenthesis);
  962. SourceLocation lStart = GetStart(), lEnd = GetEnd();
  963. int grouping = _tokenizer.GroupingLevel;
  964. Parameter[] parameters = ParseVarArgsList(TokenKind.RightParenthesis);
  965. FunctionDefinition ret;
  966. if (parameters == null) {
  967. // error in parameters
  968. ret = new FunctionDefinition(name, new Parameter[0]);
  969. ret.SetLoc(start, lEnd);
  970. return ret;
  971. }
  972. SourceLocation rStart = GetStart(), rEnd = GetEnd();
  973. ret = new FunctionDefinition(name, parameters);
  974. PushFunction(ret);
  975. Statement body = ParseClassOrFuncBody();
  976. FunctionDefinition ret2 = PopFunction();
  977. System.Diagnostics.Debug.Assert(ret == ret2);
  978. ret.Body = body;
  979. ret.Header = rEnd;
  980. _sink.MatchPair(new SourceSpan(lStart, lEnd), new SourceSpan(rStart, rEnd), grouping);
  981. ret.SetLoc(start, body.End);
  982. return ret;
  983. }
  984. private Parameter ParseParameterName(Dictionary<string, object> names, ParameterKind kind) {
  985. string name = ReadName();
  986. if (name != null) {
  987. CheckUniqueParameter(names, name);
  988. } else {
  989. return null;
  990. }
  991. Parameter parameter = new Parameter(name, kind);
  992. parameter.SetLoc(GetStart(), GetEnd());
  993. return parameter;
  994. }
  995. private void CheckUniqueParameter(Dictionary<string, object> names, string name) {
  996. if (names.ContainsKey(name)) {
  997. ReportSyntaxError(String.Format(
  998. System.Globalization.CultureInfo.InvariantCulture,
  999. Resources.DuplicateArgumentInFuncDef,
  1000. name));
  1001. }
  1002. names[name] = null;
  1003. }
  1004. //varargslist: (fpdef ['=' expression ] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' expression] (',' fpdef ['=' expression])* [',']
  1005. //fpdef: NAME | '(' fplist ')'
  1006. //fplist: fpdef (',' fpdef)* [',']
  1007. private Parameter[] ParseVarArgsList(TokenKind terminator) {
  1008. // parameters not doing * or ** today
  1009. List<Parameter> pl = new List<Parameter>();
  1010. Dictionary<string, object> names = new Dictionary<string, object>(StringComparer.Ordinal);
  1011. bool needDefault = false;
  1012. for (int position = 0; ; position++) {
  1013. if (MaybeEat(terminator)) break;
  1014. Parameter parameter;
  1015. if (MaybeEat(TokenKind.Multiply)) {
  1016. parameter = ParseParameterName(names, ParameterKind.List);
  1017. if (parameter == null) {
  1018. // no parameter name, syntax error
  1019. return null;
  1020. }
  1021. pl.Add(parameter);
  1022. if (MaybeEat(TokenKind.Comma)) {
  1023. Eat(TokenKind.Power);
  1024. parameter = ParseParameterName(names, ParameterKind.Dictionary);
  1025. if (parameter == null) {
  1026. return null;
  1027. }
  1028. pl.Add(parameter);
  1029. }
  1030. Eat(terminator);
  1031. break;
  1032. } else if (MaybeEat(TokenKind.Power)) {
  1033. parameter = ParseParameterName(names, ParameterKind.Dictionary);
  1034. if (parameter == null) {
  1035. // no parameter name, syntax error
  1036. return null;
  1037. }
  1038. pl.Add(parameter);
  1039. Eat(terminator);
  1040. break;
  1041. }
  1042. //
  1043. // Parsing defparameter:
  1044. //
  1045. // defparameter ::=
  1046. // parameter ["=" expression]
  1047. if ((parameter = ParseParameter(position, names)) != null) {
  1048. pl.Add(parameter);
  1049. if (MaybeEat(TokenKind.Assign)) {
  1050. needDefault = true;
  1051. parameter.DefaultValue = ParseExpression();
  1052. } else if (needDefault) {
  1053. ReportSyntaxError(IronPython.Resources.DefaultRequired);
  1054. }
  1055. } else {
  1056. // no parameter due to syntax error
  1057. return null;
  1058. }
  1059. if (!MaybeEat(TokenKind.Comma)) {
  1060. Eat(terminator);
  1061. break;
  1062. }
  1063. }
  1064. return pl.ToArray();
  1065. }
  1066. // parameter ::=
  1067. // identifier | "(" sublist ")"
  1068. private Parameter ParseParameter(int position, Dictionary<string, object> names) {
  1069. Token t = PeekToken();
  1070. Parameter parameter = null;
  1071. switch (t.Kind) {
  1072. case TokenKind.LeftParenthesis: // sublist
  1073. NextToken();
  1074. Expression ret = ParseSublist(names);
  1075. Eat(TokenKind.RightParenthesis);
  1076. TupleExpression tret = ret as TupleExpression;
  1077. NameExpression nameRet;
  1078. if (tret != null) {
  1079. parameter = new SublistParameter(position, tret);
  1080. } else if ((nameRet = ret as NameExpression) != null) {
  1081. parameter = new Parameter(nameRet.Name);
  1082. } else {
  1083. ReportSyntaxError(_lookahead);
  1084. }
  1085. if (parameter != null) {
  1086. parameter.SetLoc(ret.Span);
  1087. }
  1088. break;
  1089. case TokenKind.Name: // identifier
  1090. NextToken();
  1091. string name = FixName((string)t.Value);
  1092. parameter = new Parameter(name);
  1093. CompleteParameterName(parameter, name, names);
  1094. break;
  1095. default:
  1096. ReportSyntaxError(_lookahead);
  1097. break;
  1098. }
  1099. return parameter;
  1100. }
  1101. private void CompleteParameterName(Node node, string name, Dictionary<string, object> names) {
  1102. SourceSpan span = GetSpan();
  1103. _sink.StartName(span, name);
  1104. CheckUniqueParameter(names, name);
  1105. node.SetLoc(span);
  1106. }
  1107. // parameter ::=
  1108. // identifier | "(" sublist ")"
  1109. private Expression ParseSublistParameter(Dictionary<string, object> names) {
  1110. Token t = NextToken();
  1111. Expression ret = null;
  1112. switch (t.Kind) {
  1113. case TokenKind.LeftParenthesis: // sublist
  1114. ret = ParseSublist(names);
  1115. Eat(TokenKind.RightParenthesis);
  1116. break;
  1117. case TokenKind.Name: // identifier
  1118. string name = FixName((string)t.Value);
  1119. NameExpression ne = new NameExpression(name);
  1120. CompleteParameterName(ne, name, names);
  1121. return ne;
  1122. default:
  1123. ReportSyntaxError(_token);
  1124. ret = Error();
  1125. break;
  1126. }
  1127. return ret;
  1128. }
  1129. // sublist ::=
  1130. // parameter ("," parameter)* [","]
  1131. private Expression ParseSublist(Dictionary<string, object> names) {
  1132. bool trailingComma;
  1133. List<Expression> list = new List<Expression>();
  1134. for (; ; ) {
  1135. trailingComma = false;
  1136. list.Add(ParseSublistParameter(names));
  1137. if (MaybeEat(TokenKind.Comma)) {
  1138. trailingComma = true;
  1139. switch (PeekToken().Kind) {
  1140. case TokenKind.LeftParenthesis:
  1141. case TokenKind.Name:
  1142. continue;
  1143. default:
  1144. break;
  1145. }
  1146. break;
  1147. } else {
  1148. trailingComma = false;
  1149. break;
  1150. }
  1151. }
  1152. return MakeTupleOrExpr(list, trailingComma);
  1153. }
  1154. //Python2.5 -> old_lambdef: 'lambda' [varargslist] ':' old_expression
  1155. private Expression FinishOldLambdef() {
  1156. FunctionDefinition func = ParseLambdaHelperStart(null);
  1157. Expression expr = ParseOldExpression();
  1158. return ParseLambdaHelperEnd(func, expr);
  1159. }
  1160. //lambdef: 'lambda' [varargslist] ':' expression
  1161. private Expression FinishLambdef() {
  1162. FunctionDefinition func = ParseLambdaHelperStart(null);
  1163. Expression expr = ParseExpression();
  1164. return ParseLambdaHelperEnd(func, expr);
  1165. }
  1166. // Helpers for parsing lambda expressions.
  1167. // Usage
  1168. // FunctionDefinition f = ParseLambdaHelperStart(string);
  1169. // Expression expr = ParseXYZ();
  1170. // return ParseLambdaHelperEnd(f, expr);
  1171. private FunctionDefinition ParseLambdaHelperStart(string name) {
  1172. SourceLocation start = GetStart();
  1173. Parameter[] parameters;
  1174. parameters = ParseVarArgsList(TokenKind.Colon);
  1175. SourceLocation mid = GetEnd();
  1176. FunctionDefinition func = new FunctionDefinition(name, parameters);
  1177. func.Header = mid;
  1178. func.Start = start;
  1179. // Push the lambda function on the stack so that it's available for any yield expressions to mark it as a generator.
  1180. PushFunction(func);
  1181. return func;
  1182. }
  1183. private Expression ParseLambdaHelperEnd(FunctionDefinition func, Expression expr) {
  1184. // Pep 342 in Python 2.5 allows Yield Expressions, which can occur inside a Lambda body.
  1185. // In this case, the lambda is a generator and will yield it's final result instead of just return it.
  1186. Statement body;
  1187. if (func.IsGenerator) {
  1188. YieldExpression y = new YieldExpression(expr);
  1189. y.SetLoc(expr.Span);
  1190. body = new ExpressionStatement(y);
  1191. } else {
  1192. body = new ReturnStatement(expr);
  1193. }
  1194. body.SetLoc(expr.Start, expr.End);
  1195. FunctionDefinition func2 = PopFunction();
  1196. System.Diagnostics.Debug.Assert(func == func2);
  1197. func.Body = body;
  1198. func.End = GetEnd();
  1199. LambdaExpression ret = new LambdaExpression(func);
  1200. ret.SetLoc(func.Span);
  1201. return ret;
  1202. }
  1203. //while_stmt: 'while' expression ':' suite ['else' ':' suite]
  1204. private WhileStatement ParseWhileStmt() {
  1205. Eat(TokenKind.KeywordWhile);
  1206. SourceLocation start = GetStart();
  1207. Expression expr = ParseExpression();
  1208. SourceLocation mid = GetEnd();
  1209. Statement body = ParseLoopSuite();
  1210. Statement else_ = null;
  1211. if (MaybeEat(TokenKind.KeywordElse)) {
  1212. else_ = ParseSuite();
  1213. }
  1214. WhileStatement ret = new WhileStatement(expr, body, else_);
  1215. ret.SetLoc(start, mid, GetEnd());
  1216. return ret;
  1217. }
  1218. //with_stmt: 'with' expression [ 'as' with_var ] ':' suite
  1219. private WithStatement ParseWithStmt() {
  1220. Eat(TokenKind.KeywordWith);
  1221. SourceLocation start = GetStart();
  1222. Expression contextManager = ParseExpression();
  1223. Expression var = null;
  1224. if (MaybeEat(TokenKind.KeywordAs)) {
  1225. var = ParseExpression();
  1226. }
  1227. SourceLocation header = GetEnd();
  1228. Statement body = ParseSuite();
  1229. WithStatement ret = new WithStatement(contextManager, var, body);
  1230. ret.Header = header;
  1231. ret.SetLoc(start, GetEnd());
  1232. return ret;
  1233. }
  1234. //for_stmt: 'for' target_list 'in' expression_list ':' suite ['else' ':' suite]
  1235. private ForStatement ParseForStmt() {
  1236. Eat(TokenKind.KeywordFor);
  1237. SourceLocation start = GetStart();
  1238. bool trailingComma;
  1239. List<Expression> l = ParseTargetList(out trailingComma);
  1240. // expr list is something like:
  1241. // ()
  1242. // a
  1243. // a,b
  1244. // a,b,c
  1245. // we either want just () or a or we want (a,b) and (a,b,c)
  1246. // so we can do tupleExpr.EmitSet() or loneExpr.EmitSet()
  1247. Expression lhs = MakeTupleOrExpr(l, trailingComma);
  1248. Eat(TokenKind.KeywordIn);
  1249. Expression list = ParseTestListAsExpr(false);
  1250. SourceLocation header = GetEnd();
  1251. Statement body = ParseLoopSuite();
  1252. Statement else_ = null;
  1253. if (MaybeEat(TokenKind.KeywordElse)) {
  1254. else_ = ParseSuite();
  1255. }
  1256. ForStatement ret = new ForStatement(lhs, list, body, else_);
  1257. ret.Header = header;
  1258. ret.SetLoc(start, GetEnd());
  1259. return ret;
  1260. }
  1261. private Statement ParseLoopSuite() {
  1262. Statement body;
  1263. bool inLoop = _inLoop;
  1264. try {
  1265. _inLoop = true;
  1266. body = ParseSuite();
  1267. } finally {
  1268. _inLoop = inLoop;
  1269. }
  1270. return body;
  1271. }
  1272. private Statement ParseClassOrFuncBody() {
  1273. Statement body;
  1274. bool inLoop = _inLoop, inFinally = _inFinally, isGenerator = _isGenerator, returnWithValue = _returnWithValue;
  1275. try {
  1276. _inLoop = false;
  1277. _inFinally = false;
  1278. _isGenerator = false;
  1279. _returnWithValue = false;
  1280. body = ParseSuite();
  1281. } finally {
  1282. _inLoop = inLoop;
  1283. _inFinally = inFinally;
  1284. _isGenerator = isGenerator;
  1285. _returnWithValue = returnWithValue;
  1286. }
  1287. return body;
  1288. }
  1289. // if_stmt: 'if' expression ':' suite ('elif' expression ':' suite)* ['else' ':' suite]
  1290. private IfStatement ParseIfStmt() {
  1291. Eat(TokenKind.KeywordIf);
  1292. SourceLocation start = GetStart();
  1293. List<IfStatementTest> l = new List<IfStatementTest>();
  1294. l.Add(ParseIfStmtTest());
  1295. while (MaybeEat(TokenKind.KeywordElseIf)) {
  1296. l.Add(ParseIfStmtTest());
  1297. }
  1298. Statement else_ = null;
  1299. if (MaybeEat(TokenKind.KeywordElse)) {
  1300. else_ = ParseSuite();
  1301. }
  1302. IfStatementTest[] tests = l.ToArray();
  1303. IfStatement ret = new IfStatement(tests, else_);
  1304. ret.SetLoc(start, GetEnd());
  1305. return ret;
  1306. }
  1307. private IfStatementTest ParseIfStmtTest() {
  1308. SourceLocation start = GetStart();
  1309. Expression expr = ParseExpression();
  1310. SourceLocation header = GetEnd();
  1311. Statement suite = ParseSuite();
  1312. IfStatementTest ret = new IfStatementTest(expr, suite);
  1313. ret.SetLoc(start, suite.End);
  1314. ret.Header = header;
  1315. return ret;
  1316. }
  1317. //try_stmt: ('try' ':' suite (except_clause ':' suite)+
  1318. // ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite)
  1319. //# NB compile.c makes sure that the default except clause is last
  1320. // Python 2.5 grammar
  1321. //try_stmt: 'try' ':' suite
  1322. // (
  1323. // (except_clause ':' suite)+
  1324. // ['else' ':' suite]
  1325. // ['finally' ':' suite]
  1326. // |
  1327. // 'finally' : suite
  1328. // )
  1329. private Statement ParseTryStatement() {
  1330. Eat(TokenKind.KeywordTry);
  1331. SourceLocation start = GetStart();
  1332. SourceLocation mid = GetEnd();
  1333. Statement body = ParseSuite();
  1334. Statement finallySuite = null;
  1335. Statement elseSuite = null;
  1336. Statement ret;
  1337. SourceLocation end;
  1338. if (MaybeEat(TokenKind.KeywordFinally)) {
  1339. finallySuite = ParseFinallySuite(finallySuite);
  1340. end = finallySuite.End;
  1341. TryStatement tfs = new TryStatement(body, null, elseSuite, finallySuite);
  1342. tfs.Header = mid;
  1343. ret = tfs;
  1344. } else {
  1345. List<TryStatementHandler> handlers = new List<TryStatementHandler>();
  1346. TryStatementHandler dh = null;
  1347. do {
  1348. TryStatementHandler handler = ParseTryStmtHandler();
  1349. end = handler.End;
  1350. handlers.Add(handler);
  1351. if (dh != null) {
  1352. ReportSyntaxError(dh.Start, dh.End, "default 'except' must be last");
  1353. }
  1354. if (handler.Test == null) {
  1355. dh = handler;
  1356. }
  1357. } while (PeekToken().Kind == TokenKind.KeywordExcept);
  1358. if (MaybeEat(TokenKind.KeywordElse)) {
  1359. elseSuite = ParseSuite();
  1360. end = elseSuite.End;
  1361. }
  1362. if (MaybeEat(TokenKind.KeywordFinally)) {
  1363. // If this function has an except block, then it can set the current exception.
  1364. finallySuite = ParseFinallySuite(finallySuite);
  1365. end = finallySuite.End;
  1366. }
  1367. TryStatement ts = new TryStatement(body, handlers.ToArray(), elseSuite, finallySuite);
  1368. ts.Header = mid;
  1369. ret = ts;
  1370. }
  1371. ret.SetLoc(start, end);
  1372. return ret;
  1373. }
  1374. private Statement ParseFinallySuite(Statement finallySuite) {
  1375. MarkFunctionContainsFinally();
  1376. bool inFinally = _inFinally;
  1377. try {
  1378. _inFinally = true;
  1379. finallySuite = ParseSuite();
  1380. } finally {
  1381. _inFinally = inFinally;
  1382. }
  1383. return finallySuite;
  1384. }
  1385. private void MarkFunctionContainsFinally() {
  1386. FunctionDefinition current = CurrentFunction;
  1387. if (current != null) {
  1388. current.ContainsTryFinally = true;
  1389. }
  1390. }
  1391. //except_clause: 'except' [expression [',' expression]]
  1392. //2.6: except_clause: 'except' [expression [(',' or 'as') expression]]
  1393. private TryStatementHandler ParseTryStmtHandler() {
  1394. Eat(TokenKind.KeywordExcept);
  1395. // If this function has an except block, then it can set the current exception.
  1396. FunctionDefinition current = CurrentFunction;
  1397. if (current != null) {
  1398. current.CanSetSysExcInfo = true;
  1399. }
  1400. SourceLocation start = GetStart();
  1401. Expression test1 = null, test2 = null;
  1402. if (PeekToken().Kind != TokenKind.Colon) {
  1403. test1 = ParseExpression();
  1404. if (MaybeEat(TokenKind.Comma) || MaybeEat(TokenKind.KeywordAs)) {
  1405. test2 = ParseExpression();
  1406. }
  1407. }
  1408. SourceLocation mid = GetEnd();
  1409. Statement body = ParseSuite();
  1410. TryStatementHandler ret = new TryStatementHandler(test1, test2, body);
  1411. ret.Header = mid;
  1412. ret.SetLoc(start, body.End);
  1413. return ret;
  1414. }
  1415. //suite: simple_stmt NEWLINE | Newline INDENT stmt+ DEDENT
  1416. private Statement ParseSuite() {
  1417. if (!EatNoEof(TokenKind.Colon)) {
  1418. // improve error handling...
  1419. return ErrorStmt();
  1420. }
  1421. TokenWithSpan cur = _lookahead;
  1422. List<Statement> l = new List<Statement>();
  1423. // we only read a real NewLine here because we need to adjust error reporting
  1424. // for the interpreter.
  1425. if (MaybeEat(TokenKind.NewLine)) {
  1426. CheckSuiteEofError(cur);
  1427. // for error reporting we track the NL tokens and report the error on
  1428. // the last one. This matches CPython.
  1429. cur = _lookahead;
  1430. while (PeekToken(TokenKind.NLToken)) {
  1431. cur = _lookahead;
  1432. NextToken();
  1433. }
  1434. if (!MaybeEat(TokenKind.Indent)) {
  1435. // no indent? report the indentation error.
  1436. if (cur.Token.Kind == TokenKind.Dedent) {
  1437. ReportSyntaxError(_lookahead.Span.Start, _lookahead.Span.End, "expected an indented block", ErrorCodes.SyntaxError | ErrorCodes.IncompleteStatement);
  1438. } else {
  1439. ReportSyntaxError(cur, ErrorCodes.IndentationError);
  1440. }
  1441. return ErrorStmt();
  1442. }
  1443. while (true) {
  1444. Statement s = ParseStmt();
  1445. l.Add(s);
  1446. if (MaybeEat(TokenKind.Dedent)) break;
  1447. if (PeekToken().Kind == TokenKind.EndOfFile) {
  1448. ReportSyntaxError("unexpected end of file");
  1449. break; // error handling
  1450. }
  1451. }
  1452. Statement[] stmts = l.ToArray();
  1453. SuiteStatement ret = new SuiteStatement(stmts);
  1454. ret.SetLoc(stmts[0].Start, stmts[stmts.Length - 1].End);
  1455. return ret;
  1456. } else {
  1457. // simple_stmt NEWLINE
  1458. // ParseSimpleStmt takes care of the NEWLINE
  1459. Statement s = ParseSimpleStmt();
  1460. return s;
  1461. }
  1462. }
  1463. private void CheckSuiteEofError(TokenWithSpan cur) {
  1464. if (MaybeEat(TokenKind.EndOfFile)) {
  1465. // for interactive parsing we allow the user to continue in this case
  1466. ReportSyntaxError(_lookahead.Token, cur.Span, ErrorCodes.SyntaxError, true);
  1467. }
  1468. }
  1469. // Python 2.5 -> old_test: or_test | old_lambdef
  1470. private Expression ParseOldExpression() {
  1471. if (MaybeEat(TokenKind.KeywordLambda)) {
  1472. return FinishOldLambdef();
  1473. }
  1474. return ParseOrTest();
  1475. }
  1476. // expression: conditional_expression | lambda_form
  1477. // conditional_expression: or_test ['if' or_test 'else' expression]
  1478. // lambda_form: "lambda" [parameter_list] : expression
  1479. private Expression ParseExpression() {
  1480. if (MaybeEat(TokenKind.KeywordLambda)) {
  1481. return FinishLambdef();
  1482. }
  1483. Expression ret = ParseOrTest();
  1484. if (MaybeEat(TokenKind.KeywordIf)) {
  1485. SourceLocation start = ret.Start;
  1486. ret = ParseConditionalTest(ret);
  1487. ret.SetLoc(start, GetEnd());
  1488. }
  1489. return ret;
  1490. }
  1491. // or_test: and_test ('or' and_test)*
  1492. private Expression ParseOrTest() {
  1493. Expression ret = ParseAndTest();
  1494. while (MaybeEat(TokenKind.KeywordOr)) {
  1495. SourceLocation start = ret.Start;
  1496. ret = new OrExpression(ret, ParseAndTest());
  1497. ret.SetLoc(start, GetEnd());
  1498. }
  1499. return ret;
  1500. }
  1501. private Expression ParseConditionalTest(Expression trueExpr) {
  1502. Expression expr = ParseOrTest();
  1503. Eat(TokenKind.KeywordElse);
  1504. Expression falseExpr = ParseExpression();
  1505. return new ConditionalExpression(expr, trueExpr, falseExpr);
  1506. }
  1507. // and_test: not_test ('and' not_test)*
  1508. private Expression ParseAndTest() {
  1509. Expression ret = ParseNotTest();
  1510. while (MaybeEat(TokenKind.KeywordAnd)) {
  1511. SourceLocation start = ret.Start;
  1512. ret = new AndExpression(ret, ParseAndTest());
  1513. ret.SetLoc(start, GetEnd());
  1514. }
  1515. return ret;
  1516. }
  1517. //not_test: 'not' not_test | comparison
  1518. private Expression ParseNotTest() {
  1519. if (MaybeEat(TokenKind.KeywordNot)) {
  1520. SourceLocation start = GetStart();
  1521. Expression ret = new UnaryExpression(PythonOperator.Not, ParseNotTest());
  1522. ret.SetLoc(start, GetEnd());
  1523. return ret;
  1524. } else {
  1525. return ParseComparison();
  1526. }
  1527. }
  1528. //comparison: expr (comp_op expr)*
  1529. //comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
  1530. private Expression ParseComparison() {
  1531. Expression ret = ParseExpr();
  1532. while (true) {
  1533. PythonOperator op;
  1534. switch (PeekToken().Kind) {
  1535. case TokenKind.LessThan: NextToken(); op = PythonOperator.LessThan; break;
  1536. case TokenKind.LessThanOrEqual: NextToken(); op = PythonOperator.LessThanOrEqual; break;
  1537. case TokenKind.GreaterThan: NextToken(); op = PythonOperator.GreaterThan; break;
  1538. case TokenKind.GreaterThanOrEqual: NextToken(); op = PythonOperator.GreaterThanOrEqual; break;
  1539. case TokenKind.Equals: NextToken(); op = PythonOperator.Equal; break;
  1540. case TokenKind.NotEquals: NextToken(); op = PythonOperator.NotEqual; break;
  1541. case TokenKind.LessThanGreaterThan: NextToken(); op = PythonOperator.NotEqual; break;
  1542. case TokenKind.KeywordIn: NextToken(); op = PythonOperator.In; break;
  1543. case TokenKind.KeywordNot: NextToken(); Eat(TokenKind.KeywordIn); op = PythonOperator.NotIn; break;
  1544. case TokenKind.KeywordIs:
  1545. NextToken();
  1546. if (MaybeEat(TokenKind.KeywordNot)) {
  1547. op = PythonOperator.IsNot;
  1548. } else {
  1549. op = PythonOperator.Is;
  1550. }
  1551. break;
  1552. default:
  1553. return ret;
  1554. }
  1555. Expression rhs = ParseComparison();
  1556. BinaryExpression be = new BinaryExpression(op, ret, rhs);
  1557. be.SetLoc(ret.Start, GetEnd());
  1558. ret = be;
  1559. }
  1560. }
  1561. /*
  1562. expr: xor_expr ('|' xor_expr)*
  1563. xor_expr: and_expr ('^' and_expr)*
  1564. and_expr: shift_expr ('&' shift_expr)*
  1565. shift_expr: arith_expr (('<<'|'>>') arith_expr)*
  1566. arith_expr: term (('+'|'-') term)*
  1567. term: factor (('*'|'/'|'%'|'//') factor)*
  1568. */
  1569. private Expression ParseExpr() {
  1570. return ParseExpr(0);
  1571. }
  1572. private Expression ParseExpr(int precedence) {
  1573. Expression ret = ParseFactor();
  1574. while (true) {
  1575. Token t = PeekToken();
  1576. OperatorToken ot = t as OperatorToken;
  1577. if (ot == null) return ret;
  1578. int prec = ot.Precedence;
  1579. if (prec >= precedence) {
  1580. NextToken();
  1581. Expression right = ParseExpr(prec + 1);
  1582. SourceLocation start = ret.Start;
  1583. ret = new BinaryExpression(GetBinaryOperator(ot), ret, right);
  1584. ret.SetLoc(start, GetEnd());
  1585. } else {
  1586. return ret;
  1587. }
  1588. }
  1589. }
  1590. // factor: ('+'|'-'|'~') factor | power
  1591. private Expression ParseFactor() {
  1592. SourceLocation start = _lookahead.Span.Start;
  1593. Expression ret;
  1594. switch (PeekToken().Kind) {
  1595. case TokenKind.Add:
  1596. NextToken();
  1597. ret = new UnaryExpression(PythonOperator.Pos, ParseFactor());
  1598. break;
  1599. case TokenKind.Subtract:
  1600. NextToken();
  1601. ret = FinishUnaryNegate();
  1602. break;
  1603. case TokenKind.Twiddle:
  1604. NextToken();
  1605. ret = new UnaryExpression(PythonOperator.Invert, ParseFactor());
  1606. break;
  1607. default:
  1608. return ParsePower();
  1609. }
  1610. ret.SetLoc(start, GetEnd());
  1611. return ret;
  1612. }
  1613. private Expression FinishUnaryNegate() {
  1614. // Special case to ensure that System.Int32.MinValue is an int and not a BigInteger
  1615. if (PeekToken().Kind == TokenKind.Constant) {
  1616. Token t = PeekToken();
  1617. if (t.Value is BigInteger) {
  1618. BigInteger bi = (BigInteger)t.Value;
  1619. uint iVal;
  1620. if (bi.AsUInt32(out iVal) && iVal == 0x80000000) {
  1621. string tokenString = _tokenizer.GetTokenString(); ;
  1622. Debug.Assert(tokenString.Length > 0);
  1623. if (tokenString[tokenString.Length - 1] != 'L' &&
  1624. tokenString[tokenString.Length - 1] != 'l') {
  1625. NextToken();
  1626. return new ConstantExpression(-2147483648);
  1627. }
  1628. }
  1629. }
  1630. }
  1631. return new UnaryExpression(PythonOperator.Negate, ParseFactor());
  1632. }
  1633. // power: atom trailer* ['**' factor]
  1634. private Expression ParsePower() {
  1635. Expression ret = ParsePrimary();
  1636. ret = AddTrailers(ret);
  1637. if (MaybeEat(TokenKind.Power)) {
  1638. SourceLocation start = ret.Start;
  1639. ret = new BinaryExpression(PythonOperator.Power, ret, ParseFactor());
  1640. ret.SetLoc(start, GetEnd());
  1641. }
  1642. return ret;
  1643. }
  1644. // primary: atom | attributeref | subscription | slicing | call
  1645. // atom: identifier | literal | enclosure
  1646. // enclosure:
  1647. // parenth_form |
  1648. // list_display |
  1649. // generator_expression |
  1650. // dict_display |
  1651. // string_conversion |
  1652. // yield_atom
  1653. private Expression ParsePrimary() {
  1654. Token t = PeekToken();
  1655. Expression ret;
  1656. switch (t.Kind) {
  1657. case TokenKind.LeftParenthesis: // parenth_form, generator_expression, yield_atom
  1658. NextToken();
  1659. return FinishTupleOrGenExp();
  1660. case TokenKind.LeftBracket: // list_display
  1661. NextToken();
  1662. return FinishListValue();
  1663. case TokenKind.LeftBrace: // dict_display
  1664. NextToken();
  1665. return FinishDictValue();
  1666. case TokenKind.BackQuote: // string_conversion
  1667. NextToken();
  1668. return FinishStringConversion();
  1669. case TokenKind.Name: // identifier
  1670. NextToken();
  1671. SourceSpan span = GetSpan();
  1672. string name = (string)t.Value;
  1673. _sink.StartName(span, name);
  1674. ret = new NameExpression(FixName(name));
  1675. ret.SetLoc(GetStart(), GetEnd());
  1676. return ret;
  1677. case TokenKind.Constant: // literal
  1678. NextToken();
  1679. SourceLocation start = GetStart();
  1680. object cv = t.Value;
  1681. string cvs = cv as string;
  1682. if (cvs != null) {
  1683. cv = FinishStringPlus(cvs);
  1684. } else {
  1685. Bytes bytes = cv as Bytes;
  1686. if (bytes != null) {
  1687. cv = FinishBytesPlus(bytes);
  1688. }
  1689. }
  1690. if (t is UnicodeStringToken) {
  1691. ret = ConstantExpression.MakeUnicode((string)cv);
  1692. } else {
  1693. ret = new ConstantExpression(cv);
  1694. }
  1695. ret.SetLoc(start, GetEnd());
  1696. return ret;
  1697. default:
  1698. ReportSyntaxError(_lookahead.Token, _lookahead.Span, ErrorCodes.SyntaxError, _allowIncomplete || _tokenizer.EndContinues);
  1699. // error node
  1700. ret = new ErrorExpression();
  1701. ret.SetLoc(_lookahead.Span.Start, _lookahead.Span.End);
  1702. return ret;
  1703. }
  1704. }
  1705. private string FinishStringPlus(string s) {
  1706. Token t = PeekToken();
  1707. while (true) {
  1708. if (t is ConstantValueToken) {
  1709. string cvs;
  1710. if ((cvs = t.Value as String) != null) {
  1711. s += cvs;
  1712. NextToken();
  1713. t = PeekToken();
  1714. continue;
  1715. } else {
  1716. ReportSyntaxError("invalid syntax");
  1717. }
  1718. }
  1719. break;
  1720. }
  1721. return s;
  1722. }
  1723. private Bytes FinishBytesPlus(Bytes s) {
  1724. Token t = PeekToken();
  1725. while (true) {
  1726. if (t is ConstantValueToken) {
  1727. Bytes cvs;
  1728. if ((cvs = t.Value as Bytes) != null) {
  1729. s = s + cvs;
  1730. NextToken();
  1731. t = PeekToken();
  1732. continue;
  1733. } else {
  1734. ReportSyntaxError("invalid syntax");
  1735. }
  1736. }
  1737. break;
  1738. }
  1739. return s;
  1740. }
  1741. private Expression AddTrailers(Expression ret) {
  1742. return AddTrailers(ret, true);
  1743. }
  1744. // trailer: '(' [ arglist_genexpr ] ')' | '[' subscriptlist ']' | '.' NAME
  1745. private Expression AddTrailers(Expression ret, bool allowGeneratorExpression) {
  1746. bool prevAllow = _allowIncomplete;
  1747. try {
  1748. _allowIncomplete = true;
  1749. while (true) {
  1750. switch (PeekToken().Kind) {
  1751. case TokenKind.LeftParenthesis:
  1752. if (!allowGeneratorExpression) return ret;
  1753. NextToken();
  1754. Arg[] args = FinishArgListOrGenExpr();
  1755. CallExpression call;
  1756. if (args != null) {
  1757. call = FinishCallExpr(ret, args);
  1758. } else {
  1759. call = new CallExpression(ret, new Arg[0]);
  1760. }
  1761. call.SetLoc(ret.Start, GetEnd());
  1762. ret = call;
  1763. break;
  1764. case TokenKind.LeftBracket:
  1765. NextToken();
  1766. Expression index = ParseSubscriptList();
  1767. IndexExpression ie = new IndexExpression(ret, index);
  1768. ie.SetLoc(ret.Start, GetEnd());
  1769. ret = ie;
  1770. break;
  1771. case TokenKind.Dot:
  1772. NextToken();
  1773. string name = ReadNameMaybeNone();
  1774. MemberExpression fe = new MemberExpression(ret, name);
  1775. fe.SetLoc(ret.Start, GetEnd());
  1776. ret = fe;
  1777. break;
  1778. case TokenKind.Constant:
  1779. // abc.1, abc"", abc 1L, abc 0j
  1780. ReportSyntaxError("invalid syntax");
  1781. return Error();
  1782. default:
  1783. return ret;
  1784. }
  1785. }
  1786. } finally {
  1787. _allowIncomplete = prevAllow;
  1788. }
  1789. }
  1790. //subscriptlist: subscript (',' subscript)* [',']
  1791. //subscript: '.' '.' '.' | expression | [expression] ':' [expression] [sliceop]
  1792. //sliceop: ':' [expression]
  1793. private Expression ParseSubscriptList() {
  1794. const TokenKind terminator = TokenKind.RightBracket;
  1795. SourceLocation start0 = GetStart();
  1796. bool trailingComma = false;
  1797. List<Expression> l = new List<Expression>();
  1798. while (true) {
  1799. Expression e;
  1800. if (MaybeEat(TokenKind.Dot)) {
  1801. SourceLocation start = GetStart();
  1802. Eat(TokenKind.Dot); Eat(TokenKind.Dot);
  1803. e = new ConstantExpression(Ellipsis.Value);
  1804. e.SetLoc(start, GetEnd());
  1805. } else if (MaybeEat(TokenKind.Colon)) {
  1806. e = FinishSlice(null, GetStart());
  1807. } else {
  1808. e = ParseExpression();
  1809. if (MaybeEat(TokenKind.Colon)) {
  1810. e = FinishSlice(e, e.Start);
  1811. }
  1812. }
  1813. l.Add(e);
  1814. if (!MaybeEat(TokenKind.Comma)) {
  1815. Eat(terminator);
  1816. trailingComma = false;
  1817. break;
  1818. }
  1819. trailingComma = true;
  1820. if (MaybeEat(terminator)) {
  1821. break;
  1822. }
  1823. }
  1824. Expression ret = MakeTupleOrExpr(l, trailingComma, true);
  1825. ret.SetLoc(start0, GetEnd());
  1826. return ret;
  1827. }
  1828. private Expression ParseSliceEnd() {
  1829. Expression e2 = null;
  1830. switch (PeekToken().Kind) {
  1831. case TokenKind.Comma:
  1832. case TokenKind.RightBracket:
  1833. break;
  1834. default:
  1835. e2 = ParseExpression();
  1836. break;
  1837. }
  1838. return e2;
  1839. }
  1840. private Expression FinishSlice(Expression e0, SourceLocation start) {
  1841. Expression e1 = null;
  1842. Expression e2 = null;
  1843. bool stepProvided = false;
  1844. switch (PeekToken().Kind) {
  1845. case TokenKind.Comma:
  1846. case TokenKind.RightBracket:
  1847. break;
  1848. case TokenKind.Colon:
  1849. // x[?::?]
  1850. stepProvided = true;
  1851. NextToken();
  1852. e2 = ParseSliceEnd();
  1853. break;
  1854. default:
  1855. // x[?:val:?]
  1856. e1 = ParseExpression();
  1857. if (MaybeEat(TokenKind.Colon)) {
  1858. stepProvided = true;
  1859. e2 = ParseSliceEnd();
  1860. }
  1861. break;
  1862. }
  1863. SliceExpression ret = new SliceExpression(e0, e1, e2, stepProvided);
  1864. ret.SetLoc(start, GetEnd());
  1865. return ret;
  1866. }
  1867. //exprlist: expr (',' expr)* [',']
  1868. private List<Expression> ParseExprList() {
  1869. List<Expression> l = new List<Expression>();
  1870. while (true) {
  1871. Expression e = ParseExpr();
  1872. l.Add(e);
  1873. if (!MaybeEat(TokenKind.Comma)) {
  1874. break;
  1875. }
  1876. if (NeverTestToken(PeekToken())) {
  1877. break;
  1878. }
  1879. }
  1880. return l;
  1881. }
  1882. // arglist:
  1883. // expression rest_of_arguments
  1884. // expression "=" expression rest_of_arguments
  1885. // expression "for" gen_expr_rest
  1886. //
  1887. private Arg[] FinishArgListOrGenExpr() {
  1888. Arg a = null;
  1889. _sink.StartParameters(GetSpan());
  1890. Token t = PeekToken();
  1891. if (t.Kind != TokenKind.RightParenthesis && t.Kind != TokenKind.Multiply && t.Kind != TokenKind.Power) {
  1892. SourceLocation start = GetStart();
  1893. Expression e = ParseExpression();
  1894. if (e is ErrorExpression) {
  1895. return null;
  1896. }
  1897. if (MaybeEat(TokenKind.Assign)) { // Keyword argument
  1898. a = FinishKeywordArgument(e);
  1899. if (a == null) { // Error recovery
  1900. a = new Arg(e);
  1901. a.SetLoc(e.Start, GetEnd());
  1902. }
  1903. } else if (PeekToken(Tokens.KeywordForToken)) { // Generator expression
  1904. a = new Arg(ParseGeneratorExpression(e));
  1905. Eat(TokenKind.RightParenthesis);
  1906. a.SetLoc(start, GetEnd());
  1907. _sink.EndParameters(GetSpan());
  1908. return new Arg[1] { a }; // Generator expression is the argument
  1909. } else {
  1910. a = new Arg(e);
  1911. a.SetLoc(e.Start, e.End);
  1912. }
  1913. // Was this all?
  1914. //
  1915. if (MaybeEat(TokenKind.Comma)) {
  1916. _sink.NextParameter(GetSpan());
  1917. } else {
  1918. Eat(TokenKind.RightParenthesis);
  1919. a.SetLoc(start, GetEnd());
  1920. _sink.EndParameters(GetSpan());
  1921. return new Arg[1] { a };
  1922. }
  1923. }
  1924. return FinishArgumentList(a);
  1925. }
  1926. private Arg FinishKeywordArgument(Expression t) {
  1927. NameExpression n = t as NameExpression;
  1928. if (n == null) {
  1929. ReportSyntaxError(IronPython.Resources.ExpectedName);
  1930. Arg arg = new Arg(null, t);
  1931. arg.SetLoc(t.Start, t.End);
  1932. return arg;
  1933. } else {
  1934. Expression val = ParseExpression();
  1935. Arg arg = new Arg(n.Name, val);
  1936. arg.SetLoc(n.Start, val.End);
  1937. return arg;
  1938. }
  1939. }
  1940. private void CheckUniqueArgument(Dictionary<string, string> names, Arg arg) {
  1941. if (arg != null && arg.Name != null) {
  1942. string name = arg.Name;
  1943. if (names.ContainsKey(name)) {
  1944. ReportSyntaxError(IronPython.Resources.DuplicateKeywordArg);
  1945. }
  1946. names[name] = name;
  1947. }
  1948. }
  1949. //arglist: (argument ',')* (argument [',']| '*' expression [',' '**' expression] | '**' expression)
  1950. //argument: [expression '='] expression # Really [keyword '='] expression
  1951. private Arg[] FinishArgumentList(Arg first) {
  1952. const TokenKind terminator = TokenKind.RightParenthesis;
  1953. List<Arg> l = new List<Arg>();
  1954. Dictionary<string, string> names = new Dictionary<string, string>();
  1955. if (first != null) {
  1956. l.Add(first);
  1957. CheckUniqueArgument(names, first);
  1958. }
  1959. // Parse remaining arguments
  1960. while (true) {
  1961. if (MaybeEat(terminator)) {
  1962. break;
  1963. }
  1964. SourceLocation start = GetStart();
  1965. Arg a;
  1966. if (MaybeEat(TokenKind.Multiply)) {
  1967. Expression t = ParseExpression();
  1968. a = new Arg("*", t);
  1969. } else if (MaybeEat(TokenKind.Power)) {
  1970. Expression t = ParseExpression();
  1971. a = new Arg("**", t);
  1972. } else {
  1973. Expression e = ParseExpression();
  1974. if (MaybeEat(TokenKind.Assign)) {
  1975. a = FinishKeywordArgument(e);
  1976. CheckUniqueArgument(names, a);
  1977. } else {
  1978. a = new Arg(e);
  1979. }
  1980. }
  1981. a.SetLoc(start, GetEnd());
  1982. l.Add(a);
  1983. if (MaybeEat(TokenKind.Comma)) {
  1984. _sink.NextParameter(GetSpan());
  1985. } else {
  1986. Eat(terminator);
  1987. break;
  1988. }
  1989. }
  1990. _sink.EndParameters(GetSpan());
  1991. Arg[] ret = l.ToArray();
  1992. return ret;
  1993. }
  1994. private List<Expression> ParseTestList() {
  1995. bool tmp;
  1996. return ParseExpressionList(out tmp);
  1997. }
  1998. private Expression ParseOldExpressionListAsExpr() {
  1999. bool trailingComma;
  2000. List<Expression> l = ParseOldExpressionList(out trailingComma);
  2001. // the case when no expression was parsed e.g. when we have an empty expression list
  2002. if (l.Count == 0 && !trailingComma) {
  2003. ReportSyntaxError("invalid syntax");
  2004. }
  2005. return MakeTupleOrExpr(l, trailingComma);
  2006. }
  2007. // old_expression_list: old_expression [(',' old_expression)+ [',']]
  2008. private List<Expression> ParseOldExpressionList(out bool trailingComma) {
  2009. List<Expression> l = new List<Expression>();
  2010. trailingComma = false;
  2011. while (true) {
  2012. if (NeverTestToken(PeekToken())) break;
  2013. l.Add(ParseOldExpression());
  2014. if (!MaybeEat(TokenKind.Comma)) {
  2015. trailingComma = false;
  2016. break;
  2017. }
  2018. trailingComma = true;
  2019. }
  2020. return l;
  2021. }
  2022. // target_list: target ("," target)* [","]
  2023. private List<Expression> ParseTargetList(out bool trailingComma) {
  2024. List<Expression> l = new List<Expression>();
  2025. while (true) {
  2026. l.Add(ParseTarget());
  2027. if (!MaybeEat(TokenKind.Comma)) {
  2028. trailingComma = false;
  2029. break;
  2030. }
  2031. trailingComma = true;
  2032. if (NeverTestToken(PeekToken())) break;
  2033. }
  2034. return l;
  2035. }
  2036. // target: identifier | "(" target_list ")" | "[" target_list "]" | attributeref | subscription | slicing
  2037. private Expression ParseTarget() {
  2038. Token t = PeekToken();
  2039. switch (t.Kind) {
  2040. case TokenKind.LeftParenthesis: // parenth_form or generator_expression
  2041. case TokenKind.LeftBracket: // list_display
  2042. Eat(t.Kind);
  2043. bool trailingComma;
  2044. Expression res = MakeTupleOrExpr(ParseTargetList(out trailingComma), trailingComma);
  2045. if (t.Kind == TokenKind.LeftParenthesis) {
  2046. Eat(TokenKind.RightParenthesis);
  2047. } else {
  2048. Eat(TokenKind.RightBracket);
  2049. }
  2050. return res;
  2051. default: // identifier, attribute ref, subscription, slicing
  2052. return AddTrailers(ParsePrimary(), false);
  2053. }
  2054. }
  2055. // expression_list: expression (',' expression)* [',']
  2056. private List<Expression> ParseExpressionList(out bool trailingComma) {
  2057. List<Expression> l = new List<Expression>();
  2058. trailingComma = false;
  2059. while (true) {
  2060. if (NeverTestToken(PeekToken())) break;
  2061. l.Add(ParseExpression());
  2062. if (!MaybeEat(TokenKind.Comma)) {
  2063. trailingComma = false;
  2064. break;
  2065. }
  2066. trailingComma = true;
  2067. }
  2068. return l;
  2069. }
  2070. private Expression ParseTestListAsExpr(bool allowEmptyExpr) {
  2071. bool trailingComma;
  2072. List<Expression> l = ParseExpressionList(out trailingComma);
  2073. // the case when no expression was parsed e.g. when we have an empty expression list
  2074. if (!allowEmptyExpr && l.Count == 0 && !trailingComma) {
  2075. if (MaybeEat(TokenKind.Indent)) {
  2076. // the error is on the next token which has a useful location, unlike the indent - note we don't have an
  2077. // indent if we're at an EOF. It'a also an indentation error instead of a syntax error.
  2078. NextToken();
  2079. ReportSyntaxError(GetStart(), GetEnd(), "unexpected indent", ErrorCodes.IndentationError);
  2080. } else {
  2081. ReportSyntaxError(_lookahead);
  2082. }
  2083. }
  2084. return MakeTupleOrExpr(l, trailingComma);
  2085. }
  2086. private Expression FinishExpressionListAsExpr(Expression expr) {
  2087. SourceLocation start = GetStart();
  2088. bool trailingComma = true;
  2089. List<Expression> l = new List<Expression>();
  2090. l.Add(expr);
  2091. while (true) {
  2092. if (NeverTestToken(PeekToken())) break;
  2093. expr = ParseExpression();
  2094. l.Add(expr);
  2095. if (!MaybeEat(TokenKind.Comma)) {
  2096. trailingComma = false;
  2097. break;
  2098. }
  2099. trailingComma = true;
  2100. }
  2101. Expression ret = MakeTupleOrExpr(l, trailingComma);
  2102. ret.SetLoc(start, GetEnd());
  2103. return ret;
  2104. }
  2105. //
  2106. // testlist_gexp: expression ( genexpr_for | (',' expression)* [','] )
  2107. //
  2108. private Expression FinishTupleOrGenExp() {
  2109. SourceLocation lStart = GetStart();
  2110. SourceLocation lEnd = GetEnd();
  2111. int grouping = _tokenizer.GroupingLevel;
  2112. bool hasRightParenthesis;
  2113. Expression ret;
  2114. // Empty tuple
  2115. if (MaybeEat(TokenKind.RightParenthesis)) {
  2116. ret = MakeTupleOrExpr(new List<Expression>(), false);
  2117. hasRightParenthesis = true;
  2118. } else if (MaybeEat(TokenKind.KeywordYield)) {
  2119. ret = ParseYieldExpression();
  2120. Eat(TokenKind.RightParenthesis);
  2121. hasRightParenthesis = true;
  2122. } else {
  2123. bool prevAllow = _allowIncomplete;
  2124. try {
  2125. _allowIncomplete = true;
  2126. Expression expr = ParseExpression();
  2127. if (MaybeEat(TokenKind.Comma)) {
  2128. // "(" expression "," ...
  2129. ret = FinishExpressionListAsExpr(expr);
  2130. } else if (PeekToken(Tokens.KeywordForToken)) {
  2131. // "(" expression "for" ...
  2132. ret = ParseGeneratorExpression(expr);
  2133. } else {
  2134. // "(" expression ")"
  2135. ret = expr is ParenthesisExpression ? expr : new ParenthesisExpression(expr);
  2136. }
  2137. hasRightParenthesis = Eat(TokenKind.RightParenthesis);
  2138. } finally {
  2139. _allowIncomplete = prevAllow;
  2140. }
  2141. }
  2142. SourceLocation rStart = GetStart();
  2143. SourceLocation rEnd = GetEnd();
  2144. if (hasRightParenthesis) {
  2145. _sink.MatchPair(new SourceSpan(lStart, lEnd), new SourceSpan(rStart, rEnd), grouping);
  2146. }
  2147. ret.SetLoc(lStart, rEnd);
  2148. return ret;
  2149. }
  2150. // genexpr_for ::= "for" target_list "in" or_test [genexpr_iter]
  2151. // genexpr_iter ::= (genexpr_for | genexpr_if) *
  2152. //
  2153. // "for" has NOT been eaten before entering this method
  2154. private Expression ParseGeneratorExpression(Expression expr) {
  2155. ForStatement root = ParseGenExprFor();
  2156. Statement current = root;
  2157. for (; ; ) {
  2158. if (PeekToken(Tokens.KeywordForToken)) {
  2159. current = NestGenExpr(current, ParseGenExprFor());
  2160. } else if (PeekToken(Tokens.KeywordIfToken)) {
  2161. current = NestGenExpr(current, ParseGenExprIf());
  2162. } else {
  2163. // Generator Expressions have an implicit function definition and yield around their expression.
  2164. // (x for i in R)
  2165. // becomes:
  2166. // def f():
  2167. // for i in R: yield (x)
  2168. ExpressionStatement ys = new ExpressionStatement(new YieldExpression(expr));
  2169. ys.Expression.SetLoc(expr.Span);
  2170. ys.SetLoc(expr.Span);
  2171. NestGenExpr(current, ys);
  2172. break;
  2173. }
  2174. }
  2175. // We pass the outermost iterable in as a parameter because Python semantics
  2176. // say that this one piece is computed at definition time rather than iteration time
  2177. const string fname = "__generator_";
  2178. Parameter parameter = new Parameter("__gen_$_parm__", 0);
  2179. FunctionDefinition func = new FunctionDefinition(fname, new Parameter[] { parameter }, root);
  2180. func.IsGenerator = true;
  2181. func.SetLoc(root.Start, GetEnd());
  2182. func.Header = root.End;
  2183. // Transform the root "for" statement
  2184. Expression outermost = root.List;
  2185. NameExpression ne = new NameExpression("__gen_$_parm__");
  2186. ne.SetLoc(outermost.Span);
  2187. root.List = ne;
  2188. GeneratorExpression ret = new GeneratorExpression(func, outermost);
  2189. ret.SetLoc(expr.Start, GetEnd());
  2190. return ret;
  2191. }
  2192. private static Statement NestGenExpr(Statement current, Statement nested) {
  2193. ForStatement fes = current as ForStatement;
  2194. IfStatement ifs;
  2195. if (fes != null) {
  2196. fes.Body = nested;
  2197. } else if ((ifs = current as IfStatement) != null) {
  2198. ifs.Tests[0].Body = nested;
  2199. }
  2200. return nested;
  2201. }
  2202. // "for" target_list "in" or_test
  2203. private ForStatement ParseGenExprFor() {
  2204. SourceLocation start = GetStart();
  2205. Eat(TokenKind.KeywordFor);
  2206. bool trailingComma;
  2207. List<Expression> l = ParseTargetList(out trailingComma);
  2208. Expression lhs = MakeTupleOrExpr(l, trailingComma);
  2209. Eat(TokenKind.KeywordIn);
  2210. Expression expr = null;
  2211. expr = ParseOrTest();
  2212. ForStatement gef = new ForStatement(lhs, expr, null, null);
  2213. SourceLocation end = GetEnd();
  2214. gef.SetLoc(start, end);
  2215. gef.Header = end;
  2216. return gef;
  2217. }
  2218. // genexpr_if: "if" old_test
  2219. private IfStatement ParseGenExprIf() {
  2220. SourceLocation start = GetStart();
  2221. Eat(TokenKind.KeywordIf);
  2222. Expression expr = ParseOldExpression();
  2223. IfStatementTest ist = new IfStatementTest(expr, null);
  2224. SourceLocation end = GetEnd();
  2225. ist.Header = end;
  2226. ist.SetLoc(start, end);
  2227. IfStatement gei = new IfStatement(new IfStatementTest[] { ist }, null);
  2228. gei.SetLoc(start, end);
  2229. return gei;
  2230. }
  2231. // dict_display: '{' [key_datum_list] '}'
  2232. // key_datum_list: key_datum (',' key_datum)* [","]
  2233. // key_datum: expression ':' expression
  2234. private Expression FinishDictValue() {
  2235. SourceLocation oStart = GetStart();
  2236. SourceLocation oEnd = GetEnd();
  2237. List<SliceExpression> l = new List<SliceExpression>();
  2238. bool prevAllow = _allowIncomplete;
  2239. try {
  2240. _allowIncomplete = true;
  2241. while (true) {
  2242. if (MaybeEat(TokenKind.RightBrace)) {
  2243. break;
  2244. }
  2245. Expression e1 = ParseExpression();
  2246. Eat(TokenKind.Colon);
  2247. Expression e2 = ParseExpression();
  2248. SliceExpression se = new SliceExpression(e1, e2, null, false);
  2249. se.SetLoc(e1.Start, e2.End);
  2250. l.Add(se);
  2251. if (!MaybeEat(TokenKind.Comma)) {
  2252. Eat(TokenKind.RightBrace);
  2253. break;
  2254. }
  2255. }
  2256. } finally {
  2257. _allowIncomplete = prevAllow;
  2258. }
  2259. SourceLocation cStart = GetStart();
  2260. SourceLocation cEnd = GetEnd();
  2261. _sink.MatchPair(new SourceSpan(oStart, oEnd), new SourceSpan(cStart, cEnd), 1);
  2262. SliceExpression[] exprs = l.ToArray();
  2263. DictionaryExpression ret = new DictionaryExpression(exprs);
  2264. ret.SetLoc(oStart, cEnd);
  2265. return ret;
  2266. }
  2267. // listmaker: expression ( list_for | (',' expression)* [','] )
  2268. private Expression FinishListValue() {
  2269. SourceLocation oStart = GetStart();
  2270. SourceLocation oEnd = GetEnd();
  2271. int grouping = _tokenizer.GroupingLevel;
  2272. Expression ret;
  2273. if (MaybeEat(TokenKind.RightBracket)) {
  2274. ret = new ListExpression();
  2275. } else {
  2276. bool prevAllow = _allowIncomplete;
  2277. try {
  2278. _allowIncomplete = true;
  2279. Expression t0 = ParseExpression();
  2280. if (MaybeEat(TokenKind.Comma)) {
  2281. List<Expression> l = ParseTestList();
  2282. Eat(TokenKind.RightBracket);
  2283. l.Insert(0, t0);
  2284. ret = new ListExpression(l.ToArray());
  2285. } else if (PeekToken(Tokens.KeywordForToken)) {
  2286. ret = FinishListComp(t0);
  2287. } else {
  2288. Eat(TokenKind.RightBracket);
  2289. ret = new ListExpression(t0);
  2290. }
  2291. } finally {
  2292. _allowIncomplete = prevAllow;
  2293. }
  2294. }
  2295. SourceLocation cStart = GetStart();
  2296. SourceLocation cEnd = GetEnd();
  2297. _sink.MatchPair(new SourceSpan(oStart, oEnd), new SourceSpan(cStart, cEnd), grouping);
  2298. ret.SetLoc(oStart, cEnd);
  2299. return ret;
  2300. }
  2301. // list_iter: list_for | list_if
  2302. private ListComprehension FinishListComp(Expression item) {
  2303. List<ListComprehensionIterator> iters = new List<ListComprehensionIterator>();
  2304. ListComprehensionFor firstFor = ParseListCompFor();
  2305. iters.Add(firstFor);
  2306. while (true) {
  2307. if (PeekToken(Tokens.KeywordForToken)) {
  2308. iters.Add(ParseListCompFor());
  2309. } else if (PeekToken(Tokens.KeywordIfToken)) {
  2310. iters.Add(ParseListCompIf());
  2311. } else {
  2312. break;
  2313. }
  2314. }
  2315. Eat(TokenKind.RightBracket);
  2316. return new ListComprehension(item, iters.ToArray());
  2317. }
  2318. // list_for: 'for' target_list 'in' old_expression_list [list_iter]
  2319. private ListComprehensionFor ParseListCompFor() {
  2320. Eat(TokenKind.KeywordFor);
  2321. SourceLocation start = GetStart();
  2322. bool trailingComma;
  2323. List<Expression> l = ParseTargetList(out trailingComma);
  2324. // expr list is something like:
  2325. // ()
  2326. // a
  2327. // a,b
  2328. // a,b,c
  2329. // we either want just () or a or we want (a,b) and (a,b,c)
  2330. // so we can do tupleExpr.EmitSet() or loneExpr.EmitSet()
  2331. Expression lhs = MakeTupleOrExpr(l, trailingComma);
  2332. Eat(TokenKind.KeywordIn);
  2333. Expression list = null;
  2334. list = ParseOldExpressionListAsExpr();
  2335. ListComprehensionFor ret = new ListComprehensionFor(lhs, list);
  2336. ret.SetLoc(start, GetEnd());
  2337. return ret;
  2338. }
  2339. // list_if: 'if' old_test [list_iter]
  2340. private ListComprehensionIf ParseListCompIf() {
  2341. Eat(TokenKind.KeywordIf);
  2342. SourceLocation start = GetStart();
  2343. Expression expr = ParseOldExpression();
  2344. ListComprehensionIf ret = new ListComprehensionIf(expr);
  2345. ret.SetLoc(start, GetEnd());
  2346. return ret;
  2347. }
  2348. private Expression FinishStringConversion() {
  2349. Expression ret;
  2350. SourceLocation start = GetStart();
  2351. Expression expr = ParseTestListAsExpr(false);
  2352. Eat(TokenKind.BackQuote);
  2353. ret = new BackQuoteExpression(expr);
  2354. ret.SetLoc(start, GetEnd());
  2355. return ret;
  2356. }
  2357. private static Expression MakeTupleOrExpr(List<Expression> l, bool trailingComma) {
  2358. return MakeTupleOrExpr(l, trailingComma, false);
  2359. }
  2360. private static Expression MakeTupleOrExpr(List<Expression> l, bool trailingComma, bool expandable) {
  2361. if (l.Count == 1 && !trailingComma) return l[0];
  2362. Expression[] exprs = l.ToArray();
  2363. TupleExpression te = new TupleExpression(expandable && !trailingComma, exprs);
  2364. if (exprs.Length > 0) {
  2365. te.SetLoc(exprs[0].Start, exprs[exprs.Length - 1].End);
  2366. }
  2367. return te;
  2368. }
  2369. private static bool NeverTestToken(Token t) {
  2370. switch (t.Kind) {
  2371. case TokenKind.AddEqual:
  2372. case TokenKind.SubtractEqual:
  2373. case TokenKind.MultiplyEqual:
  2374. case TokenKind.DivideEqual:
  2375. case TokenKind.ModEqual:
  2376. case TokenKind.BitwiseAndEqual:
  2377. case TokenKind.BitwiseOrEqual:
  2378. case TokenKind.ExclusiveOrEqual:
  2379. case TokenKind.LeftShiftEqual:
  2380. case TokenKind.RightShiftEqual:
  2381. case TokenKind.PowerEqual:
  2382. case TokenKind.FloorDivideEqual:
  2383. case TokenKind.Indent:
  2384. case TokenKind.Dedent:
  2385. case TokenKind.NewLine:
  2386. case TokenKind.EndOfFile:
  2387. case TokenKind.Semicolon:
  2388. case TokenKind.Assign:
  2389. case TokenKind.RightBrace:
  2390. case TokenKind.RightBracket:
  2391. case TokenKind.RightParenthesis:
  2392. case TokenKind.Comma:
  2393. case TokenKind.KeywordFor:
  2394. case TokenKind.KeywordIn:
  2395. case TokenKind.KeywordIf:
  2396. return true;
  2397. default: return false;
  2398. }
  2399. }
  2400. private FunctionDefinition CurrentFunction {
  2401. get {
  2402. if (_functions != null && _functions.Count > 0) {
  2403. return _functions.Peek();
  2404. }
  2405. return null;
  2406. }
  2407. }
  2408. private FunctionDefinition PopFunction() {
  2409. if (_functions != null && _functions.Count > 0) {
  2410. return _functions.Pop();
  2411. }
  2412. return null;
  2413. }
  2414. private void PushFunction(FunctionDefinition function) {
  2415. if (_functions == null) {
  2416. _functions = new Stack<FunctionDefinition>();
  2417. }
  2418. _functions.Push(function);
  2419. }
  2420. private CallExpression FinishCallExpr(Expression target, params Arg[] args) {
  2421. bool hasArgsTuple = false;
  2422. bool hasKeywordDict = false;
  2423. int keywordCount = 0;
  2424. int extraArgs = 0;
  2425. foreach (Arg arg in args) {
  2426. if (arg.Name == null) {
  2427. if (hasArgsTuple || hasKeywordDict || keywordCount > 0) {
  2428. ReportSyntaxError(IronPython.Resources.NonKeywordAfterKeywordArg);
  2429. }
  2430. } else if (arg.Name == "*") {
  2431. if (hasArgsTuple || hasKeywordDict) {
  2432. ReportSyntaxError(IronPython.Resources.OneListArgOnly);
  2433. }
  2434. hasArgsTuple = true; extraArgs++;
  2435. } else if (arg.Name == "**") {
  2436. if (hasKeywordDict) {
  2437. ReportSyntaxError(IronPython.Resources.OneKeywordArgOnly);
  2438. }
  2439. hasKeywordDict = true; extraArgs++;
  2440. } else {
  2441. if (hasKeywordDict) {
  2442. ReportSyntaxError(IronPython.Resources.KeywordOutOfSequence);
  2443. }
  2444. keywordCount++;
  2445. }
  2446. }
  2447. return new CallExpression(target, args);
  2448. }
  2449. #endregion
  2450. #region IDisposable Members
  2451. public void Dispose() {
  2452. if (_sourceReader != null) {
  2453. _sourceReader.Close();
  2454. }
  2455. }
  2456. #endregion
  2457. #region Implementation Details
  2458. private PythonAst ParseFileWorker(bool makeModule, bool returnValue) {
  2459. StartParsing();
  2460. List<Statement> l = new List<Statement>();
  2461. //
  2462. // A future statement must appear near the top of the module.
  2463. // The only lines that can appear before a future statement are:
  2464. // - the module docstring (if any),
  2465. // - comments,
  2466. // - blank lines, and
  2467. // - other future statements.
  2468. //
  2469. MaybeEatNewLine();
  2470. if (PeekToken(TokenKind.Constant)) {
  2471. Statement s = ParseStmt();
  2472. l.Add(s);
  2473. _fromFutureAllowed = false;
  2474. ExpressionStatement es = s as ExpressionStatement;
  2475. if (es != null) {
  2476. ConstantExpression ce = es.Expression as ConstantExpression;
  2477. if (ce != null && ce.Value is string) {
  2478. // doc string
  2479. _fromFutureAllowed = true;
  2480. }
  2481. }
  2482. }
  2483. MaybeEatNewLine();
  2484. // from __future__
  2485. if (_fromFutureAllowed) {
  2486. while (PeekToken(Tokens.KeywordFromToken)) {
  2487. Statement s = ParseStmt();
  2488. l.Add(s);
  2489. FromImportStatement fis = s as FromImportStatement;
  2490. if (fis != null && !fis.IsFromFuture) {
  2491. // end of from __future__
  2492. break;
  2493. }
  2494. }
  2495. }
  2496. // the end of from __future__ sequence
  2497. _fromFutureAllowed = false;
  2498. while (true) {
  2499. if (MaybeEat(TokenKind.EndOfFile)) break;
  2500. if (MaybeEatNewLine()) continue;
  2501. Statement s = ParseStmt();
  2502. l.Add(s);
  2503. }
  2504. Statement[] stmts = l.ToArray();
  2505. if (returnValue && stmts.Length > 0) {
  2506. ExpressionStatement exprStmt = stmts[stmts.Length - 1] as ExpressionStatement;
  2507. if (exprStmt != null) {
  2508. stmts[stmts.Length - 1] = new ReturnStatement(exprStmt.Expression);
  2509. }
  2510. }
  2511. SuiteStatement ret = new SuiteStatement(stmts);
  2512. ret.SetLoc(_sourceUnit.MakeLocation(SourceLocation.MinValue), GetEnd());
  2513. return new PythonAst(ret, makeModule, _languageFeatures, false, _context);
  2514. }
  2515. private Statement InternalParseInteractiveInput(out bool parsingMultiLineCmpdStmt, out bool isEmptyStmt) {
  2516. try {
  2517. Statement s;
  2518. isEmptyStmt = false;
  2519. parsingMultiLineCmpdStmt = false;
  2520. switch (PeekToken().Kind) {
  2521. case TokenKind.NewLine:
  2522. MaybeEatNewLine();
  2523. Eat(TokenKind.EndOfFile);
  2524. if (_tokenizer.EndContinues) {
  2525. parsingMultiLineCmpdStmt = true;
  2526. _errorCode = ErrorCodes.IncompleteStatement;
  2527. } else {
  2528. isEmptyStmt = true;
  2529. }
  2530. return null;
  2531. case TokenKind.KeywordIf:
  2532. case TokenKind.KeywordWhile:
  2533. case TokenKind.KeywordFor:
  2534. case TokenKind.KeywordTry:
  2535. case TokenKind.At:
  2536. case TokenKind.KeywordDef:
  2537. case TokenKind.KeywordClass:
  2538. case TokenKind.KeywordWith:
  2539. parsingMultiLineCmpdStmt = true;
  2540. s = ParseStmt();
  2541. EatEndOfInput();
  2542. break;
  2543. default:
  2544. // parseSimpleStmt takes care of one or more simple_stmts and the Newline
  2545. s = ParseSimpleStmt();
  2546. MaybeEatNewLine();
  2547. Eat(TokenKind.EndOfFile);
  2548. break;
  2549. }
  2550. return s;
  2551. } catch (BadSourceException bse) {
  2552. throw BadSourceError(bse);
  2553. }
  2554. }
  2555. private Expression ParseTestListAsExpression() {
  2556. StartParsing();
  2557. Expression expression = ParseTestListAsExpr(false);
  2558. EatEndOfInput();
  2559. return expression;
  2560. }
  2561. /// <summary>
  2562. /// Maybe eats a new line token returning true if the token was
  2563. /// eaten.
  2564. ///
  2565. /// Python always tokenizes to have only 1 new line character in a
  2566. /// row. But we also craete NLToken's and ignore them except for
  2567. /// error reporting purposes. This gives us the same errors as
  2568. /// CPython and also matches the behavior of the standard library
  2569. /// tokenize module. This function eats any present NL tokens and throws
  2570. /// them away.
  2571. /// </summary>
  2572. private bool MaybeEatNewLine() {
  2573. if (MaybeEat(TokenKind.NewLine)) {
  2574. while (MaybeEat(TokenKind.NLToken)) ;
  2575. return true;
  2576. }
  2577. return false;
  2578. }
  2579. /// <summary>
  2580. /// Eats a new line token throwing if the next token isn't a new line.
  2581. ///
  2582. /// Python always tokenizes to have only 1 new line character in a
  2583. /// row. But we also craete NLToken's and ignore them except for
  2584. /// error reporting purposes. This gives us the same errors as
  2585. /// CPython and also matches the behavior of the standard library
  2586. /// tokenize module. This function eats any present NL tokens and throws
  2587. /// them away.
  2588. /// </summary>
  2589. private bool EatNewLine() {
  2590. bool res = Eat(TokenKind.NewLine);
  2591. while (MaybeEat(TokenKind.NLToken)) ;
  2592. return res;
  2593. }
  2594. private Token EatEndOfInput() {
  2595. while (MaybeEatNewLine() || MaybeEat(TokenKind.Dedent)) {
  2596. ;
  2597. }
  2598. Token t = NextToken();
  2599. if (t.Kind != TokenKind.EndOfFile) {
  2600. ReportSyntaxError(_token);
  2601. }
  2602. return t;
  2603. }
  2604. private Exception/*!*/ BadSourceError(BadSourceException bse) {
  2605. StreamReader sr = _sourceReader.BaseReader as StreamReader;
  2606. if (sr != null && sr.BaseStream.CanSeek) {
  2607. return PythonContext.ReportEncodingError(sr.BaseStream, _sourceUnit.Path);
  2608. }
  2609. // BUG: We have some weird stream and we can't accurately track the
  2610. // position where the exception came from. There are too many levels
  2611. // of buffering below us to re-wind and calculate the actual line number, so
  2612. // we'll give the last line number the tokenizer was at.
  2613. return IronPython.Runtime.Operations.PythonOps.BadSourceError(
  2614. bse._badByte,
  2615. new SourceSpan(_tokenizer.CurrentPosition, _tokenizer.CurrentPosition),
  2616. _sourceUnit.Path
  2617. );
  2618. }
  2619. private bool TrueDivision {
  2620. get { return (_languageFeatures & ModuleOptions.TrueDivision) == ModuleOptions.TrueDivision; }
  2621. }
  2622. private bool AbsoluteImports {
  2623. get { return (_languageFeatures & ModuleOptions.AbsoluteImports) == ModuleOptions.AbsoluteImports; }
  2624. }
  2625. private void StartParsing() {
  2626. if (_parsingStarted)
  2627. throw new InvalidOperationException("Parsing already started. Use Restart to start again.");
  2628. _parsingStarted = true;
  2629. FetchLookahead();
  2630. }
  2631. private SourceLocation GetEnd() {
  2632. Debug.Assert(_token.Token != null, "No token fetched");
  2633. return _token.Span.End;
  2634. }
  2635. private SourceLocation GetStart() {
  2636. Debug.Assert(_token.Token != null, "No token fetched");
  2637. return _token.Span.Start;
  2638. }
  2639. private SourceSpan GetSpan() {
  2640. Debug.Assert(_token.Token != null, "No token fetched");
  2641. return _token.Span;
  2642. }
  2643. private Token NextToken() {
  2644. _token = _lookahead;
  2645. FetchLookahead();
  2646. return _token.Token;
  2647. }
  2648. private Token PeekToken() {
  2649. return _lookahead.Token;
  2650. }
  2651. private void FetchLookahead() {
  2652. _lookahead.Token = _tokenizer.GetNextToken();
  2653. _lookahead.Span = _tokenizer.TokenSpan;
  2654. }
  2655. private bool PeekToken(TokenKind kind) {
  2656. return PeekToken().Kind == kind;
  2657. }
  2658. private bool PeekToken(Token check) {
  2659. return PeekToken() == check;
  2660. }
  2661. private bool Eat(TokenKind kind) {
  2662. Token next = PeekToken();
  2663. if (next.Kind != kind) {
  2664. ReportSyntaxError(_lookahead);
  2665. return false;
  2666. } else {
  2667. NextToken();
  2668. return true;
  2669. }
  2670. }
  2671. private bool EatNoEof(TokenKind kind) {
  2672. Token next = PeekToken();
  2673. if (next.Kind != kind) {
  2674. ReportSyntaxError(_lookahead.Token, _lookahead.Span, ErrorCodes.SyntaxError, false);
  2675. return false;
  2676. }
  2677. NextToken();
  2678. return true;
  2679. }
  2680. private bool MaybeEat(TokenKind kind) {
  2681. if (PeekToken().Kind == kind) {
  2682. NextToken();
  2683. return true;
  2684. } else {
  2685. return false;
  2686. }
  2687. }
  2688. private class TokenizerErrorSink : ErrorSink {
  2689. private readonly Parser _parser;
  2690. public TokenizerErrorSink(Parser parser) {
  2691. Assert.NotNull(parser);
  2692. _parser = parser;
  2693. }
  2694. public override void Add(SourceUnit sourceUnit, string message, SourceSpan span, int errorCode, Severity severity) {
  2695. if (_parser._errorCode == 0 && (severity == Severity.Error || severity == Severity.FatalError)) {
  2696. _parser._errorCode = errorCode;
  2697. }
  2698. _parser.ErrorSink.Add(sourceUnit, message, span, errorCode, severity);
  2699. }
  2700. }
  2701. #endregion
  2702. }
  2703. }