예제 #1
0
 public ClassConstructor(Context context, FunctionDefinition creator, ClassDefinition classDefinition)
     : base(context, creator)
 {
     this.classDefinition = classDefinition;
 }
예제 #2
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.InClassDefinition;
                        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 method", 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.InClassDefinition
                    },
                        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);
        }