Пример #1
0
        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.AsyncMethod:
            {
                break;
            }

            case FunctionKind.MethodGenerator:
            case FunctionKind.Method:
            {
                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 have 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
            {
                using (state.WithNewLabelsScope())
                    using (state.WithCodeContext())
                    {
                        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;
                        state.CodeContext |= CodeContext.AllowDirectives;
                        state.CodeContext &= ~(CodeContext.InExpression | CodeContext.Conditional | CodeContext.InEval);

                        state.AllowReturn++;
                        try
                        {
                            state.AllowBreak.Push(false);
                            state.AllowContinue.Push(false);
                            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.AllowBreak.Pop();
                            state.AllowContinue.Pop();
                            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);
        }
Пример #2
0
 public override void Optimize(ref CodeNode _this, FunctionDefinition owner, InternalCompilerMessageCallback message, Options opts, FunctionInfo stats)
 {
     base.Optimize(ref _this, owner, message, opts, stats);
 }
Пример #3
0
        public override void Optimize(ref CodeNode _this, FunctionDefinition owner, InternalCompilerMessageCallback message, Options opts, FunctionInfo stats)
        {
            baseOptimize(ref _this, owner, message, opts, stats);
            var vr = _left as VariableReference;

            if (vr != null)
            {
                if (vr._descriptor.IsDefined)
                {
                    var stype = _right.ResultType;
                    if (vr._descriptor.lastPredictedType == PredictedType.Unknown)
                    {
                        vr._descriptor.lastPredictedType = stype;
                    }
                    else if (vr._descriptor.lastPredictedType != stype)
                    {
                        if (Tools.IsEqual(vr._descriptor.lastPredictedType, stype, PredictedType.Group))
                        {
                            vr._descriptor.lastPredictedType = stype & PredictedType.Group;
                        }
                        else
                        {
                            if (message != null && stype >= PredictedType.Undefined && vr._descriptor.lastPredictedType >= PredictedType.Undefined)
                            {
                                message(MessageLevel.Warning, Position, Length, "Variable \"" + vr.Name + "\" has ambiguous type. It can be make impossible some optimizations and cause errors.");
                            }
                            vr._descriptor.lastPredictedType = PredictedType.Ambiguous;
                        }
                    }
                }
                else if (message != null)
                {
                    message(MessageLevel.CriticalWarning, Position, Length, "Assign to undefined variable \"" + vr.Name + "\". It will declare a global variable.");
                }
            }

            var variable = _left as Variable;

            if (variable != null && variable._descriptor.IsDefined && (_codeContext & CodeContext.InWith) == 0 && !variable._descriptor.captured)
            {
                if (!stats.ContainsEval && !stats.ContainsWith)
                {
                    if (owner != null // не будем это применять в корневом узле. Только в функциях.
                                      // Иначе это может использоваться как настройка контекста для последующего использования в Eval
                        && (opts & Options.SuppressUselessExpressionsElimination) == 0 &&
                        (_codeContext & CodeContext.InLoop) == 0)
                    {
                        if ((owner._body._strict || variable._descriptor.owner != owner || !owner._functionInfo.ContainsArguments)) // аргументы это одна сущность с двумя именами
                        {
                            bool last = true;
                            for (var i = 0; last && i < variable._descriptor.references.Count; i++)
                            {
                                last &= variable._descriptor.references[i].Eliminated || variable._descriptor.references[i].Position <= Position;
                            }

                            if (last)
                            {
                                if (_right.ContextIndependent)
                                {
                                    _this.Eliminated = true;
                                    _this            = Empty.Instance;
                                }
                                else
                                {
                                    _this           = _right;
                                    this._right     = null;
                                    this.Eliminated = true;
                                    this._right     = _this as Expression;
                                }
                            }
                        }
                    }
                }

                /*if (_this == this && second.ResultInTempContainer) // это присваивание, не последнее, без with
                 * {
                 *  _this = new AssignmentOverReplace(first, second)
                 *  {
                 *      Position = Position,
                 *      Length = Length,
                 *      _codeContext = _codeContext
                 *  };
                 * }*/
            }
        }
Пример #4
0
        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);

                var async = false;
                if (!asterisk)
                {
                    async = Parser.Validate(state.Code, "async", ref 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);
                    CodeNode initializer;
                    if (state.Code[i] == '(')
                    {
                        initializer = FunctionDefinition.Parse(state, ref i, asterisk ? FunctionKind.AnonymousGenerator : async ? FunctionKind.AsyncAnonymousFunction : FunctionKind.AnonymousFunction);
                    }
                    else
                    {
                        if (!Parser.Validate(state.Code, ":", ref i))
                        {
                            ExceptionHelper.ThrowSyntaxError(Strings.UnexpectedToken, state.Code, i);
                        }
                        initializer = 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 : async ? FunctionKind.AsyncMethod : FunctionKind.Method);
                    }
                    else
                    {
                        if (asterisk || (async && state.Code[i] != ':'))
                        {
                            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);
                            }

                            if (state.Message != null)
                            {
                                state.Message(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
            });
        }
Пример #5
0
 public ClassConstructor(Context context, FunctionDefinition creator, ClassDefinition classDefinition)
     : base(context, creator)
 {
     this.classDefinition = classDefinition;
 }
Пример #6
0
        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(Strings.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]));

                        CodeNode initializer;
                        if (state.Code[i] == '(')
                        {
                            initializer = FunctionDefinition.Parse(state, ref i, asterisk ? FunctionKind.AnonymousGenerator : FunctionKind.AnonymousFunction);
                        }
                        else
                        {
                            initializer = ExpressionTree.Parse(state, ref i);
                        }

                        switch (state.Code[s])
                        {
                        case 'g':
                        {
                            computedProperties.Add(new MemberDescriptor((Expression)propertyName, new PropertyPair((Expression)initializer, null), @static));
                            break;
                        }

                        case 's':
                        {
                            computedProperties.Add(new MemberDescriptor((Expression)propertyName, new PropertyPair(null, (Expression)initializer), @static));
                            break;
                        }

                        default:
                        {
                            computedProperties.Add(new MemberDescriptor((Expression)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(Strings.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 as FunctionDefinition, 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);
        }
Пример #7
0
 private ClassDefinition(string name, Expression baseType, MemberDescriptor[] fields, FunctionDefinition ctor, MemberDescriptor[] computedProperties)
     : base(name)
 {
     this._baseClass         = baseType;
     this._constructor       = ctor;
     this._members           = fields;
     this.computedProperties = computedProperties;
 }
Пример #8
0
 public override void Optimize(ref Core.CodeNode _this, FunctionDefinition owner, CompilerMessageCallback message, Options opts, FunctionInfo stats)
 {
 }
Пример #9
0
        public override void Optimize(ref CodeNode _this, FunctionDefinition owner, CompilerMessageCallback message, Options opts, FunctionInfo stats)
        {
            if ((opts & Options.SuppressConstantPropogation) == 0 &&
                !_descriptor.captured &&
                _descriptor.isDefined &&
                !stats.ContainsWith &&
                !stats.ContainsEval &&
                (_descriptor.owner != owner || !owner._functionInfo.ContainsArguments))
            {
                var assigns = _descriptor.assignments;
                if (assigns != null && assigns.Count > 0)
                {
                    /*
                     * Применение оптимизации зависит от порядка добавления присваиваний.
                     * Этот порядок в свою очередь зависит от порядка следования операций в CodeBlock.
                     * Раньше этот порядок был обратным, сейчас прямой, поэтому здесь присваивания нужно перебирать
                     * в обратном порядке. Оптимизация не применится если найдется изменение в котором first указывает на
                     * это использование. Это говорит о том, что в данном месте этой переменной
                     * присваивается значение
                     */
                    CodeNode lastAssign = null;
                    for (var i = assigns.Count; i-- > 0;)
                    {
                        if (assigns[i]._left == this ||
                            ((assigns[i]._left is AssignmentOperatorCache) && assigns[i]._left._left == this))
                        {
                            // оптимизация не применяется
                            lastAssign = null;
                            break;
                        }

                        if (assigns[i].Position > Position)
                        {
                            if ((_codeContext & CodeContext.InLoop) != 0 && ((assigns[i] as Expression)._codeContext & CodeContext.InLoop) != 0)
                            // присваивание может быть после этого использования, но если всё это в цикле, то выполнение вернётся сюда.
                            {
                                // оптимизация не применяется
                                lastAssign = null;
                                break;
                            }
                            continue; // пропускаем ноду
                        }

                        if (_descriptor.isReadOnly)
                        {
                            if (assigns[i] is ForceAssignmentOperator)
                            {
                                lastAssign = assigns[i];
                                break;
                            }
                        }
                        else if (lastAssign == null || assigns[i].Position > lastAssign.Position)
                        {
                            lastAssign = assigns[i];
                        }
                    }
                    var assign = lastAssign as Assignment;
                    if (assign != null && (assign._codeContext & CodeContext.Conditional) == 0 && assign._right is Constant)
                    {
                        _this = assign._right;
                    }
                }
            }
        }