Пример #1
0
        // TODO: C# 7: put proper Tuple handling in place.

        private static Tuple <PrototypeMember, string> ParseVarStatement(ScriptProcessor processor, ScriptStatement statement)
        {
            var code      = statement.Code;
            var signature = code.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

            string identifier;
            var    assignment = "";
            var    isReadOnly = false;
            var    isStatic   = false;

            // Read static:
            if (signature.Contains(VAR_SIGNATURE_STATIC))
            {
                isStatic = true;
                signature.Remove(VAR_SIGNATURE_STATIC);
            }

            // Read readonly:
            if (signature.Contains(VAR_SIGNATURE_READONLY))
            {
                isReadOnly = true;
                signature.Remove(VAR_SIGNATURE_READONLY);
            }

            if (signature[0] != "var" || signature.Count < 2)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_VAR_DECLARATION);
            }

            identifier = signature[1];

            if (!ScriptProcessor.IsValidIdentifier(identifier))
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME);
            }

            if (signature.Count > 2)
            {
                if (signature[2].StartsWith("="))
                {
                    assignment = code.Remove(0, code.IndexOf("=") + 1).Trim();
                }
                else
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_VAR_DECLARATION);
                }
            }

            var member = new PrototypeMember(identifier, processor.Undefined, isStatic, isReadOnly, false, false);

            return(new Tuple <PrototypeMember, string>(member, assignment));
        }
Пример #2
0
        // TODO: C# 7: put proper Tuple handling in place.

        private static Tuple <PrototypeMember, string> ParseVarStatement(ScriptProcessor processor, ScriptStatement statement)
        {
            var code      = statement.Code;
            var signature = code.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

            var assignment = "";
            var isReadOnly = false;
            var isStatic   = false;

            // Read static:
            if (signature.Contains(VarSignatureStatic))
            {
                isStatic = true;
                signature.Remove(VarSignatureStatic);
            }

            // Read readonly:
            if (signature.Contains(VarSignatureReadonly))
            {
                isReadOnly = true;
                signature.Remove(VarSignatureReadonly);
            }

            if (signature[0] != "var" || signature.Count < 2)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassInvalidVarDeclaration);
            }

            var identifier = signature[1];

            if (!ScriptProcessor.IsValidIdentifier(identifier))
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingVarName);
            }

            if (signature.Count > 2)
            {
                if (signature[2].StartsWith("="))
                {
                    assignment = code.Remove(0, code.IndexOf("=", StringComparison.Ordinal) + 1).Trim();
                }
                else
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassInvalidVarDeclaration);
                }
            }

            var member = new PrototypeMember(identifier, processor.Undefined, isStatic, isReadOnly, false, false);

            return(new Tuple <PrototypeMember, string>(member, assignment));
        }
Пример #3
0
        /// <summary>
        /// Initializes an instance with a script code signature and body.
        /// </summary>
        /// <param name="processor"></param>
        /// <param name="sourceCode">The source code, format: <code>function (params) { code }</code></param>
        public SFunction(ScriptProcessor processor, string sourceCode)
        {
            sourceCode = sourceCode.Trim();
            var paramCode = sourceCode.Remove(0, "function".Length).Trim().Remove(0, 1); //Removes "function", then any spaces between "function" and "(", then removes "(".

            paramCode = paramCode.Remove(paramCode.IndexOf(")", StringComparison.Ordinal));

            _parameters = paramCode.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray();

            var allIdentifiersValid = true;
            var i = 0;

            while (i < _parameters.Length - 1 && allIdentifiersValid)
            {
                if (!ScriptProcessor.IsValidIdentifier(_parameters[i]))
                {
                    allIdentifiersValid = false;
                }

                i++;
            }

            if (!allIdentifiersValid)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingFormalParameter);
            }
            else
            {
                if (!sourceCode.Contains("{") || !sourceCode.EndsWith("}"))
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingFunctionBody);
                }
                else
                {
                    Body = sourceCode.Remove(sourceCode.Length - 1, 1).Remove(0, sourceCode.IndexOf("{", StringComparison.Ordinal) + 1).Trim();
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Initializes an instance with a script code signature and body.
        /// </summary>
        /// <param name="sourceCode">The source code, format: <code>function (params) { code }</code></param>
        public SFunction(ScriptProcessor processor, string sourceCode)
        {
            sourceCode = sourceCode.Trim();
            var paramCode = sourceCode.Remove(0, "function".Length).Trim().Remove(0, 1); //Removes "function", then any spaces between "function" and "(", then removes "(".

            paramCode = paramCode.Remove(paramCode.IndexOf(")"));

            _parameters = paramCode.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray();

            var allIdentifiersValid = true;
            var i = 0;

            while (i < _parameters.Length - 1 && allIdentifiersValid)
            {
                if (!ScriptProcessor.IsValidIdentifier(_parameters[i]))
                {
                    allIdentifiersValid = false;
                }

                i++;
            }

            if (!allIdentifiersValid)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_FORMAL_PARAMETER);
            }
            else
            {
                if (!sourceCode.Contains("{") || !sourceCode.EndsWith("}"))
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_FUNCTION_BODY);
                }
                else
                {
                    Body = sourceCode.Remove(sourceCode.Length - 1, 1).Remove(0, sourceCode.IndexOf("{") + 1).Trim();
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Parses an anonymous object.
        /// </summary>
        internal static SProtoObject Parse(ScriptProcessor processor, string source)
        {
            var 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));
            }

            var     index      = 0;
            var     identifier = "";
            var     content    = "";
            SObject contentObj = null;

            while (index < source.Length)
            {
                var nextSeperatorIndex = source.IndexOf(",", index);
                if (nextSeperatorIndex == -1)
                {
                    nextSeperatorIndex = source.Length;
                }
                else
                {
                    //Let's find the correct ",":

                    nextSeperatorIndex = index;

                    var depth = 0;
                    StringEscapeHelper escaper = new LeftToRightStringEscapeHelper(source, nextSeperatorIndex, true);
                    var foundSeperator         = false;

                    while (!foundSeperator && nextSeperatorIndex < source.Length)
                    {
                        var 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++;
                    }
                }

                var 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));
        }
Пример #6
0
        private static PrototypeMember ParseFunctionStatement(ScriptProcessor processor, ScriptStatement headerStatement, ScriptStatement bodyStatement)
        {
            var header    = headerStatement.Code;
            var signature = header.Remove(header.IndexOf("(")).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

            string identifier;
            var    isStatic     = false;
            var    isIndexerGet = false;
            var    isIndexerSet = false;
            var    functionType = FunctionUsageType.Default;

            var significantCount = 0;

            // Read static:
            if (signature.Contains(FUNCTION_SIGNATURE_STATIC))
            {
                isStatic = true;
                signature.Remove(FUNCTION_SIGNATURE_STATIC);
            }

            // Read indexer:
            if (signature.Contains(FUNCTION_SIGNATURE_INDEXER))
            {
                significantCount++;

                var indexerIndex = signature.IndexOf(FUNCTION_SIGNATURE_INDEXER);

                if (indexerIndex + 1 == signature.Count)
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_INDEXER_EXPECTED_TYPE);
                }

                var indexerType = signature[indexerIndex + 1];
                if (indexerType == FUNCTION_SIGNATURE_GET)
                {
                    isIndexerGet = true;
                    signature.RemoveAt(indexerIndex + 1);
                }
                else if (indexerType == FUNCTION_SIGNATURE_SET)
                {
                    isIndexerSet = true;
                    signature.RemoveAt(indexerIndex + 1);
                }
                else
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_INDEXER_INVALID_TYPE, indexerType);
                }

                signature.Remove(FUNCTION_SIGNATURE_INDEXER);
            }
            // Read property:
            if (signature.Contains(FUNCTION_SIGNATURE_PROPERTY))
            {
                significantCount++;

                var propertyIndex = signature.IndexOf(FUNCTION_SIGNATURE_PROPERTY);

                if (propertyIndex + 1 == signature.Count)
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_PROPERTY_EXPECTED_TYPE);
                }

                var propertyType = signature[propertyIndex + 1];
                if (propertyType == FUNCTION_SIGNATURE_GET)
                {
                    functionType = FunctionUsageType.PropertyGetter;
                    signature.RemoveAt(propertyIndex + 1);
                }
                else if (propertyType == FUNCTION_SIGNATURE_SET)
                {
                    functionType = FunctionUsageType.PropertySetter;
                    signature.RemoveAt(propertyIndex + 1);
                }
                else
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_PROPERTY_INVALID_TYPE, propertyType);
                }

                signature.Remove(FUNCTION_SIGNATURE_PROPERTY);
            }

            // Only one (or none) significant signature types can be added to a signature.
            if (significantCount > 1)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INCOMPATIBLE_SIGNATURE);
            }

            if (signature.Count != 2)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_FUNCTION_SIGNATURE);
            }

            identifier = signature[1];

            if (!ScriptProcessor.IsValidIdentifier(identifier))
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME);
            }

            // After the valid identifier check is done, we add the getter/setter prefix. It wouldn't pass the test.
            if (functionType == FunctionUsageType.PropertyGetter)
            {
                identifier = PROPERTY_GET_PREFIX + identifier;
            }
            if (functionType == FunctionUsageType.PropertySetter)
            {
                identifier = PROPERTY_SET_PREFIX + identifier;
            }

            var function = new SFunction(processor, signature[0] + " " + header.Remove(0, header.IndexOf("(")) + bodyStatement.Code)
            {
                FunctionUsage = functionType
            };

            return(new PrototypeMember(identifier, function, isStatic, false, isIndexerGet, isIndexerSet));
        }
Пример #7
0
        internal new static SObject Parse(ScriptProcessor processor, string code)
        {
            code = code.Trim();

            if (Regex.IsMatch(code, REGEX_CLASS_SIGNATURE, RegexOptions.Singleline))
            {
                var signature = code.Remove(code.IndexOf("{")).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

                var extends    = "";
                var identifier = "";
                var isAbstract = false;

                // Read extends:
                if (signature.Contains(CLASS_SIGNATURE_EXTENDS))
                {
                    var 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:
                var 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);
                    }

                    var extendedPrototype = processor.Context.GetPrototype(extends);

                    if (extendedPrototype == null)
                    {
                        processor.ErrorHandler.ThrowError(ErrorType.ReferenceError, ErrorHandler.MESSAGE_REFERENCE_NO_PROTOTYPE, extends);
                    }

                    prototype.Extends = extendedPrototype;
                }
                else
                {
                    // Set default prototype:
                    prototype.Extends = processor.Context.GetPrototype("Object");
                }

                var body = code.Remove(0, code.IndexOf("{") + 1);
                body = body.Remove(body.Length - 1, 1).Trim();

                var additionalCtorCode = "";
                var staticCtorCode     = "";

                var statements = StatementProcessor.GetStatements(processor, body);

                for (var i = 0; i < statements.Length; i++)
                {
                    var statement = statements[i];

                    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)
                    {
                        i++;

                        if (statements.Length > i)
                        {
                            var bodyStatement = statements[i];
                            var parsed        = ParseFunctionStatement(processor, statement, bodyStatement);

                            if (parsed.Identifier == CLASS_METHOD_CTOR)
                            {
                                if (prototype.Constructor != null)
                                {
                                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_DUPLICATE_DEFINITION, parsed.Identifier, identifier);
                                }

                                prototype.Constructor = parsed;
                            }
                            else
                            {
                                prototype.AddMember(processor, parsed);
                            }
                        }
                        else
                        {
                            return(processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script"));
                        }
                    }
                    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));
            }
        }
Пример #8
0
        private static PrototypeMember ParseFunctionStatement(ScriptProcessor processor, ScriptStatement headerStatement, ScriptStatement bodyStatement)
        {
            var header    = headerStatement.Code;
            var signature = header.Remove(header.IndexOf("(", StringComparison.Ordinal)).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

            var isStatic     = false;
            var isIndexerGet = false;
            var isIndexerSet = false;
            var functionType = FunctionUsageType.Default;

            var significantCount = 0;

            // Read static:
            if (signature.Contains(FunctionSignatureStatic))
            {
                isStatic = true;
                signature.Remove(FunctionSignatureStatic);
            }

            // Read indexer:
            if (signature.Contains(FunctionSignatureIndexer))
            {
                significantCount++;

                var indexerIndex = signature.IndexOf(FunctionSignatureIndexer);

                if (indexerIndex + 1 == signature.Count)
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassFunctionIndexerExpectedType);
                }

                var indexerType = signature[indexerIndex + 1];
                if (indexerType == FunctionSignatureGet)
                {
                    isIndexerGet = true;
                    signature.RemoveAt(indexerIndex + 1);
                }
                else if (indexerType == FunctionSignatureSet)
                {
                    isIndexerSet = true;
                    signature.RemoveAt(indexerIndex + 1);
                }
                else
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassFunctionIndexerInvalidType, indexerType);
                }

                signature.Remove(FunctionSignatureIndexer);
            }
            // Read property:
            if (signature.Contains(FunctionSignatureProperty))
            {
                significantCount++;

                var propertyIndex = signature.IndexOf(FunctionSignatureProperty);

                if (propertyIndex + 1 == signature.Count)
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassFunctionPropertyExpectedType);
                }

                var propertyType = signature[propertyIndex + 1];
                if (propertyType == FunctionSignatureGet)
                {
                    functionType = FunctionUsageType.PropertyGetter;
                    signature.RemoveAt(propertyIndex + 1);
                }
                else if (propertyType == FunctionSignatureSet)
                {
                    functionType = FunctionUsageType.PropertySetter;
                    signature.RemoveAt(propertyIndex + 1);
                }
                else
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassFunctionPropertyInvalidType, propertyType);
                }

                signature.Remove(FunctionSignatureProperty);
            }

            // Only one (or none) significant signature types can be added to a signature.
            if (significantCount > 1)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassIncompatibleSignature);
            }

            if (signature.Count != 2)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassInvalidFunctionSignature);
            }

            var identifier = signature[1];

            if (!ScriptProcessor.IsValidIdentifier(identifier))
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingVarName);
            }

            // After the valid identifier check is done, we add the getter/setter prefix. It wouldn't pass the test.
            if (functionType == FunctionUsageType.PropertyGetter)
            {
                identifier = PropertyGetPrefix + identifier;
            }
            if (functionType == FunctionUsageType.PropertySetter)
            {
                identifier = PropertySetPrefix + identifier;
            }

            var function = new SFunction(processor, signature[0] + " " + header.Remove(0, header.IndexOf("(", StringComparison.Ordinal)) + bodyStatement.Code)
            {
                FunctionUsage = functionType
            };

            return(new PrototypeMember(identifier, function, isStatic, false, isIndexerGet, isIndexerSet));
        }
Пример #9
0
        internal new static SObject Parse(ScriptProcessor processor, string code)
        {
            code = code.Trim();

            if (Regex.IsMatch(code, RegexClassSignature, RegexOptions.Singleline))
            {
                var signature = code.Remove(code.IndexOf("{", StringComparison.Ordinal)).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

                var extends    = "";
                var isAbstract = false;

                // Read extends:
                if (signature.Contains(ClassSignatureExtends))
                {
                    var extendsIndex = signature.IndexOf(ClassSignatureExtends);

                    if (extendsIndex + 1 == signature.Count) // when extends is the last element in the signature, throw error:
                    {
                        processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassExtendsMissing);
                    }

                    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(ClassSignatureAbstract))
                {
                    isAbstract = true;
                    signature.Remove(ClassSignatureAbstract);
                }

                if (signature.Count != 2) // The signature must only have "class" and the identifier left.
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxInvalidClassSignature);
                }

                // Read class name:
                var identifier = signature[1];

                if (!ScriptProcessor.IsValidIdentifier(identifier))
                {
                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassIdentifierMissing);
                }

                // Create instance:
                var prototype = new Prototype(identifier)
                {
                    IsAbstract = isAbstract
                };

                // Handle extends:
                if (extends.Length > 0)
                {
                    if (isAbstract)
                    {
                        processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageTypeAbstractNoExtends);
                    }

                    var extendedPrototype = processor.Context.GetPrototype(extends);

                    if (extendedPrototype == null)
                    {
                        processor.ErrorHandler.ThrowError(ErrorType.ReferenceError, ErrorHandler.MessageReferenceNoPrototype, extends);
                    }

                    prototype.Extends = extendedPrototype;
                }
                else
                {
                    // Set default prototype:
                    prototype.Extends = processor.Context.GetPrototype("Object");
                }

                var body = code.Remove(0, code.IndexOf("{", StringComparison.Ordinal) + 1);
                body = body.Remove(body.Length - 1, 1).Trim();

                var additionalCtorCode = "";
                var staticCtorCode     = "";

                var statements = StatementProcessor.GetStatements(processor, body);

                for (var i = 0; i < statements.Length; i++)
                {
                    var statement = statements[i];

                    if (statement.StatementType == StatementType.Var)
                    {
                        var parsed = ParseVarStatement(processor, statement);

                        if (parsed.Item1.Identifier == ClassMethodCtor)
                        {
                            processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingVarName);
                        }

                        prototype.AddMember(processor, parsed.Item1);

                        if (parsed.Item2.Length > 0)
                        {
                            if (parsed.Item1.IsStatic)
                            {
                                staticCtorCode += string.Format(FormatVarAssignment, parsed.Item1.Identifier, parsed.Item2);
                            }
                            else
                            {
                                additionalCtorCode += string.Format(FormatVarAssignment, parsed.Item1.Identifier, parsed.Item2);
                            }
                        }
                    }
                    else if (statement.StatementType == StatementType.Function)
                    {
                        i++;

                        if (statements.Length > i)
                        {
                            var bodyStatement = statements[i];
                            var parsed        = ParseFunctionStatement(processor, statement, bodyStatement);

                            if (parsed.Identifier == ClassMethodCtor)
                            {
                                if (prototype.Constructor != null)
                                {
                                    processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassDuplicateDefinition, parsed.Identifier, identifier);
                                }

                                prototype.Constructor = parsed;
                            }
                            else
                            {
                                prototype.AddMember(processor, parsed);
                            }
                        }
                        else
                        {
                            return(processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxExpectedExpression, "end of script"));
                        }
                    }
                    else
                    {
                        processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxClassInvalidStatement);
                    }
                }

                // 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(ClassMethodCtor, 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.MessageSyntaxInvalidClassSignature));
            }
        }
Пример #10
0
        public static SObject AddMember(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters)
        {
            // Parameter #1: (String)Name of the new member
            // [Parameter #2: Default value of the new member ] / Undefined
            // [Parameter #3: Signature config of the new member] / instance member, no special settings

            if (parameters.Length == 0)
            {
                return(processor.Undefined);
            }

            Prototype prototype;

            if (IsPrototype(instance.GetType()))
            {
                prototype = (Prototype)instance;
            }
            else
            {
                // The instance will be a prototype instance, so get its prototype from there:
                var protoObj = (SProtoObject)instance;
                prototype = protoObj.Prototype;
            }

            var memberAsString = parameters[0] as SString;
            var memberName     = memberAsString != null ? memberAsString.Value : parameters[0].ToString(processor).Value;

            var defaultValue = processor.Undefined;

            if (parameters.Length > 1)
            {
                defaultValue = parameters[1];
            }

            var isReadOnly   = false;
            var isStatic     = false;
            var isIndexerGet = false;
            var isIndexerSet = false;

            if (parameters.Length > 2)
            {
                var signature = parameters[2];
                var array     = signature as SArray;
                if (array != null)
                {
                    foreach (var arrayMember in array.ArrayMembers)
                    {
                        var arrayMemberAsString = arrayMember as SString;
                        if (arrayMemberAsString == null)
                        {
                            continue;
                        }

                        var signatureMember = arrayMemberAsString.Value;
                        switch (signatureMember)
                        {
                        case "readOnly":
                            isReadOnly = true;
                            break;

                        case "static":
                            isStatic = true;
                            break;

                        case "indexerGet":
                            isIndexerGet = true;
                            break;

                        case "indexerSet":
                            isIndexerSet = true;
                            break;
                        }
                    }
                }
            }

            if ((isIndexerSet || isIndexerGet) && !(defaultValue is SFunction))
            {
                processor.ErrorHandler.ThrowError(ErrorType.TypeError, ErrorHandler.MessageTypeGetterSetterNotAFunction);
            }

            if (!ScriptProcessor.IsValidIdentifier(memberName))
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingVarName);
            }

            prototype.AddMember(processor, new PrototypeMember(memberName, defaultValue, isStatic, isReadOnly, isIndexerGet, isIndexerSet));

            return(processor.Undefined);
        }
Пример #11
0
        public static SObject AddMember(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters)
        {
            // Parameter #1: (String)Name of the new member
            // [Parameter #2: Default value of the new member ] / Undefined
            // [Parameter #3: Signature config of the new member] / instance member, no special settings

            if (parameters.Length == 0)
            {
                return(processor.Undefined);
            }

            Prototype prototype;

            if (IsPrototype(instance.GetType()))
            {
                prototype = (Prototype)instance;
            }
            else
            {
                // The instance will be a prototype instance, so get its prototype from there:
                var protoObj = (SProtoObject)instance;
                prototype = protoObj.Prototype;
            }

            string memberName;

            if (parameters[0] is SString)
            {
                memberName = ((SString)parameters[0]).Value;
            }
            else
            {
                memberName = parameters[0].ToString(processor).Value;
            }

            var defaultValue = processor.Undefined;

            if (parameters.Length > 1)
            {
                defaultValue = parameters[1];
            }

            var isReadOnly   = false;
            var isStatic     = false;
            var isIndexerGet = false;
            var isIndexerSet = false;

            if (parameters.Length > 2)
            {
                var signature = parameters[2];
                if (signature is SArray)
                {
                    foreach (var arrayMember in ((SArray)signature).ArrayMembers)
                    {
                        if (arrayMember is SString)
                        {
                            var signatureMember = ((SString)arrayMember).Value;
                            switch (signatureMember)
                            {
                            case "readOnly":
                                isReadOnly = true;
                                break;

                            case "static":
                                isStatic = true;
                                break;

                            case "indexerGet":
                                isIndexerGet = true;
                                break;

                            case "indexerSet":
                                isIndexerSet = true;
                                break;
                            }
                        }
                    }
                }
            }

            if ((isIndexerSet || isIndexerGet) && !(defaultValue is SFunction))
            {
                processor.ErrorHandler.ThrowError(ErrorType.TypeError, ErrorHandler.MESSAGE_TYPE_GETTER_SETTER_NOT_A_FUNCTION);
            }

            if (!ScriptProcessor.IsValidIdentifier(memberName))
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME);
            }

            prototype.AddMember(processor, new PrototypeMember(memberName, defaultValue, isStatic, isReadOnly, isIndexerGet, isIndexerSet));

            return(processor.Undefined);
        }