LNode TentativeExpr(VList<LNode> attrs, out TentativeResult result, bool allowUnassigned = false) { result = new TentativeResult(InputPosition); var oldState = _tentative; _tentative = new TentativeState(true); { try { bool failed = false; result.Result = Expr(StartExpr).PlusAttrs(attrs); if ((LA0 != EOF && LA0 != TT.Semicolon && LA0 != TT.Comma)) { failed = true; } result.Errors = _tentative.DeferredErrors; result.InputPosition = InputPosition; if (failed || _tentative.LocalErrorCount != 0) { InputPosition = result.OldPosition; return null; } } finally { _tentative = oldState; } } return Apply(result); }
LNode Apply(TentativeResult result) { InputPosition = result.InputPosition; if (result.Errors != null) { result.Errors.WriteListTo(CurrentSink(false)); } return result.Result; }
// Parses an expression (TentativeExpr) or variable declaration (TentativeVarDecl). // Returns the parsed node on success or null if outer-level parse error(s) // occurred; the out param result is never null, and in case of success it // is the same as the return value. Error handling is tricky... we fail if // there are errors at the current level, not if there are errors in // parenthesized subexpressions. LNode TentativeVarDecl(VList<LNode> attrs, out TentativeResult result, bool allowUnassigned = false) { result = new TentativeResult(InputPosition); var oldState = _tentative; _tentative = new TentativeState(true); { try { bool failed = false; int _; var cat = DetectStatementCategoryAndAddWordAttributes(out _, ref attrs, DetectionMode.Expr); if ((cat != StmtCat.MethodOrPropOrVar)) { failed = true; result.Result = F.Missing; } else { bool hasInitializer; result.Result = VarDeclExpr(out hasInitializer, attrs); if ((!hasInitializer && !allowUnassigned)) { Error(-1, "An unassigned variable declaration is not allowed in this context"); } } result.Errors = _tentative.DeferredErrors; result.InputPosition = InputPosition; if (failed || _tentative.LocalErrorCount != 0) { // error(s) occurred. InputPosition = result.OldPosition; return null; } } finally { _tentative = oldState; } } return Apply(result); // must Apply after finally block }