public ClassConstructor(Context context, FunctionDefinition creator, ClassDefinition classDefinition) : base(context, creator) { this.classDefinition = classDefinition; }
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); }