/// <summary> /// Parses an anonymous object. /// </summary> internal static SProtoObject Parse(ScriptProcessor processor, string source) { Prototype prototype = new Prototype(LITERAL_OBJECT); source = source.Trim(); // Format: { member1 : content1, member2 : content2 } // Remove "{" and "}": source = source.Remove(source.Length - 1, 1).Remove(0, 1).Trim(); if (source.Length == 0) return prototype.CreateInstance(processor, null, false); int index = 0; string identifier = ""; string content = ""; SObject contentObj = null; while (index < source.Length) { int nextSeperatorIndex = source.IndexOf(",", index); if (nextSeperatorIndex == -1) { nextSeperatorIndex = source.Length - 1; } else { //Let's find the correct ",": nextSeperatorIndex = index; int depth = 0; StringEscapeHelper escaper = new LeftToRightStringEscapeHelper(source, nextSeperatorIndex, true); bool foundSeperator = false; while (!foundSeperator && nextSeperatorIndex < source.Length) { char t = source[nextSeperatorIndex]; escaper.CheckStartAt(nextSeperatorIndex); if (!escaper.IsString) { if (t == '{' || t == '[' || t == '(') { depth++; } else if (t == '}' || t == ']' || t == ')') { depth--; } else if (t == ',' && depth == 0) { foundSeperator = true; nextSeperatorIndex--; // it adds one to the index at the end of the while loop, but we need the index where we stopped searching, so we subtract 1 here to accommodate for that. } } nextSeperatorIndex++; } } string member = source.Substring(index, nextSeperatorIndex - index); if (member.Contains(":")) { identifier = member.Remove(member.IndexOf(":")).Trim(); content = member.Remove(0, member.IndexOf(":") + 1); contentObj = processor.ExecuteStatement(new ScriptStatement(content)); } else { identifier = member.Trim(); contentObj = processor.Undefined; } if (!ScriptProcessor.IsValidIdentifier(identifier)) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME); prototype.AddMember(processor, new PrototypeMember(identifier, contentObj)); index = nextSeperatorIndex + 1; } return prototype.CreateInstance(processor, null, false); }
internal new static SObject Parse(ScriptProcessor processor, string code) { code = code.Trim(); if (Regex.IsMatch(code, REGEX_CLASS_SIGNATURE)) { List<string> signature = code.Remove(code.IndexOf("{")).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); string extends = ""; string identifier = ""; bool isAbstract = false; // Read extends: if (signature.Contains(CLASS_SIGNATURE_EXTENDS)) { int extendsIndex = signature.IndexOf(CLASS_SIGNATURE_EXTENDS); if (extendsIndex + 1 == signature.Count) // when extends is the last element in the signature, throw error: processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_EXTENDS_MISSING); extends = signature[extendsIndex + 1]; // The extended class name is after the "extends" keyword. signature.RemoveAt(extendsIndex); // Remove at the extends index twice, to remove the "extends" keyword and the identifier of the extended class. signature.RemoveAt(extendsIndex); } // Read abstract: if (signature.Contains(CLASS_SIGNATURE_ABSTRACT)) { isAbstract = true; signature.Remove(CLASS_SIGNATURE_ABSTRACT); } if (signature.Count != 2) // The signature must only have "class" and the identifier left. processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_INVALID_CLASS_SIGNATURE); // Read class name: identifier = signature[1]; if (!ScriptProcessor.IsValidIdentifier(identifier)) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_IDENTIFIER_MISSING); // Create instance: Prototype prototype = new Prototype(identifier) { IsAbstract = isAbstract }; // Handle extends: if (extends.Length > 0) { if (isAbstract) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_TYPE_ABSTRACT_NO_EXTENDS); Prototype extendedPrototype = processor.Context.GetPrototype(extends); if (extendedPrototype == null) processor.ErrorHandler.ThrowError(ErrorType.ReferenceError, ErrorHandler.MESSAGE_REFERENCE_NO_PROTOTYPE, new object[] { extends }); prototype.Extends = extendedPrototype; } else { // Set default prototype: prototype.Extends = processor.Context.GetPrototype("Object"); } string body = code.Remove(0, code.IndexOf("{") + 1); body = body.Remove(body.Length - 1, 1).Trim(); string additionalCtorCode = ""; string staticCtorCode = ""; ScriptStatement[] statements = StatementProcessor.GetStatements(processor, body); foreach (ScriptStatement statement in statements) { if (statement.StatementType == StatementType.Var) { var parsed = ParseVarStatement(processor, statement); if (parsed.Item1.Identifier == CLASS_METHOD_CTOR) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME); prototype.AddMember(processor, parsed.Item1); if (parsed.Item2.Length > 0) { if (parsed.Item1.IsStatic) { staticCtorCode += string.Format(FORMAT_VAR_ASSIGNMENT, parsed.Item1.Identifier, parsed.Item2); } else { additionalCtorCode += string.Format(FORMAT_VAR_ASSIGNMENT, parsed.Item1.Identifier, parsed.Item2); } } } else if (statement.StatementType == StatementType.Function) { PrototypeMember parsed = ParseFunctionStatement(processor, statement); if (parsed.Identifier == CLASS_METHOD_CTOR) { if (prototype.Constructor != null) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_DUPLICATE_DEFINITION, new object[] { parsed.Identifier, identifier }); prototype.Constructor = parsed; } else { prototype.AddMember(processor, parsed); } } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_STATEMENT); } } // Add additional constructor code & static constructor code to prototype: if (staticCtorCode.Length > 0) { prototype._staticConstructor = new SFunction(staticCtorCode, new string[] { }); prototype._staticConstructorProcessor = processor; } if (additionalCtorCode.Length > 0) { if (prototype.Constructor == null) { // Create new ctor if no one has been defined: prototype.Constructor = new PrototypeMember(CLASS_METHOD_CTOR, new SFunction("", new string[] { }), false, true, false, false); } prototype.Constructor.ToFunction().Body = additionalCtorCode + prototype.Constructor.ToFunction().Body; } return prototype; } else { return processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_INVALID_CLASS_SIGNATURE); } }
/// <summary> /// Creates an instance of the given prototype. /// </summary> internal SObject CreateInstance(Prototype prototype, SObject[] parameters) { if (!prototype.IsAbstract) return prototype.CreateInstance(_processor, parameters, true); else return _processor.ErrorHandler.ThrowError(ErrorType.TypeError, ErrorHandler.MESSAGE_TYPE_ABSTRACT_NO_INSTANCE); }
/// <summary> /// Creates an instance derived from this prototype. /// </summary> internal SProtoObject CreateInstance(ScriptProcessor processor, SObject[] parameters, bool executeCtor) { SProtoObject obj = CreateBaseObject(); obj.AddMember(MEMBER_NAME_PROTOTYPE, this); if (typeof(ObjectPrototype) != GetType()) { // If no extends class is explicitly specified, "Object" is assumed. if (Extends == null) Extends = processor.Context.GetPrototype("Object"); var superInstance = Extends.CreateInstance(processor, null, false); obj.AddMember(MEMBER_NAME_SUPER, superInstance); } foreach (PrototypeMember member in GetInstanceMembers()) { obj.AddMember(member.Identifier, member.Data); } var indexerGetFunction = GetIndexerGetFunction(); if (indexerGetFunction != null) obj.IndexerGetFunction = indexerGetFunction.ToFunction(); var indexerSetFunction = GetIndexerSetFunction(); if (indexerSetFunction != null) obj.IndexerSetFunction = indexerSetFunction.ToFunction(); if (executeCtor && Constructor != null) { Constructor.ToFunction().Call(processor, obj, obj, parameters); } // Lock all readonly members after the constructor call, so they can be set in the constructor: foreach (PrototypeMember member in GetReadOnlyInstanceMembers()) obj.Members[member.Identifier].IsReadOnly = true; return obj; }