Represents an object from which other objects can be created.
Inheritance: SProtoObject
Exemplo n.º 1
0
 /// <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);
 }
Exemplo n.º 2
0
 internal void AddPrototype(Prototype prototype)
 {
     if (_prototypes.ContainsKey(prototype.Name))
         _prototypes[prototype.Name] = prototype;
     else
         _prototypes.Add(prototype.Name, prototype);
 }
Exemplo n.º 3
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);
        }
Exemplo n.º 4
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);
            }
        }
Exemplo n.º 5
0
        internal static Prototype TranslatePrototype(ScriptProcessor processor, Type t)
        {
            var name = t.Name;
            var customNameAttribute = t.GetCustomAttribute<ScriptPrototypeAttribute>();
            if (!string.IsNullOrWhiteSpace(customNameAttribute?.VariableName))
                name = customNameAttribute.VariableName;

            var prototype = new Prototype(name);

            object typeInstance = null;
            if (!t.IsAbstract)
            {
                typeInstance = Activator.CreateInstance(t);
            }

            var fields = t
                .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
                .Where(f => f.GetCustomAttribute<CompilerGeneratedAttribute>() == null)
                .ToArray();

            foreach (var field in fields)
            {
                var attributes = field.GetCustomAttributes(false);

                foreach (var attr in attributes)
                {
                    if (attr.GetType() == typeof(ScriptVariableAttribute))
                    {
                        var memberAttr = (ScriptMemberAttribute)attr;
                        var identifier = field.Name;
                        if (!string.IsNullOrEmpty(memberAttr.VariableName))
                            identifier = memberAttr.VariableName;

                        var fieldContent = field.GetValue(typeInstance);

                        if (fieldContent == null)
                            prototype.AddMember(processor, new PrototypeMember(identifier, processor.Undefined, field.IsStatic, field.IsInitOnly, false, false));
                        else
                            prototype.AddMember(processor, new PrototypeMember(identifier, Translate(processor, fieldContent), field.IsStatic, field.IsInitOnly, false, false));
                    }
                    else if (attr.GetType() == typeof(ScriptFunctionAttribute))
                    {
                        var memberAttr = (ScriptFunctionAttribute)attr;
                        var identifier = field.Name;
                        if (!string.IsNullOrEmpty(memberAttr.VariableName))
                            identifier = memberAttr.VariableName;

                        var fieldContent = field.GetValue(typeInstance);

                        if (fieldContent == null)
                        {
                            if (memberAttr.FunctionType != ScriptFunctionType.Standard)
                                throw new InvalidOperationException("A member function marked with Indexer Set, Indexer Get or Constructor has to be defined.");

                            prototype.AddMember(processor, new PrototypeMember(identifier, processor.Undefined, field.IsStatic, field.IsInitOnly, false, false));
                        }
                        else
                        {
                            switch (memberAttr.FunctionType)
                            {
                                case ScriptFunctionType.Standard:
                                    prototype.AddMember(processor, new PrototypeMember(identifier, new SFunction(processor, fieldContent.ToString()), field.IsStatic, field.IsInitOnly, false, false));
                                    break;
                                case ScriptFunctionType.IndexerGet:
                                    prototype.IndexerGetFunction = new SFunction(processor, fieldContent.ToString());
                                    break;
                                case ScriptFunctionType.IndexerSet:
                                    prototype.IndexerSetFunction = new SFunction(processor, fieldContent.ToString());
                                    break;
                                case ScriptFunctionType.Constructor:
                                    prototype.Constructor = new PrototypeMember(Prototype.CLASS_METHOD_CTOR, new SFunction(processor, fieldContent.ToString()), false, true, false, false);
                                    break;
                            }
                        }
                    }
                }
            }

            var methods = t
                .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
                .Where(f => f.GetCustomAttribute<CompilerGeneratedAttribute>() == null)
                .ToArray();

            foreach (var method in methods)
            {
                var attr = method.GetCustomAttribute<ScriptFunctionAttribute>(false);
                if (attr != null)
                {
                    var identifier = method.Name;
                    if (!string.IsNullOrEmpty(attr.VariableName))
                        identifier = attr.VariableName;

                    if (attr.FunctionType == ScriptFunctionType.Getter)
                        identifier = SProtoObject.PROPERTY_GET_PREFIX + identifier;
                    if (attr.FunctionType == ScriptFunctionType.Setter)
                        identifier = SProtoObject.PROPERTY_SET_PREFIX + identifier;

                    Delegate methodDelegate = null;

                    if (method.GetParameters().Length == 3)
                    {
                        // two parameter means the method is a DotNetBuiltInMethod.
                        methodDelegate = (DotNetBuiltInMethod)Delegate.CreateDelegate(typeof(DotNetBuiltInMethod), method);
                    }
                    else if (method.GetParameters().Length == 4)
                    {
                        // four parameters means that the method is a valid BuiltInMethod.
                        methodDelegate = (BuiltInMethod)Delegate.CreateDelegate(typeof(BuiltInMethod), method);
                    }

                    switch (attr.FunctionType)
                    {
                        case ScriptFunctionType.Standard:
                        case ScriptFunctionType.Getter:
                        case ScriptFunctionType.Setter:
                            prototype.AddMember(processor, new PrototypeMember(identifier, new SFunction(methodDelegate), attr.IsStatic, true, false, false));
                            break;
                        case ScriptFunctionType.IndexerGet:
                            prototype.IndexerGetFunction = new SFunction(methodDelegate);
                            break;
                        case ScriptFunctionType.IndexerSet:
                            prototype.IndexerSetFunction = new SFunction(methodDelegate);
                            break;
                        case ScriptFunctionType.Constructor:
                            prototype.Constructor = new PrototypeMember(Prototype.CLASS_METHOD_CTOR, new SFunction(methodDelegate), false, true, false, false);
                            break;
                    }
                }
            }

            prototype.MappedType = t;

            return prototype;
        }