private void assignValues(JSValue source, ArrayDefinition targetMap) { if (targetMap == null) { return; } var values = new JSValue[targetMap.Elements.Length]; for (var i = 0; i < targetMap.Elements.Length; i++) { values[i] = source[Tools.Int32ToString(i)].CloneImpl(false); } Arguments setterArgs = null; for (var i = 0; i < targetMap.Elements.Length; i++) { if (targetMap.Elements[i] is ObjectDefinition) { assignValues(values[i], targetMap.Elements[i] as ObjectDefinition); assignValues(values[i], targetMap.Elements[i] as ArrayDefinition); } else { var target = targetMap.Elements[i].EvaluateForWrite(_context); setterArgs = assign(target, values[i], setterArgs); } } }
private static void collectTargetVariables(ArrayDefinition arrayDefinition, List <Variable> result) { if (arrayDefinition == null) { return; } for (var i = 0; i < arrayDefinition.Elements.Length; i++) { if (arrayDefinition.Elements[i] is Variable) { result.Add((Variable)arrayDefinition.Elements[i]); } else { collectTargetVariables(arrayDefinition.Elements[i] as ObjectDefinition, result); collectTargetVariables(arrayDefinition.Elements[i] as ArrayDefinition, result); } } }
public static bool CheckObjectDefinition(ArrayDefinition arrayDefinition, bool @throw) { if (arrayDefinition == null) { return(true); } for (var i = 0; i < arrayDefinition.Elements.Length; i++) { if (!ExpressionTree.canBeAssignee(arrayDefinition.Elements[i])) { if (@throw) { ExceptionHelper.ThrowReferenceError(Strings.InvalidLefthandSideInAssignment); } return(false); } } return(true); }
internal static Expression Parse(ParseInfo state, ref int index, FunctionKind kind) { string code = state.Code; int position = index; switch (kind) { case FunctionKind.AsyncAnonymousFunction: case FunctionKind.AnonymousFunction: case FunctionKind.AnonymousGenerator: { break; } case FunctionKind.Function: { if (!Parser.Validate(code, "function", ref position)) { return(null); } if (code[position] == '*') { kind = FunctionKind.Generator; position++; } else if ((code[position] != '(') && (!Tools.IsWhiteSpace(code[position]))) { return(null); } break; } case FunctionKind.Getter: { if (!Parser.Validate(code, "get ", ref position)) { return(null); } break; } case FunctionKind.Setter: { if (!Parser.Validate(code, "set ", ref position)) { return(null); } break; } case FunctionKind.MethodGenerator: case FunctionKind.Method: { if (Parser.Validate(code, "async", ref position)) { kind = FunctionKind.AsyncMethod; } if (code[position] == '*') { kind = FunctionKind.MethodGenerator; position++; } else if (kind == FunctionKind.MethodGenerator) { throw new ArgumentException("mode"); } break; } case FunctionKind.AsyncArrow: { if (!Parser.Validate(code, "async", ref position)) { return(null); } break; } case FunctionKind.Arrow: { break; } case FunctionKind.AsyncFunction: { if (!Parser.Validate(code, "async", ref position)) { return(null); } Tools.SkipSpaces(code, ref position); if (!Parser.Validate(code, "function", ref position)) { return(null); } break; } default: throw new NotImplementedException(kind.ToString()); } Tools.SkipSpaces(state.Code, ref position); var parameters = new List <ParameterDescriptor>(); CodeBlock body = null; string name = null; bool arrowWithSinglePrm = false; int nameStartPos = 0; bool containsDestructuringPrms = false; if (kind != FunctionKind.Arrow) { if (code[position] != '(') { nameStartPos = position; if (Parser.ValidateName(code, ref position, false, true, state.strict)) { name = Tools.Unescape(code.Substring(nameStartPos, position - nameStartPos), state.strict); } else if ((kind == FunctionKind.Getter || kind == FunctionKind.Setter) && Parser.ValidateString(code, ref position, false)) { name = Tools.Unescape(code.Substring(nameStartPos + 1, position - nameStartPos - 2), state.strict); } else if ((kind == FunctionKind.Getter || kind == FunctionKind.Setter) && Parser.ValidateNumber(code, ref position)) { name = Tools.Unescape(code.Substring(nameStartPos, position - nameStartPos), state.strict); } else { ExceptionHelper.ThrowSyntaxError("Invalid function name", code, nameStartPos, position - nameStartPos); } Tools.SkipSpaces(code, ref position); if (code[position] != '(') { ExceptionHelper.ThrowUnknownToken(code, position); } } else if (kind == FunctionKind.Getter || kind == FunctionKind.Setter) { ExceptionHelper.ThrowSyntaxError("Getter and Setter must have name", code, index); } else if (kind == FunctionKind.Method || kind == FunctionKind.MethodGenerator || kind == FunctionKind.AsyncMethod) { ExceptionHelper.ThrowSyntaxError("Method must has name", code, index); } position++; } else if (code[position] != '(') { arrowWithSinglePrm = true; } else { position++; } Tools.SkipSpaces(code, ref position); if (code[position] == ',') { ExceptionHelper.ThrowSyntaxError(Strings.UnexpectedToken, code, position); } while (code[position] != ')') { if (parameters.Count == 255 || (kind == FunctionKind.Setter && parameters.Count == 1) || kind == FunctionKind.Getter) { ExceptionHelper.ThrowSyntaxError(string.Format(Strings.TooManyArgumentsForFunction, name), code, index); } bool rest = Parser.Validate(code, "...", ref position); Expression destructor = null; int n = position; if (!Parser.ValidateName(code, ref position, state.strict)) { if (code[position] == '{') { destructor = (Expression)ObjectDefinition.Parse(state, ref position); } else if (code[position] == '[') { destructor = (Expression)ArrayDefinition.Parse(state, ref position); } if (destructor == null) { ExceptionHelper.ThrowUnknownToken(code, nameStartPos); } containsDestructuringPrms = true; } var pname = Tools.Unescape(code.Substring(n, position - n), state.strict); var reference = new ParameterReference(pname, rest, state.lexicalScopeLevel + 1) { Position = n, Length = position - n }; var desc = reference.Descriptor as ParameterDescriptor; if (destructor != null) { desc.Destructor = new ObjectDesctructor(destructor); } parameters.Add(desc); Tools.SkipSpaces(state.Code, ref position); if (arrowWithSinglePrm) { position--; break; } if (code[position] == '=') { if (rest) { ExceptionHelper.ThrowSyntaxError("Rest parameters can not have an initializer", code, position); } do { position++; }while (Tools.IsWhiteSpace(code[position])); desc.initializer = ExpressionTree.Parse(state, ref position, false, false) as Expression; } if (code[position] == ',') { if (rest) { ExceptionHelper.ThrowSyntaxError("Rest parameters must be the last in parameters list", code, position); } do { position++; }while (Tools.IsWhiteSpace(code[position])); } } if (kind == FunctionKind.Setter) { if (parameters.Count != 1) { ExceptionHelper.ThrowSyntaxError("Setter must has only one argument", code, index); } } position++; Tools.SkipSpaces(code, ref position); if (kind == FunctionKind.Arrow || kind == FunctionKind.AsyncArrow) { if (!Parser.Validate(code, "=>", ref position)) { ExceptionHelper.ThrowSyntaxError("Expected \"=>\"", code, position); } Tools.SkipSpaces(code, ref position); } if (code[position] != '{') { var oldFunctionScopeLevel = state.functionScopeLevel; state.functionScopeLevel = ++state.lexicalScopeLevel; try { if (kind == FunctionKind.Arrow || kind == FunctionKind.AsyncArrow) { body = new CodeBlock(new CodeNode[] { new Return(ExpressionTree.Parse(state, ref position, processComma: false) as Expression) }) { _variables = new VariableDescriptor[0] }; body.Position = body._lines[0].Position; body.Length = body._lines[0].Length; } else { ExceptionHelper.ThrowUnknownToken(code, position); } } finally { state.functionScopeLevel = oldFunctionScopeLevel; state.lexicalScopeLevel--; } } else { var oldCodeContext = state.CodeContext; state.CodeContext &= ~(CodeContext.InExpression | CodeContext.Conditional | CodeContext.InEval); if (kind == FunctionKind.Generator || kind == FunctionKind.MethodGenerator || kind == FunctionKind.AnonymousGenerator) { state.CodeContext |= CodeContext.InGenerator; } else if (kind == FunctionKind.AsyncFunction || kind == FunctionKind.AsyncMethod || kind == FunctionKind.AsyncAnonymousFunction || kind == FunctionKind.AsyncArrow) { state.CodeContext |= CodeContext.InAsync; } state.CodeContext |= CodeContext.InFunction; var labels = state.Labels; state.Labels = new List <string>(); state.AllowReturn++; try { state.AllowBreak.Push(false); state.AllowContinue.Push(false); state.AllowDirectives = true; body = CodeBlock.Parse(state, ref position) as CodeBlock; if (containsDestructuringPrms) { var destructuringTargets = new List <VariableDescriptor>(); var assignments = new List <Expression>(); for (var i = 0; i < parameters.Count; i++) { if (parameters[i].Destructor != null) { var targets = parameters[i].Destructor.GetTargetVariables(); for (var j = 0; j < targets.Count; j++) { destructuringTargets.Add(new VariableDescriptor(targets[j].Name, state.functionScopeLevel)); } assignments.Add(new Assignment(parameters[i].Destructor, parameters[i].references[0])); } } var newLines = new CodeNode[body._lines.Length + 1]; System.Array.Copy(body._lines, 0, newLines, 1, body._lines.Length); newLines[0] = new VariableDefinition(destructuringTargets.ToArray(), assignments.ToArray(), VariableKind.AutoGeneratedParameters); body._lines = newLines; } } finally { state.CodeContext = oldCodeContext; state.AllowBreak.Pop(); state.AllowContinue.Pop(); state.AllowDirectives = false; state.Labels = labels; state.AllowReturn--; } if (kind == FunctionKind.Function && string.IsNullOrEmpty(name)) { kind = FunctionKind.AnonymousFunction; } } if (body._strict || (parameters.Count > 0 && parameters[parameters.Count - 1].IsRest) || kind == FunctionKind.Arrow) { for (var j = parameters.Count; j-- > 1;) { for (var k = j; k-- > 0;) { if (parameters[j].Name == parameters[k].Name) { ExceptionHelper.ThrowSyntaxError("Duplicate names of function parameters not allowed in strict mode", code, index); } } } if (name == "arguments" || name == "eval") { ExceptionHelper.ThrowSyntaxError("Functions name can not be \"arguments\" or \"eval\" in strict mode at", code, index); } for (int j = parameters.Count; j-- > 0;) { if (parameters[j].Name == "arguments" || parameters[j].Name == "eval") { ExceptionHelper.ThrowSyntaxError("Parameters name cannot be \"arguments\" or \"eval\" in strict mode at", code, parameters[j].references[0].Position, parameters[j].references[0].Length); } } } var func = new FunctionDefinition(name) { parameters = parameters.ToArray(), _body = body, kind = kind, Position = index, Length = position - index, #if DEBUG trace = body.directives != null?body.directives.Contains("debug trace") : false #endif }; if (!string.IsNullOrEmpty(name)) { func.Reference.ScopeLevel = state.lexicalScopeLevel; func.Reference.Position = nameStartPos; func.Reference.Length = name.Length; func.reference._descriptor.definitionScopeLevel = func.reference.ScopeLevel; } if (parameters.Count != 0) { var newVariablesCount = body._variables.Length + parameters.Count; for (var j = 0; j < body._variables.Length; j++) { for (var k = 0; k < parameters.Count; k++) { if (body._variables[j].name == parameters[k].name) { newVariablesCount--; break; } } } var newVariables = new VariableDescriptor[newVariablesCount]; for (var j = 0; j < parameters.Count; j++) { newVariables[j] = parameters[parameters.Count - j - 1]; // порядок определяет приоритет for (var k = 0; k < body._variables.Length; k++) { if (body._variables[k] != null && body._variables[k].name == parameters[j].name) { if (body._variables[k].initializer != null) { newVariables[j] = body._variables[k]; } else { body._variables[k].lexicalScope = false; } body._variables[k] = null; break; } } } for (int j = 0, k = parameters.Count; j < body._variables.Length; j++) { if (body._variables[j] != null) { newVariables[k++] = body._variables[j]; } } body._variables = newVariables; } if ((state.CodeContext & CodeContext.InExpression) == 0 && kind == FunctionKind.Function) // Позволяет делать вызов сразу при объявлении функции // (в таком случае функция не добавляется в контекст). // Если убрать проверку, то в тех сулчаях, // когда определение и вызов стоят внутри выражения, // будет выдано исключение, потому, // что тогда это уже не определение и вызов функции, // а часть выражения, которые не могут начинаться со слова "function". // За красивыми словами "может/не может" кроется другая хрень: если бы это было выражение, // то прямо тут надо было бы разбирать тот оператор, который стоит после определения функции, // что не разумно { var tindex = position; while (position < code.Length && Tools.IsWhiteSpace(code[position]) && !Tools.IsLineTerminator(code[position])) { position++; } if (position < code.Length && code[position] == '(') { var args = new List <Expression>(); position++; for (; ;) { while (Tools.IsWhiteSpace(code[position])) { position++; } if (code[position] == ')') { break; } else if (code[position] == ',') { do { position++; }while (Tools.IsWhiteSpace(code[position])); } args.Add(ExpressionTree.Parse(state, ref position, false, false)); } position++; index = position; while (position < code.Length && Tools.IsWhiteSpace(code[position])) { position++; } if (position < code.Length && code[position] == ';') { ExceptionHelper.Throw((new SyntaxError("Expression can not start with word \"function\""))); } return(new Call(func, args.ToArray())); } else { position = tindex; } } if ((state.CodeContext & CodeContext.InExpression) == 0 && (kind != FunctionKind.Arrow || (state.CodeContext & CodeContext.InEval) == 0)) { if (string.IsNullOrEmpty(name)) { ExceptionHelper.ThrowSyntaxError("Function must has name", state.Code, index); } state.Variables.Add(func.reference._descriptor); } index = position; return(func); }