public static CodeNode Parse(ParseInfo state, ref int position) { var i = position; if (!Parser.ValidateRegex(state.Code, ref i, false)) { return(null); } string value = state.Code.Substring(position, i - position); position = i; state.Code = Tools.removeComments(state.SourceCode, i); var s = value.LastIndexOf('/') + 1; string flags = value.Substring(s); try { return(new RegExpExpression(value.Substring(1, s - 2), flags)); // объекты должны быть каждый раз разные } catch (Exception e) { if (state.message != null) { state.message(MessageLevel.Error, CodeCoordinates.FromTextPosition(state.Code, i - value.Length, value.Length), string.Format(Strings.InvalidRegExp, value)); } return(new ExpressionWrapper(new Throw(e))); } }
internal static void ThrowUnknownToken(string code, int index) { var cord = CodeCoordinates.FromTextPosition(code, index, 0); Throw(new SyntaxError(string.Format( Strings.UnknowIdentifier, code.Substring(index, System.Math.Min(50, code.Length - index)).Split(Tools.TrimChars).FirstOrDefault(), cord))); }
public JSException(Error data, CodeNode exceptionMaker, string code) { Error = Context.CurrentGlobalContext.ProxyValue(data); ExceptionMaker = exceptionMaker; Code = code; if (code != null) { CodeCoordinates = CodeCoordinates.FromTextPosition(code, exceptionMaker.Position, exceptionMaker.Length); } }
public static CodeNode Parse(ParseInfo state, ref int index) { var i = index; if (!Parser.Validate(state.Code, "new", ref i) || !Parser.IsIdentifierTerminator(state.Code[i])) { return(null); } while (Tools.IsWhiteSpace(state.Code[i])) { i++; } var result = (Expression)ExpressionTree.Parse(state, ref i, true, false, true, true, false); if (result == null) { var cord = CodeCoordinates.FromTextPosition(state.Code, i, 0); ExceptionHelper.Throw((new SyntaxError("Invalid prefix operation. " + cord))); } if (result is Call) { result = new New(result as Call) { Position = index, Length = i - index } } ; else { if (state.message != null) { state.message(MessageLevel.Warning, index, 0, "Missed brackets in a constructor invocation."); } result = new Expressions.New(new Call(result, new Expression[0]) { Position = result.Position, Length = result.Length }) { Position = index, Length = i - index }; } index = i; return(result); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; if (!Parser.ValidateName(state.Code, ref i, state.strict)) { return(null); } int l = i; if (i >= state.Code.Length || (!Parser.Validate(state.Code, " :", ref i) && state.Code[i++] != ':')) { return(null); } var label = state.Code.Substring(index, l - index); state.Labels.Add(label); int oldlc = state.LabelsCount; state.LabelsCount++; var stat = Parser.Parse(state, ref i, 0); state.Labels.Remove(label); state.LabelsCount = oldlc; if (stat is FunctionDefinition) { if (state.message != null) { state.message(MessageLevel.CriticalWarning, CodeCoordinates.FromTextPosition(state.Code, stat.Position, stat.Length), "Labeled function. Are you sure?"); } } var pos = index; index = i; return(new LabeledStatement() { statement = stat, label = label, Position = pos, Length = index - pos }); }
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, CodeCoordinates.FromTextPosition(state.Code, 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; 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 ForOf() { _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, "of", 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-of 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) { string code = state.Code; int i = index; if (!Parser.Validate(code, "class", ref i)) { return(null); } while (Tools.IsWhiteSpace(code[i])) { i++; } string name = null; Expression baseType = null; if (!Parser.Validate(code, "extends ", i)) { var n = i; if (Parser.ValidateName(code, ref i, true)) { name = code.Substring(n, i - n); } while (Tools.IsWhiteSpace(code[i])) { i++; } } if (Parser.Validate(code, "extends ", ref i)) { var n = i; if (!Parser.ValidateName(code, ref i, true) && !Parser.Validate(code, "null", ref i)) { ExceptionHelper.ThrowSyntaxError("Invalid base class name", state.Code, i); } var baseClassName = code.Substring(n, i - n); if (baseClassName == "null") { baseType = new Constant(JSValue.@null); } else { baseType = new Variable(baseClassName, 1); } baseType.Position = n; baseType.Length = i - n; while (Tools.IsWhiteSpace(code[i])) { i++; } } if (code[i] != '{') { ExceptionHelper.ThrowSyntaxError(Messages.UnexpectedToken, code, i); } FunctionDefinition ctor = null; ClassDefinition result = null; var oldStrict = state.Strict; state.Strict = true; var flds = new Dictionary <string, MemberDescriptor>(); var computedProperties = new List <MemberDescriptor>(); var oldCodeContext = state.CodeContext; state.CodeContext |= CodeContext.InExpression; try { while (code[i] != '}') { do { i++; }while (Tools.IsWhiteSpace(code[i]) || code[i] == ';'); int s = i; if (state.Code[i] == '}') { break; } bool @static = Parser.Validate(state.Code, "static", ref i); if (@static) { Tools.SkipSpaces(state.Code, ref i); s = i; } bool getOrSet = Parser.Validate(state.Code, "get", ref i) || Parser.Validate(state.Code, "set", ref i); if (getOrSet) { Tools.SkipSpaces(state.Code, ref i); } var asterisk = state.Code[i] == '*'; if (asterisk) { do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); } if (Parser.Validate(state.Code, "[", ref i)) { var propertyName = ExpressionTree.Parse(state, ref i, false, false, false, true, false); while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != ']') { ExceptionHelper.ThrowSyntaxError("Expected ']'", state.Code, i); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); var initializer = state.Code[i] == '(' ? FunctionDefinition.Parse(state, ref i, asterisk ? FunctionKind.AnonymousGenerator : FunctionKind.AnonymousFunction) : ExpressionTree.Parse(state, ref i); switch (state.Code[s]) { case 'g': { computedProperties.Add(new MemberDescriptor(propertyName, new PropertyPair((Expression)initializer, null), @static)); break; } case 's': { computedProperties.Add(new MemberDescriptor(propertyName, new PropertyPair(null, (Expression)initializer), @static)); break; } default: { computedProperties.Add(new MemberDescriptor(propertyName, (Expression)initializer, @static)); break; } } } else if (getOrSet) { i = s; var mode = state.Code[i] == 's' ? FunctionKind.Setter : FunctionKind.Getter; var propertyAccessor = FunctionDefinition.Parse(state, ref i, mode) as FunctionDefinition; var accessorName = (@static ? "static " : "") + propertyAccessor.Name; if (!flds.ContainsKey(accessorName)) { var propertyPair = new PropertyPair ( mode == FunctionKind.Getter ? propertyAccessor : null, mode == FunctionKind.Setter ? propertyAccessor : null ); flds.Add(accessorName, new MemberDescriptor(new Constant(propertyAccessor.Name), propertyPair, @static)); } else { var vle = flds[accessorName].Value as PropertyPair; if (vle == null) { ExceptionHelper.Throw((new SyntaxError("Try to define " + mode.ToString().ToLowerInvariant() + " for defined field at " + CodeCoordinates.FromTextPosition(state.Code, s, 0)))); } do { if (mode == FunctionKind.Getter) { if (vle.Getter == null) { vle.Getter = propertyAccessor; break; } } else { if (vle.Setter == null) { vle.Setter = propertyAccessor; break; } } ExceptionHelper.ThrowSyntaxError("Try to redefine " + mode.ToString().ToLowerInvariant() + " of " + propertyAccessor.Name, state.Code, s); }while (false); } } else { i = s; string fieldName = null; if (state.Code[i] == '*') { do { i++; }while (Tools.IsWhiteSpace(code[i])); } if (Parser.ValidateName(state.Code, ref i, false, true, state.Strict)) { fieldName = Tools.Unescape(state.Code.Substring(s, i - s), state.Strict); } else if (Parser.ValidateValue(state.Code, ref i)) { double d = 0.0; int n = s; if (Tools.ParseNumber(state.Code, ref n, out d)) { fieldName = Tools.DoubleToString(d); } else if (state.Code[s] == '\'' || state.Code[s] == '"') { fieldName = Tools.Unescape(state.Code.Substring(s + 1, i - s - 2), state.Strict); } } if (fieldName == null) { ExceptionHelper.Throw((new SyntaxError("Invalid member name at " + CodeCoordinates.FromTextPosition(state.Code, s, i - s)))); } if (fieldName == "constructor") { if (@static) { ExceptionHelper.ThrowSyntaxError(Messages.ConstructorCannotBeStatic, state.Code, s); } if (ctor != null) { ExceptionHelper.ThrowSyntaxError("Trying to redefinition constructor", state.Code, s); } state.CodeContext |= CodeContext.InClassConstructor; } else if (@static) { fieldName = "static " + fieldName; state.CodeContext |= CodeContext.InStaticMember; } if (flds.ContainsKey(fieldName)) { ExceptionHelper.Throw(new SyntaxError("Trying to redefinition member \"" + fieldName + "\" at " + CodeCoordinates.FromTextPosition(state.Code, s, i - s))); } state.CodeContext |= CodeContext.InClassDefenition; state.CodeContext &= ~CodeContext.InGenerator; i = s; var method = FunctionDefinition.Parse(state, ref i, FunctionKind.Method) as FunctionDefinition; if (method == null) { ExceptionHelper.ThrowSyntaxError("Unable to parse constructor", state.Code, i); } if (fieldName == "constructor") { ctor = method; } else { flds[fieldName] = new MemberDescriptor(new Constant(method.Name), method, @static); } } code = state.Code; } if (ctor == null) { string ctorCode; int ctorIndex = 0; if (baseType != null && !(baseType is Constant)) { ctorCode = "constructor(...args) { super(...args); }"; } else { ctorCode = "constructor(...args) { }"; } ctor = (FunctionDefinition)FunctionDefinition.Parse( new ParseInfo(ctorCode, ctorCode, null) { Strict = true, CodeContext = CodeContext.InClassConstructor | CodeContext.InClassDefenition }, ref ctorIndex, FunctionKind.Method); } result = new ClassDefinition(name, baseType, new List <MemberDescriptor>(flds.Values).ToArray(), ctor, computedProperties.ToArray()); if ((oldCodeContext & CodeContext.InExpression) == 0) { if (string.IsNullOrEmpty(name)) { ExceptionHelper.ThrowSyntaxError("Class must have name", state.Code, index); } if (state.Strict && state.FunctionScopeLevel != state.LexicalScopeLevel) { ExceptionHelper.ThrowSyntaxError("In strict mode code, class can only be declared at top level or immediately within other function.", state.Code, index); } state.Variables.Add(result.Reference._descriptor); } } finally { state.CodeContext = oldCodeContext; state.Strict = oldStrict; } index = i + 1; return(result); }
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, 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, "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, CodeCoordinates.FromTextPosition(state.Code, 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, CodeCoordinates.FromTextPosition(state.Code, 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, "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 }); }
internal static void ThrowVariableIsNotDefined(string variableName, string code, int position, int length, CodeNode exceptionMaker) { var cord = CodeCoordinates.FromTextPosition(code, position, 0); Throw(new ReferenceError(string.Format(Strings.VariableNotDefined, variableName)), exceptionMaker, code); }
public static CodeNode Parse(ParseInfo state, ref int position) { if (!Parser.Validate(state.Code, "using", ref position)) { return(null); } while (char.IsWhiteSpace(state.Code, position)) { position++; } int start = position; while (Parser.ValidateName(state.Code, ref position) && state.Code[position] == '.') { position++; } if (state.Code[position] != ' ') { throw new JSException(new SyntaxError("Unexpected char at " + CodeCoordinates.FromTextPosition(state.Code, position, 0))); } var namespaceName = state.Code.Substring(start, position - start); while (char.IsWhiteSpace(state.Code, position)) { position++; } if (!Parser.Validate(state.Code, "as", ref position)) { throw new JSException(new SyntaxError("Expected \"as\" at " + CodeCoordinates.FromTextPosition(state.Code, position, 2))); } while (char.IsWhiteSpace(state.Code, position)) { position++; } start = position; if (!Parser.ValidateName(state.Code, ref position)) { throw new JSException(new SyntaxError("Expected identifier name at " + CodeCoordinates.FromTextPosition(state.Code, position, 0))); } var aliasName = state.Code.Substring(start, position - start); while (char.IsWhiteSpace(state.Code, position)) { position++; } if (state.Code[position] != ';') { throw new JSException(new SyntaxError("Expected \";\" at " + CodeCoordinates.FromTextPosition(state.Code, position, 1))); } return(new UsingStatement(namespaceName, aliasName)); }
internal static CodeNode Parse(ParseInfo state, ref int index) { if (state.Code[index] != '{') { throw new ArgumentException("Invalid JSON definition"); } var flds = new Dictionary <string, Expression>(); var computedProperties = new List <KeyValuePair <Expression, Expression> >(); int i = index; while (state.Code[i] != '}') { i++; Tools.SkipSpaces(state.Code, ref i); int s = i; if (state.Code[i] == '}') { break; } bool getOrSet = Parser.Validate(state.Code, "get", ref i) || Parser.Validate(state.Code, "set", ref i); Tools.SkipSpaces(state.Code, ref i); if (getOrSet && state.Code[i] == '(') // function with name 'get' or 'set' { getOrSet = false; i = s; } var asterisk = state.Code[i] == '*'; Tools.SkipSpaces(state.Code, ref i); if (Parser.Validate(state.Code, "[", ref i)) { var name = ExpressionTree.Parse(state, ref i, false, false, false, true, false); while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != ']') { ExceptionHelper.ThrowSyntaxError("Expected ']'", state.Code, i); } do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); Tools.SkipSpaces(state.Code, ref i); if (state.Code[s] != 'g' && state.Code[s] != 's') { if (!Parser.Validate(state.Code, ":", ref i)) { ExceptionHelper.ThrowSyntaxError(Messages.UnexpectedToken, state.Code, i); } Tools.SkipSpaces(state.Code, ref i); } CodeNode initializer; initializer = state.Code[i] == '(' ? FunctionDefinition.Parse(state, ref i, asterisk ? FunctionKind.AnonymousGenerator : FunctionKind.AnonymousFunction) : ExpressionTree.Parse(state, ref i); switch (state.Code[s]) { case 'g': { computedProperties.Add(new KeyValuePair <Expression, Expression>(name, new PropertyPair((Expression)initializer, null))); break; } case 's': { computedProperties.Add(new KeyValuePair <Expression, Expression>(name, new PropertyPair(null, (Expression)initializer))); break; } default: { computedProperties.Add(new KeyValuePair <Expression, Expression>(name, (Expression)initializer)); break; } } } else if (getOrSet && state.Code[i] != ':') { i = s; var mode = state.Code[i] == 's' ? FunctionKind.Setter : FunctionKind.Getter; var propertyAccessor = FunctionDefinition.Parse(state, ref i, mode) as FunctionDefinition; var accessorName = propertyAccessor.Name; if (!flds.ContainsKey(accessorName)) { var propertyPair = new PropertyPair ( mode == FunctionKind.Getter ? propertyAccessor : null, mode == FunctionKind.Setter ? propertyAccessor : null ); flds.Add(accessorName, propertyPair); } else { var vle = flds[accessorName] as PropertyPair; if (vle == null) { ExceptionHelper.ThrowSyntaxError("Try to define " + mode.ToString().ToLowerInvariant() + " for defined field", state.Code, s); } do { if (mode == FunctionKind.Getter) { if (vle.Getter == null) { vle.Getter = propertyAccessor; break; } } else { if (vle.Setter == null) { vle.Setter = propertyAccessor; break; } } ExceptionHelper.ThrowSyntaxError("Try to redefine " + mode.ToString().ToLowerInvariant() + " of " + propertyAccessor.Name, state.Code, s); }while (false); } } else { if (asterisk) { do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); } i = s; var fieldName = ""; if (Parser.ValidateName(state.Code, ref i, false, true, state.Strict)) { fieldName = Tools.Unescape(state.Code.Substring(s, i - s), state.Strict); } else if (Parser.ValidateValue(state.Code, ref i)) { if (state.Code[s] == '-') { ExceptionHelper.Throw(new SyntaxError("Invalid char \"-\" at " + CodeCoordinates.FromTextPosition(state.Code, s, 1))); } double d = 0.0; int n = s; if (Tools.ParseNumber(state.Code, ref n, out d)) { fieldName = Tools.DoubleToString(d); } else if (state.Code[s] == '\'' || state.Code[s] == '"') { fieldName = Tools.Unescape(state.Code.Substring(s + 1, i - s - 2), state.Strict); } else if (flds.Count != 0) { ExceptionHelper.Throw((new SyntaxError("Invalid field name at " + CodeCoordinates.FromTextPosition(state.Code, s, i - s)))); } else { return(null); } } else { return(null); } while (Tools.IsWhiteSpace(state.Code[i])) { i++; } Expression initializer = null; if (state.Code[i] == '(') { i = s; initializer = FunctionDefinition.Parse(state, ref i, asterisk ? FunctionKind.MethodGenerator : FunctionKind.Method); } else { if (asterisk) { ExceptionHelper.ThrowSyntaxError("Unexpected token", state.Code, i); } if (state.Code[i] != ':' && state.Code[i] != ',' && state.Code[i] != '}') { ExceptionHelper.ThrowSyntaxError("Expected ',', ';' or '}'", state.Code, i); } Expression aei = null; if (flds.TryGetValue(fieldName, out aei)) { if (state.Strict ? (!(aei is Constant) || (aei as Constant).value != JSValue.undefined) : aei is PropertyPair) { ExceptionHelper.ThrowSyntaxError("Try to redefine field \"" + fieldName + "\"", state.Code, s, i - s); } state.Message?.Invoke(MessageLevel.Warning, i, 0, "Duplicate key \"" + fieldName + "\""); } if (state.Code[i] == ',' || state.Code[i] == '}') { if (!Parser.ValidateName(fieldName, 0)) { ExceptionHelper.ThrowSyntaxError("Invalid variable name", state.Code, i); } initializer = new Variable(fieldName, state.LexicalScopeLevel); } else { do { i++; }while (Tools.IsWhiteSpace(state.Code[i])); initializer = ExpressionTree.Parse(state, ref i, false, false); } } flds[fieldName] = initializer; } while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if ((state.Code[i] != ',') && (state.Code[i] != '}')) { return(null); } } i++; var pos = index; index = i; return(new ObjectDefinition(flds, computedProperties.ToArray()) { Position = pos, Length = index - pos }); }
public static Script Parse(string code, CompilerMessageCallback messageCallback = null, Options options = Options.None) { if (code == null) { throw new ArgumentNullException(); } if (code == "") { return(new Script { Root = new CodeBlock(new CodeNode[0]), Code = "" }); } var internalCallback = messageCallback != null ? (level, position, length, message) => messageCallback(level, CodeCoordinates.FromTextPosition(code, position, length), message) : null as InternalCompilerMessageCallback; int i = 0; var root = (CodeBlock)CodeBlock.Parse(new ParseInfo(Parser.RemoveComments(code, 0), code, internalCallback), ref i); var stat = new FunctionInfo(); Parser.Build(ref root, 0, new Dictionary <string, VariableDescriptor>(), CodeContext.None, internalCallback, stat, options); var body = root as CodeBlock; body._suppressScopeIsolation = SuppressScopeIsolationMode.Suppress; for (var vi = 0; vi < body._variables.Length; vi++) { body._variables[vi].captured = true; } var tv = stat.WithLexicalEnvironment ? null : new Dictionary <string, VariableDescriptor>(); body.RebuildScope(stat, tv, body._variables.Length == 0 || !stat.WithLexicalEnvironment ? 1 : 0); var bd = body as CodeNode; body.Optimize(ref bd, null, internalCallback, options, stat); if (tv != null) { body._variables = new List <VariableDescriptor>(tv.Values).ToArray(); } if (stat.NeedDecompose) { body.Decompose(ref bd); } return(new Script() { Code = code, Root = root }); }
internal static void ThrowReferenceError(string message, string code, int position, int length) { var cord = CodeCoordinates.FromTextPosition(code, position, 0); Throw(new ReferenceError(message + " " + cord)); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (!Parser.Validate(state.Code, "do", ref i) || !Parser.IsIdentifierTerminator(state.Code[i])) { return(null); } int labelsCount = state.LabelsCount; state.LabelsCount = 0; while (Tools.IsWhiteSpace(state.Code[i])) { i++; } state.AllowBreak.Push(true); state.AllowContinue.Push(true); int ccs = state.continiesCount; int cbs = state.breaksCount; var 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 }); // для того, чтобы не дублировать код по декларации функции, // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию. } state.AllowBreak.Pop(); state.AllowContinue.Pop(); if (!(body is CodeBlock) && state.Code[i] == ';') { i++; } while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])) { i++; } if (i >= state.Code.Length) { ExceptionHelper.ThrowSyntaxError(Strings.UnexpectedEndOfSource); } if (!Parser.Validate(state.Code, "while", ref i)) { ExceptionHelper.Throw((new SyntaxError("Expected \"while\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } while (Tools.IsWhiteSpace(state.Code[i])) { 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])); var condition = Parser.Parse(state, ref i, CodeFragmentType.Expression); while (Tools.IsWhiteSpace(state.Code[i])) { i++; } if (state.Code[i] != ')') { ExceptionHelper.Throw((new SyntaxError("Expected \")\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0)))); } i++; var pos = index; index = i; return(new DoWhile() { allowRemove = ccs == state.continiesCount && cbs == state.breaksCount, body = body, condition = condition, labels = state.Labels.GetRange(state.Labels.Count - labelsCount, labelsCount).ToArray(), 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 position = index; bool sroot = position == 0 && state.AllowDirectives; if (!sroot) { if (state.Code[position] != '{') { throw new ArgumentException("code (" + position + ")"); } position++; } Tools.SkipSpaces(state.Code, ref position); var body = new List <CodeNode>(); bool strictSwitch = false; bool allowDirectives = state.AllowDirectives; HashSet <string> directives = null; state.AllowDirectives = false; var oldFunctionScopeLevel = state.functionScopeLevel; state.lexicalScopeLevel++; if (allowDirectives) { state.functionScopeLevel = state.lexicalScopeLevel; } var oldVariablesCount = state.Variables.Count; VariableDescriptor[] variables = null; state.LabelsCount = 0; try { if (allowDirectives) { int start = position; do { var s = position; if (position >= state.Code.Length) { break; } if (Parser.ValidateValue(state.Code, ref position)) { while (position < state.Code.Length && Tools.IsWhiteSpace(state.Code[position])) { position++; } if (position < state.Code.Length && (Parser.IsOperator(state.Code[position]) || Parser.Validate(state.Code, "instanceof", position) || Parser.Validate(state.Code, "in", position))) { position = s; break; } var t = s; if (Parser.ValidateString(state.Code, ref t, true)) { var str = state.Code.Substring(s + 1, t - s - 2); if (!strictSwitch && str == "use strict" && !state.strict) { state.strict = true; strictSwitch = true; } if (directives == null) { directives = new HashSet <string>(); } directives.Add(str); } else { position = s; break; } } else if (state.Code[position] == ';') { if (directives == null) { break; } do { position++; }while (position < state.Code.Length && Tools.IsWhiteSpace(state.Code[position])); } else { break; } }while (true); position = start; } for (var j = body.Count; j-- > 0;) { (body[j] as Constant).value._oValue = Tools.Unescape((body[j] as Constant).value._oValue.ToString(), state.strict); } bool expectSemicolon = false; while ((sroot && position < state.Code.Length) || (!sroot && state.Code[position] != '}')) { var t = Parser.Parse(state, ref position, 0); if (t == null) { if (position < state.Code.Length) { if (sroot && state.Code[position] == '}') { ExceptionHelper.Throw(new SyntaxError("Unexpected symbol \"}\" at " + CodeCoordinates.FromTextPosition(state.Code, position, 0))); } if ((state.Code[position] == ';' || state.Code[position] == ',')) { if (state.message != null && !expectSemicolon) { state.message(MessageLevel.Warning, position, 1, "Unnecessary semicolon."); } position++; } expectSemicolon = false; } continue; } expectSemicolon = !(t is EntityDefinition); body.Add(t); } } finally { if (oldVariablesCount != state.Variables.Count) { variables = extractVariables(state, oldVariablesCount); } state.functionScopeLevel = oldFunctionScopeLevel; state.lexicalScopeLevel--; } if (!sroot) { position++; } int startPos = index; index = position; return(new CodeBlock(body.ToArray()) { _strict = (state.strict ^= strictSwitch) || strictSwitch, _variables = variables ?? emptyVariables, Position = startPos, code = state.SourceCode, Length = position - startPos, #if DEBUG directives = directives #endif }); }
internal static CodeNode Parse(ParseInfo state, ref int index) { int i = index; if (!Parser.Validate(state.Code, "throw", ref i) || (!Parser.IsIdentifierTerminator(state.Code[i]))) { return(null); } while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]) && !Tools.IsLineTerminator(state.Code[i])) { i++; } var b = state.Code[i] == ';' || Tools.IsLineTerminator(state.Code[i]) ? null : (Expression)Parser.Parse(state, ref i, CodeFragmentType.Expression); if (b is Empty) { ExceptionHelper.Throw((new SyntaxError("Can't throw result of EmptyStatement " + CodeCoordinates.FromTextPosition(state.Code, i - 1, 0)))); } var pos = index; index = i; return(new Throw(b) { Position = pos, Length = index - pos }); }
/// <summary> /// Initializes a new Module with specified code, callback for output compiler messages and compiler options. /// </summary> /// <param name="path">Path to file with script. Used for resolving paths to other modules for importing via import directive. Can be null or empty</param> /// <param name="code">JavaScript code.</param> /// <param name="messageCallback">Callback used to output compiler messages or null</param> /// <param name="options">Compiler options</param> public Module(string path, string code, CompilerMessageCallback messageCallback, Options options) { if (code == null) { throw new ArgumentNullException(); } Code = code; Context = new Context(Context.CurrentGlobalContext, true, null); Context._module = this; if (!string.IsNullOrWhiteSpace(path)) { lock (_modulesCache) { if (!_modulesCache.ContainsKey(path)) { _modulesCache[path] = this; } } FilePath = path; } if (code == "") { return; } var internalCallback = messageCallback != null ? (level, position, length, message) => messageCallback(level, CodeCoordinates.FromTextPosition(code, position, length), message) : null as InternalCompilerMessageCallback; int i = 0; _root = (CodeBlock)CodeBlock.Parse(new ParseInfo(Parser.RemoveComments(code, 0), Code, internalCallback), ref i); var stat = new FunctionInfo(); Parser.Build(ref _root, 0, new Dictionary <string, VariableDescriptor>(), CodeContext.None, internalCallback, stat, options); var body = _root as CodeBlock; body._suppressScopeIsolation = SuppressScopeIsolationMode.Suppress; Context._thisBind = new GlobalObject(Context); Context._strict = body._strict; var tv = stat.WithLexicalEnvironment ? null : new Dictionary <string, VariableDescriptor>(); body.RebuildScope(stat, tv, body._variables.Length == 0 || !stat.WithLexicalEnvironment ? 1 : 0); var bd = body as CodeNode; body.Optimize(ref bd, null, internalCallback, options, stat); if (tv != null) { body._variables = new List <VariableDescriptor>(tv.Values).ToArray(); } if (stat.NeedDecompose) { body.Decompose(ref bd); } }
internal static CodeNode Parse(ParseInfo state, ref int index, bool forForLoop) { int position = index; Tools.SkipSpaces(state.Code, ref position); VariableKind mode; if (Parser.Validate(state.Code, "var ", ref position)) { mode = VariableKind.FunctionScope; } else if (Parser.Validate(state.Code, "let ", ref position)) { mode = VariableKind.LexicalScope; } else if (Parser.Validate(state.Code, "const ", ref position)) { mode = VariableKind.ConstantInLexicalScope; } else { return(null); } var level = mode <= VariableKind.FunctionScope ? state.FunctionScopeLevel : state.LexicalScopeLevel; var initializers = new List <Expression>(); var names = new List <string>(); int s = position; while ((state.Code[position] != ';') && (state.Code[position] != '}') && !Tools.IsLineTerminator(state.Code[position])) { Tools.SkipSpaces(state.Code, ref position); if (state.Code[position] != '[' && state.Code[position] != '{' && !Parser.ValidateName(state.Code, position, state.Strict)) { if (Parser.ValidateName(state.Code, ref position, false, true, state.Strict)) { ExceptionHelper.ThrowSyntaxError('\"' + Tools.Unescape(state.Code.Substring(s, position - s), state.Strict) + "\" is a reserved word, but used as a variable. " + CodeCoordinates.FromTextPosition(state.Code, s, position - s)); } ExceptionHelper.ThrowSyntaxError("Invalid variable definition at " + CodeCoordinates.FromTextPosition(state.Code, s, position - s)); } var expression = ExpressionTree.Parse(state, ref position, processComma: false, forForLoop: forForLoop); if (expression is VariableReference) { var name = expression.ToString(); if (state.Strict) { if (name == "arguments" || name == "eval") { ExceptionHelper.ThrowSyntaxError("Varible name cannot be \"arguments\" or \"eval\" in strict mode", state.Code, s, position - s); } } names.Add(name); initializers.Add(expression); } else { var valid = false; var expr = expression as ExpressionTree; if (expr != null) { if (expr.Type == OperationType.None && expr._right == null) { expr = expr._left as ExpressionTree; } valid |= expr != null && expr.Type == OperationType.Assignment; if (valid) { if (expr._left is ObjectDesctructor) { var expressions = (expr._left as ObjectDesctructor).GetTargetVariables(); for (var i = 0; i < expressions.Count; i++) { names.Add(expressions[i].ToString()); initializers.Add(expressions[i]); } initializers.Add(expr); } else { names.Add(expr._left.ToString()); initializers.Add(expression); } } } else { var cnst = expression as Constant; valid = cnst != null && cnst.value == JSValue.undefined; if (valid) { initializers.Add(expression); names.Add(cnst.value.ToString()); } } if (!valid) { ExceptionHelper.ThrowSyntaxError("Invalid variable initializer", state.Code, position); } } s = position; if (position >= state.Code.Length) { break; } Tools.SkipSpaces(state.Code, ref s); if (s >= state.Code.Length) { break; } if (state.Code[s] == ',') { position = s + 1; Tools.SkipSpaces(state.Code, ref position); } else { break; } } if (names.Count == 0) { throw new InvalidOperationException("code (" + position + ")"); } if (!forForLoop && position < state.Code.Length && state.Code[position] == ';') { position++; } else { position = s; } var variables = new VariableDescriptor[names.Count]; for (int i = 0, skiped = 0; i < names.Count; i++) { bool skip = false; for (var j = 0; j < state.Variables.Count - i + skiped; j++) { if (state.Variables[j].name == names[i] && state.Variables[j].definitionScopeLevel >= level) { if (state.Variables[j].lexicalScope || mode > VariableKind.FunctionScope) { ExceptionHelper.ThrowSyntaxError(string.Format(Strings.IdentifierAlreadyDeclared, names[i]), state.Code, index); } skip = true; variables[i] = state.Variables[j]; skiped++; break; } } if (skip) { continue; } variables[i] = new VariableDescriptor(names[i], level) { lexicalScope = mode > VariableKind.FunctionScope, isReadOnly = mode == VariableKind.ConstantInLexicalScope }; state.Variables.Add(variables[i]); } var pos = index; index = position; return(new VariableDefinition(variables, initializers.ToArray(), mode) { Position = pos, Length = index - pos }); }
/// <summary> /// Evaluate script /// </summary> /// <param name="code">Code in JavaScript</param> /// <param name="suppressScopeCreation">If true, scope will not be created. All variables, which will be defined via let, const or class will not be destructed after evalution</param> /// <returns>Result of last evaluated operation</returns> public JSValue Eval(string code, JSValue thisBind, bool suppressScopeCreation = false) { if (_parent == null) { throw new InvalidOperationException("Cannot execute script in global context"); } if (string.IsNullOrEmpty(code)) { return(JSValue.undefined); } // чистить кэш тут не достаточно. // Мы не знаем, где объявлена одноимённая переменная // и в тех случаях, когда она пришла из функции выше // или даже глобального контекста, её кэш может быть // не сброшен вовремя и значение будет браться из контекста // eval'а, а не того контекста, в котором её позовут. /* * function a(){ * var c = 1; * function b(){ * eval("var c = 2"); * // переменная объявлена в контексте b, значит и значение должно быть из * // контекста b, но если по выходу из b кэш этой переменной сброшен не будет, * // то в a её значение будет 2 * } * } */ var mainFunctionContext = this; var stack = GetCurrectContextStack(); while (stack != null && stack.Count > 1 && stack[stack.Count - 2] == mainFunctionContext._parent && stack[stack.Count - 2]._owner == mainFunctionContext._owner) { mainFunctionContext = mainFunctionContext._parent; } int index = 0; string c = Parser.RemoveComments(code, 0); var ps = new ParseInfo(c, code, null) { strict = _strict, AllowDirectives = true, CodeContext = CodeContext.InEval }; var body = CodeBlock.Parse(ps, ref index) as CodeBlock; if (index < c.Length) { throw new ArgumentException("Invalid char"); } var variables = new Dictionary <string, VariableDescriptor>(); var stats = new FunctionInfo(); CodeNode cb = body; Parser.Build(ref cb, 0, variables, (_strict ? CodeContext.Strict : CodeContext.None) | CodeContext.InEval, null, stats, Options.None); var tv = stats.WithLexicalEnvironment ? null : new Dictionary <string, VariableDescriptor>(); body.RebuildScope(stats, tv, body._variables.Length == 0 || !stats.WithLexicalEnvironment ? 1 : 0); if (tv != null) { var newVarDescs = new VariableDescriptor[tv.Values.Count]; tv.Values.CopyTo(newVarDescs, 0); body._variables = newVarDescs; body._suppressScopeIsolation = SuppressScopeIsolationMode.DoNotSuppress; } body.Optimize(ref cb, null, null, Options.SuppressUselessExpressionsElimination | Options.SuppressConstantPropogation, stats); body = cb as CodeBlock ?? body; if (stats.NeedDecompose) { body.Decompose(ref cb); } body._suppressScopeIsolation = SuppressScopeIsolationMode.Suppress; var debugging = _debugging; _debugging = false; var runned = this.Activate(); try { var context = suppressScopeCreation || (!stats.WithLexicalEnvironment && !body._strict && !_strict) ? this : new Context(this, false, _owner) { _strict = _strict || body._strict }; if (suppressScopeCreation || (!_strict && !body._strict)) { for (var i = 0; i < body._variables.Length; i++) { if (!body._variables[i].lexicalScope) { JSValue variable; var cc = mainFunctionContext; while (cc._parent._parent != null && (cc._variables == null || !cc._variables.TryGetValue(body._variables[i].name, out variable))) { cc = cc._parent; } if (cc._definedVariables != null) { for (var j = 0; j < cc._definedVariables.Length; j++) { if (cc._definedVariables[j].name == body._variables[i].name) { cc._definedVariables[j].definitionScopeLevel = -1; } } } variable = mainFunctionContext.DefineVariable(body._variables[i].name, !suppressScopeCreation); if (body._variables[i].initializer != null) { variable.Assign(body._variables[i].initializer.Evaluate(context)); } // блокирует создание переменной в конктексте eval body._variables[i].lexicalScope = true; // блокирует кеширование body._variables[i].definitionScopeLevel = -1; } } } if (body._lines.Length == 0) { return(JSValue.undefined); } var oldThisBind = ThisBind; var runContextOfEval = context.Activate(); context._thisBind = thisBind; try { return(body.Evaluate(context) ?? context._lastResult ?? JSValue.notExists); } catch (JSException e) { if ((e.Code == null || e.CodeCoordinates == null) && e.ExceptionMaker != null) { e.Code = code; e.CodeCoordinates = CodeCoordinates.FromTextPosition(code, e.ExceptionMaker.Position, e.ExceptionMaker.Length); } throw; } finally { context._thisBind = oldThisBind; if (runContextOfEval) { context.Deactivate(); } } } finally { if (runned) { this.Deactivate(); } this._debugging = debugging; } }
internal static CodeNode Parse(ParseInfo state, ref int index) { //string code = state.Code; int i = index; if (!Parser.Validate(state.Code, "while (", ref i) && !Parser.Validate(state.Code, "while(", ref i)) { return(null); } int labelsCount = state.LabelsCount; state.LabelsCount = 0; while (Tools.IsWhiteSpace(state.Code[i])) { i++; } var condition = Parser.Parse(state, ref i, CodeFragmentType.Expression); while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])) { i++; } if (i >= state.Code.Length) { ExceptionHelper.Throw(new SyntaxError("Unexpected end of line.")); } if (state.Code[i] != ')') { throw new ArgumentException("code (" + i + ")"); } do { i++; }while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i])); if (i >= state.Code.Length) { ExceptionHelper.Throw(new SyntaxError("Unexpected end of line.")); } state.AllowBreak.Push(true); state.AllowContinue.Push(true); int ccs = state.continiesCount; int cbs = state.breaksCount; var 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, CodeCoordinates.FromTextPosition(state.Code, body.Position, body.Length), "Do not declare function in nested blocks."); } body = new CodeBlock(new[] { body }); // для того, чтобы не дублировать код по декларации функции, // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию. } state.AllowBreak.Pop(); state.AllowContinue.Pop(); var pos = index; index = i; return(new While() { allowRemove = ccs == state.continiesCount && cbs == state.breaksCount, body = body, condition = condition, labels = state.Labels.GetRange(state.Labels.Count - labelsCount, labelsCount).ToArray(), Position = pos, Length = index - pos }); }