PageRenderTime 69ms CodeModel.GetById 23ms 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

Large files files are truncated, but you can click here to view the full 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.Ki

Large files files are truncated, but you can click here to view the full file