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) ?? 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 : 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 : 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); } state.Message?.Invoke(MessageLevel.Warning, 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, "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 }); }
public override bool Build(ref CodeNode _this, int expressionDepth, Dictionary <string, VariableDescriptor> variables, CodeContext codeContext, InternalCompilerMessageCallback 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, Position, Length, "Last expression of for-loop was removed. Maybe, it's a mistake."); } } Parser.Build(ref _body, 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]; 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(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 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); }