internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (!Parser.Validate(state.Code, "for(", ref i) && (!Parser.Validate(state.Code, "for (", ref i))) { return(null); } while (Tools.IsWhiteSpace(state.Code[i])) { i++; } CodeNode init = null; CodeNode body = null; CodeNode condition = null; CodeNode post = null; CodeNode result = null; var labelsCount = state.LabelsCount; var oldVariablesCount = state.Variables.Count; state.LabelsCount = 0; state.lexicalScopeLevel++; try { init = VariableDefinition.Parse(state, ref i, true); if (init == null) { init = ExpressionTree.Parse(state, ref i, forForLoop: true); } if ((init is ExpressionTree) && (init as ExpressionTree).Type == OperationType.None && (init as ExpressionTree)._right == null) { init = (init as ExpressionTree)._left; } if (state.Code[i] != ';') { ExceptionHelper.Throw((new SyntaxError("Expected \";\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); condition = state.Code[i] == ';' ? null as CodeNode : ExpressionTree.Parse(state, ref i, forForLoop: true); if (state.Code[i] != ';') { ExceptionHelper.Throw((new SyntaxError("Expected \";\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); post = state.Code[i] == ')' ? null as CodeNode : ExpressionTree.Parse(state, ref i, forForLoop: true); while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != ')') { ExceptionHelper.Throw((new SyntaxError("Expected \";\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } i++; Tools.SkipSpaces(state.Code, ref i); state.AllowBreak.Push(true); state.AllowContinue.Push(true); try { body = Parser.Parse(state, ref i, 0); var vds = body as VariableDefinition; if (vds != null) { if (vds.Kind >= VariableKind.ConstantInLexicalScope) { ExceptionHelper.ThrowSyntaxError("Block scope variables can not be declared in for-loop directly", state.Code, body.Position); } if (state.message != null) { state.message(MessageLevel.Warning, CodeCoordinates.FromTextPosition(state.Code, body.Position, body.Length), "Do not declare variables in for-loop directly"); } } } finally { state.AllowBreak.Pop(); state.AllowContinue.Pop(); } int startPos = index; index = i; result = new For() { _body = body, _condition = condition, _initializer = init, _post = post, labels = state.Labels.GetRange(state.Labels.Count - labelsCount, labelsCount).ToArray(), Position = startPos, Length = index - startPos }; var vars = CodeBlock.extractVariables(state, oldVariablesCount); result = new CodeBlock(new[] { result }) { _variables = vars, Position = result.Position, Length = result.Length }; } finally { state.lexicalScopeLevel--; } return(result); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; if (!Parser.Validate(state.Code, "try", ref i) || !Parser.IsIdentifierTerminator(state.Code[i])) { return(null); } while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])) { i++; } if (i >= state.Code.Length) { ExceptionHelper.Throw(new SyntaxError(Strings.UnexpectedEndOfSource)); } if (state.Code[i] != '{') { ExceptionHelper.Throw((new SyntaxError("Invalid try statement definition at " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } var b = CodeBlock.Parse(state, ref i); while (Tools.IsWhiteSpace(state.Code[i])) { i++; } CodeNode cb = null; string exptn = null; if (Parser.Validate(state.Code, "catch (", ref i) || Parser.Validate(state.Code, "catch(", ref i)) { Tools.SkipSpaces(state.Code, ref i); int s = i; if (!Parser.ValidateName(state.Code, ref i, state.strict)) { ExceptionHelper.Throw((new SyntaxError("Catch block must contain variable name " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } exptn = Tools.Unescape(state.Code.Substring(s, i - s), state.strict); if (state.strict) { if (exptn == "arguments" || exptn == "eval") { ExceptionHelper.Throw((new SyntaxError("Varible name can not be \"arguments\" or \"eval\" in strict mode at " + CodeCoordinates.FromTextPosition(state.Code, s, i - s)))); } } Tools.SkipSpaces(state.Code, ref i); if (!Parser.Validate(state.Code, ")", ref i)) { ExceptionHelper.Throw((new SyntaxError("Expected \")\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != '{') { ExceptionHelper.Throw((new SyntaxError("Invalid catch block statement definition at " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } state.lexicalScopeLevel++; try { cb = CodeBlock.Parse(state, ref i); } finally { state.lexicalScopeLevel--; } while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])) { i++; } } CodeNode f = null; if (Parser.Validate(state.Code, "finally", i) && Parser.IsIdentifierTerminator(state.Code[i + 7])) { i += 7; while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != '{') { ExceptionHelper.Throw((new SyntaxError("Invalid finally block statement definition at " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } f = CodeBlock.Parse(state, ref i); } if (cb == null && f == null) { ExceptionHelper.ThrowSyntaxError("try block must contain 'catch' or/and 'finally' block", state.Code, index); } var pos = index; index = i; return(new TryCatch() { body = (CodeBlock)b, catchBody = (CodeBlock)cb, finallyBody = (CodeBlock)f, catchVariableDesc = new VariableDescriptor(exptn, state.lexicalScopeLevel + 1), Position = pos, Length = index - pos }); }
public override bool Build(ref CodeNode _this, int expressionDepth, Dictionary <string, VariableDescriptor> variables, CodeContext codeContext, CompilerMessageCallback message, FunctionInfo stats, Options opts) { Parser.Build(ref _initializer, 1, variables, codeContext, message, stats, opts); var initAsVds = _initializer as VariableDefinition; if ((opts & Options.SuppressUselessStatementsElimination) == 0) { if (initAsVds != null && initAsVds._initializers.Length == 1 && initAsVds.Kind == VariableKind.FunctionScope) { _initializer = initAsVds._initializers[0]; } } Parser.Build(ref _condition, 2, variables, codeContext | CodeContext.InLoop | CodeContext.InExpression, message, stats, opts); if (_post != null) { Parser.Build(ref _post, 1, variables, codeContext | CodeContext.Conditional | CodeContext.InLoop | CodeContext.InExpression, message, stats, opts); if (_post == null && message != null) { message(MessageLevel.Warning, new CodeCoordinates(0, Position, Length), "Last expression of for-loop was removed. Maybe, it's a mistake."); } } Parser.Build(ref _body, System.Math.Max(1, expressionDepth), variables, codeContext | CodeContext.Conditional | CodeContext.InLoop, message, stats, opts); if (initAsVds != null && initAsVds.Kind != VariableKind.FunctionScope && initAsVds._variables.Any(x => x.captured)) { var bodyAsCodeBlock = _body as CodeBlock; if (bodyAsCodeBlock != null) { var newLines = new CodeNode[bodyAsCodeBlock._lines.Length + 1]; System.Array.Copy(bodyAsCodeBlock._lines, newLines, bodyAsCodeBlock._lines.Length); newLines[newLines.Length - 1] = new PerIterationScopeInitializer(initAsVds._variables); bodyAsCodeBlock._lines = newLines; } else { _body = bodyAsCodeBlock = new CodeBlock(new[] { _body, new PerIterationScopeInitializer(initAsVds._variables) }); } bodyAsCodeBlock._suppressScopeIsolation = SuppressScopeIsolationMode.DoNotSuppress; for (var i = 0; i < initAsVds._variables.Length; i++) { if (initAsVds._variables[i].captured) { initAsVds._variables[i].definitionScopeLevel = -1; } } } if (_condition == null) { _condition = new Constant(BaseLibrary.Boolean.True); } else if ((_condition is Expression) && (_condition as Expression).ContextIndependent && !(bool)_condition.Evaluate(null)) { _this = _initializer; return(false); } else if (_body == null || _body is Empty) { VariableReference variable = null; Constant limit = null; if (_condition is Less) { variable = (_condition as Less).LeftOperand as VariableReference; limit = (_condition as Less).RightOperand as Constant; } else if (_condition is More) { variable = (_condition as More).RightOperand as VariableReference; limit = (_condition as More).LeftOperand as Constant; } else if (_condition is NotEqual) { variable = (_condition as Less).RightOperand as VariableReference; limit = (_condition as Less).LeftOperand as Constant; if (variable == null && limit == null) { variable = (_condition as Less).LeftOperand as VariableReference; limit = (_condition as Less).RightOperand as Constant; } } if (variable != null && limit != null && _post is Increment && ((_post as Increment).LeftOperand as VariableReference)._descriptor == variable._descriptor) { if (variable.ScopeLevel >= 0 && variable._descriptor.definitionScopeLevel >= 0) { if (_initializer is Assignment && (_initializer as Assignment).LeftOperand is Variable && ((_initializer as Assignment).LeftOperand as Variable)._descriptor == variable._descriptor) { var value = (_initializer as Assignment).RightOperand; if (value is Constant) { var vvalue = value.Evaluate(null); var lvalue = limit.Evaluate(null); if ((vvalue._valueType == JSValueType.Integer || vvalue._valueType == JSValueType.Boolean || vvalue._valueType == JSValueType.Double) && (lvalue._valueType == JSValueType.Integer || lvalue._valueType == JSValueType.Boolean || lvalue._valueType == JSValueType.Double)) { _post.Eliminated = true; _condition.Eliminated = true; if (!Less.Check(vvalue, lvalue)) { _this = _initializer; return(false); } _this = new CodeBlock(new[] { _initializer, new Assignment(variable, limit) }); return(true); } } } } } } return(false); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; Tools.SkipSpaces(state.Code, ref i); if (!Parser.Validate(state.Code, "for(", ref i) && (!Parser.Validate(state.Code, "for (", ref i))) { return(null); } Tools.SkipSpaces(state.Code, ref i); var result = new ForIn() { _labels = state.Labels.GetRange(state.Labels.Count - state.LabelsCount, state.LabelsCount).ToArray() }; VariableDescriptor[] vars = null; var oldVariablesCount = state.Variables.Count; state.lexicalScopeLevel++; try { var vStart = i; var variableName = ""; var variableNameStart = 0; var variableDef = VariableDefinition.Parse(state, ref i, true); if (variableDef == null) { if (state.Code[i] == ';') { return(null); } Tools.SkipSpaces(state.Code, ref i); variableNameStart = i; if (!Parser.ValidateName(state.Code, ref i, state.strict)) { return(null); } variableName = Tools.Unescape(state.Code.Substring(variableNameStart, i - variableNameStart), state.strict); variableDef = new Variable(variableName, state.lexicalScopeLevel) { Position = variableNameStart, Length = i - variableNameStart, ScopeLevel = state.lexicalScopeLevel }; Tools.SkipSpaces(state.Code, ref i); if (state.Code[i] == '=') { Tools.SkipSpaces(state.Code, ref i); var defVal = ExpressionTree.Parse(state, ref i, false, false, false, true, true); if (defVal == null) { return(defVal); } Expression exp = new AssignmentOperatorCache(variableDef as Variable); exp = new Assignment(exp, defVal) { Position = exp.Position, Length = defVal.EndPosition - exp.Position }; if (variableDef == exp._left._left) { variableDef = exp; } Tools.SkipSpaces(state.Code, ref i); } } else { variableName = (variableDef as VariableDefinition)._variables[0].name; } if (!Parser.Validate(state.Code, "in", ref i)) { if (oldVariablesCount < state.Variables.Count) { state.Variables.RemoveRange(oldVariablesCount, state.Variables.Count - oldVariablesCount); } return(null); } if (state.strict) { if (variableName == "arguments" || variableName == "eval") { ExceptionHelper.ThrowSyntaxError( "Parameters name may not be \"arguments\" or \"eval\" in strict mode at ", state.Code, variableDef.Position, variableDef.Length); } } if (variableDef is VariableDefinition) { if ((variableDef as VariableDefinition)._variables.Length > 1) { ExceptionHelper.ThrowSyntaxError("Too many variables in for-in loop", state.Code, i); } } result._variable = variableDef; state.LabelsCount = 0; Tools.SkipSpaces(state.Code, ref i); result._source = Parser.Parse(state, ref i, CodeFragmentType.Expression); Tools.SkipSpaces(state.Code, ref i); if (state.Code[i] != ')') { ExceptionHelper.Throw(new SyntaxError("Expected \")\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))); } i++; state.AllowBreak.Push(true); state.AllowContinue.Push(true); result._body = Parser.Parse(state, ref i, 0); state.AllowBreak.Pop(); state.AllowContinue.Pop(); result.Position = index; result.Length = i - index; index = i; vars = CodeBlock.extractVariables(state, oldVariablesCount); } finally { state.lexicalScopeLevel--; } return(new CodeBlock(new[] { result }) { _variables = vars, Position = result.Position, Length = result.Length }); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; if (!Parser.Validate(state.Code, "with (", ref i) && !Parser.Validate(state.Code, "with(", ref i)) { return(null); } if (state.strict) { ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("WithStatement is not allowed in strict mode."))); } if (state.message != null) { state.message(MessageLevel.CriticalWarning, index, 4, "Do not use \"with\"."); } var obj = Parser.Parse(state, ref i, CodeFragmentType.Expression); while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != ')') { ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("Invalid syntax WithStatement."))); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); CodeNode body = null; VariableDescriptor[] vars = null; var oldVariablesCount = state.Variables.Count; state.lexicalScopeLevel++; var oldCodeContext = state.CodeContext; state.CodeContext |= CodeContext.InWith; try { body = Parser.Parse(state, ref i, 0); vars = CodeBlock.extractVariables(state, oldVariablesCount); body = new CodeBlock(new[] { body }) { _variables = vars, Position = body.Position, Length = body.Length }; } finally { state.lexicalScopeLevel--; state.CodeContext = oldCodeContext; } var pos = index; index = i; return(new With() { _scope = obj, _body = body, Position = pos, Length = index - pos }); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; if (!Parser.Validate(state.Code, "if (", ref i) && !Parser.Validate(state.Code, "if(", ref i)) { return(null); } while (Tools.IsWhiteSpace(state.Code[i])) { i++; } var condition = (Expression)ExpressionTree.Parse(state, ref i); while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != ')') { throw new ArgumentException("code (" + i + ")"); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); CodeNode body = Parser.Parse(state, ref i, 0); if (body is FunctionDefinition) { if (state.strict) { ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("In strict mode code, functions can only be declared at top level or immediately within another function."))); } if (state.message != null) { state.message(MessageLevel.CriticalWarning, body.Position, body.Length, "Do not declare function in nested blocks."); } body = new CodeBlock(new[] { body }); // для того, чтобы не дублировать код по декларации функции, // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию. } CodeNode elseBody = null; var pos = i; while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])) { i++; } if (i < state.Code.Length && !(body is CodeBlock) && (state.Code[i] == ';')) { do { i++; }while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])); } if (Parser.Validate(state.Code, "else", ref i)) { while (Tools.IsWhiteSpace(state.Code[i])) { i++; } elseBody = Parser.Parse(state, ref i, 0); if (elseBody is FunctionDefinition) { if (state.strict) { ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("In strict mode code, functions can only be declared at top level or immediately within another function."))); } if (state.message != null) { state.message(MessageLevel.CriticalWarning, elseBody.Position, elseBody.Length, "Do not declare function in nested blocks."); } elseBody = new CodeBlock(new[] { elseBody }); // для того, чтобы не дублировать код по декларации функции, // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию. } } else { i = pos; } pos = index; index = i; return(new IfElse() { then = body, condition = condition, @else = elseBody, Position = pos, Length = index - pos }); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; if (!Parser.Validate(state.Code, "switch (", ref i) && !Parser.Validate(state.Code, "switch(", ref i)) { return(null); } while (Tools.IsWhiteSpace(state.Code[i])) { i++; } var body = new List <CodeNode>(); var funcs = new List <FunctionDefinition>(); var cases = new List <SwitchCase>(); CodeNode result = null; cases.Add(new SwitchCase() { index = int.MaxValue }); state.AllowBreak.Push(true); var oldVariablesCount = state.Variables.Count; VariableDescriptor[] vars = null; state.lexicalScopeLevel++; try { var image = ExpressionTree.Parse(state, ref i); if (state.Code[i] != ')') { ExceptionHelper.Throw((new SyntaxError("Expected \")\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); if (state.Code[i] != '{') { ExceptionHelper.Throw((new SyntaxError("Expected \"{\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); while (state.Code[i] != '}') { do { if (Parser.Validate(state.Code, "case", i) && Parser.IsIdentifierTerminator(state.Code[i + 4])) { i += 4; while (Tools.IsWhiteSpace(state.Code[i])) { i++; } var sample = ExpressionTree.Parse(state, ref i); if (state.Code[i] != ':') { ExceptionHelper.Throw((new SyntaxError("Expected \":\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } i++; cases.Add(new SwitchCase() { index = body.Count, statement = sample }); } else if (Parser.Validate(state.Code, "default", i) && Parser.IsIdentifierTerminator(state.Code[i + 7])) { i += 7; while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (cases[0].index != int.MaxValue) { ExceptionHelper.Throw((new SyntaxError("Duplicate default case in switch at " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } if (state.Code[i] != ':') { ExceptionHelper.Throw((new SyntaxError("Expected \":\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } i++; cases[0].index = body.Count; } else { break; } while (Tools.IsWhiteSpace(state.Code[i]) || (state.Code[i] == ';')) { i++; } } while (true); if (cases.Count == 1 && cases[0].index == int.MaxValue) { ExceptionHelper.Throw((new SyntaxError("Switch statement must contain cases. " + CodeCoordinates.FromTextPosition(state.Code, index, 0)))); } var t = Parser.Parse(state, ref i, 0); if (t == null) { continue; } body.Add(t); while (Tools.IsWhiteSpace(state.Code[i]) || (state.Code[i] == ';')) { i++; } } state.AllowBreak.Pop(); i++; var pos = index; index = i; result = new Switch(body.ToArray()) { functions = funcs.ToArray(), cases = cases.ToArray(), image = image, Position = pos, Length = index - pos }; vars = CodeBlock.extractVariables(state, oldVariablesCount); } finally { state.lexicalScopeLevel--; } return(new CodeBlock(new[] { result }) { _variables = vars, Position = result.Position, Length = result.Length }); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; if (!Parser.Validate(state.Code, "if (", ref i) && !Parser.Validate(state.Code, "if(", ref i)) { return(null); } while (Tools.IsWhiteSpace(state.Code[i])) { i++; } var condition = (Expression)ExpressionTree.Parse(state, ref i); while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != ')') { throw new ArgumentException("code (" + i + ")"); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); var combinedBody = state.Code[i] == '{'; CodeNode body = Parser.Parse(state, ref i, 0); if (body is FunctionDefinition) { if (state.message != null) { state.message(MessageLevel.CriticalWarning, body.Position, body.Length, Strings.DoNotDeclareFunctionInNestedBlocks); } body = new CodeBlock(new[] { body }); // для того, чтобы не дублировать код по декларации функции, // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию. } CodeNode elseBody = null; var pos = i; while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])) { i++; } if (i < state.Code.Length && !combinedBody && state.Code[i] == ';') { do { i++; }while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])); } if (Parser.Validate(state.Code, "else", ref i)) { while (Tools.IsWhiteSpace(state.Code[i])) { i++; } elseBody = Parser.Parse(state, ref i, 0); if (elseBody is FunctionDefinition) { if (state.message != null) { state.message(MessageLevel.CriticalWarning, elseBody.Position, elseBody.Length, Strings.DoNotDeclareFunctionInNestedBlocks); } elseBody = new CodeBlock(new[] { elseBody }); // для того, чтобы не дублировать код по декларации функции, // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию. } } else { i = pos; } pos = index; index = i; return(new IfElse() { then = body, condition = condition, @else = elseBody, Position = pos, Length = index - pos }); }