Example #1
0
 /// <summary>
 /// Creates a new container, consuming the provided builder.
 /// </summary>
 /// <param name="builder"></param>
 public Container(ContainerBuilder builder)
 {
     ContainerScope  = new Scoped(this);
     Registrations   = builder.Registrations;
     Settings        = builder.Settings;
     DependencyGraph = new ResolverPipeline(builder.Registrations, ContainerScope, Settings, null);
 }
Example #2
0
        internal override Expression ResolveEntityNames(ParserContext parser)
        {
            if (this.Name == "$var")
            {
                return(new CompileTimeDictionary(this.FirstToken, "var", this.Owner));
            }

            if (this.Name == "$$$")
            {
                throw new ParserException(this, "Core function invocations cannot stand alone and must be immediately invoked.");
            }

            NamespaceReferenceTemplate nrt = this.Owner.FileScope.FileScopeEntityLookup.DoNamespaceLookup(this.Name, this.TopLevelEntity);

            if (nrt != null)
            {
                return(new NamespaceReference(this.FirstToken, this.Owner, nrt));
            }

            TopLevelEntity exec = this.Owner.FileScope.FileScopeEntityLookup.DoEntityLookup(this.Name, this.Owner);

            if (exec != null)
            {
                if (!(this.Owner is ICodeContainer && ((ICodeContainer)this.Owner).ArgumentNameLookup.Contains(this.Name)))
                {
                    return(ResolverPipeline.ConvertStaticReferenceToExpression(exec, this.FirstToken, this.Owner));
                }
            }

            return(this);
        }
Example #3
0
 /// <summary>
 /// Creates a new child container using the provided builder.
 /// </summary>
 /// <param name="parentContainer"></param>
 /// <param name="builder"></param>
 private Container(Container parentContainer, ContainerBuilder builder)
 {
     Settings         = parentContainer.Settings;
     _parentContainer = parentContainer;
     ContainerScope   = new Scoped(this);
     Registrations    = builder.Registrations;
     DependencyGraph  = new ResolverPipeline(builder.Registrations, ContainerScope, Settings, parentContainer.DependencyGraph);
 }
Example #4
0
        /// <summary>
        /// Creates a new container using the provided builder.
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="options"></param>
        public Container(Action <ContainerBuilder>?builder = null, SingularitySettings?options = null)
        {
            var context = new ContainerBuilder(this);

            builder?.Invoke(context);
            _options         = options ?? SingularitySettings.Default;
            _containerScope  = new Scoped(this);
            Registrations    = context.Registrations;
            _dependencyGraph = new ResolverPipeline(context.Registrations, _containerScope, _options, null);
        }
Example #5
0
        private Container(Container parentContainer, Action <ContainerBuilder>?builder)
        {
            var context = new ContainerBuilder(this);

            builder?.Invoke(context);
            _parentContainer = parentContainer;
            _options         = parentContainer._options;
            _containerScope  = new Scoped(this);
            Registrations    = context.Registrations;
            _dependencyGraph = new ResolverPipeline(context.Registrations, _containerScope, _options, parentContainer._dependencyGraph);
        }
Example #6
0
        public TopLevelConstruct[] ParseAllTheThings()
        {
            Dictionary <string, string> files = this.GetCodeFiles();

            // When a syntax error is encountered, add it to this list (RELEASE builds only).
            // Only allow one syntax error per file. Libraries are considered stable and will
            // only report the first error in the event that an error occurs (since they get
            // parsed along with the file that imports it and so it's considered an error from
            // the importing file).
            List <ParserException> parseErrors = new List <ParserException>();

            // Only iterate through actual user files. Library imports will be inserted into the code when encountered
            // the first time for each library.
            foreach (string fileName in files.Keys)
            {
                string code = files[fileName];
#if DEBUG
                this.ParseInterpretedCode(fileName, code);
#else
                try
                {
                    this.ParseInterpretedCode(fileName, code);
                }
                catch (ParserException pe)
                {
                    parseErrors.Add(pe);
                }
#endif
            }

            if (parseErrors.Count > 0)
            {
                throw new MultiParserException(parseErrors);
            }

            return(ResolverPipeline.Resolve(this, this.compilationScopes.Values));
        }
Example #7
0
        internal override Expression ResolveEntityNames(
            ParserContext parser)
        {
            FunctionDefinition funcDef; // used in multiple places.
            FieldDefinition    fieldDec;

            this.Root = this.Root.ResolveEntityNames(parser);
            Expression root  = this.Root;
            string     field = this.FieldToken.Value;

            if (root is NamespaceReference)
            {
                // already a fully qualified namespace, therefore imports don't matter.
                string         fullyQualifiedName = ((NamespaceReference)root).Template.Name + "." + field;
                TopLevelEntity entity             = this.Owner.FileScope.FileScopeEntityLookup.DoEntityLookup(fullyQualifiedName, parser.CurrentCodeContainer);
                if (entity != null)
                {
                    return(ResolverPipeline.ConvertStaticReferenceToExpression(entity, this.FirstToken, this.Owner));
                }

                NamespaceReferenceTemplate nrt = this.Owner.FileScope.FileScopeEntityLookup.DoNamespaceLookup(fullyQualifiedName, parser.CurrentCodeContainer);
                if (nrt != null)
                {
                    return(new NamespaceReference(this.FirstToken, this.Owner, nrt));
                }

                throw new ParserException(this, "Could not find class or function by the name of: '" + fullyQualifiedName + "'");
            }

            if (root is ClassReference)
            {
                ClassDefinition cd = ((ClassReference)root).ClassDefinition;

                funcDef = cd.GetMethod(field, false);
                if (funcDef != null)
                {
                    if (!funcDef.Modifiers.HasStatic)
                    {
                        string className    = cd.NameToken.Value;
                        string functionName = funcDef.NameToken.Value;

                        throw new ParserException(this.DotToken, "'" + className + "." + functionName + "' is not a static method, but it is being used as though it is static.");
                    }

                    Node.EnsureAccessIsAllowed(this.FieldToken, this.Owner, funcDef);

                    return(new FunctionReference(this.FirstToken, funcDef, this.Owner));
                }

                fieldDec = cd.GetField(field, false);
                if (fieldDec != null)
                {
                    if (!fieldDec.Modifiers.HasStatic)
                    {
                        throw new ParserException(this.DotToken, "Cannot make a static reference to a non-static field.");
                    }

                    Node.EnsureAccessIsAllowed(this.FieldToken, this.Owner, fieldDec);

                    return(new FieldReference(this.FirstToken, fieldDec, this.Owner));
                }

                // TODO: typeof(class name) is less error prone with localization conflicts.
                // However there's a Core.typeOf() method that sort of conflicts.
                // TODO: if this notation is kept, then this needs to be split into two class keywords
                // since they do different things.
                if (field == parser.Keywords.CLASS)
                {
                    return(new ClassReferenceLiteral(this.FirstToken, cd, this.Owner));
                }

                // TODO: nested classes, enums, constants

                // TODO: show spelling suggestions.
                throw new ParserException(this.FieldToken, "No static fields or methods named '" + field + "' on the class " + cd.NameToken.Value + ".");
            }

            if (root is BaseKeyword)
            {
                ClassDefinition thisClass = null;
                if (this.Owner != null)
                {
                    if (this.Owner is FunctionDefinition)
                    {
                        thisClass = this.Owner.Owner as ClassDefinition;
                    }
                    else
                    {
                        thisClass = this.Owner as ClassDefinition;
                    }
                }

                if (thisClass == null)
                {
                    throw new ParserException(root, "'base' keyword can only be used inside classes.");
                }

                ClassDefinition cd = thisClass.BaseClass;
                if (cd == null)
                {
                    throw new ParserException(root, "'base' keyword can only be used inside classes that extend from another class.");
                }

                FunctionDefinition fd = cd.GetMethod(field, true);
                if (fd == null)
                {
                    throw new ParserException(this.DotToken, "Cannot find a method by that name in the base class chain.");
                }

                if (fd.Modifiers.HasStatic)
                {
                    throw new ParserException(this.DotToken, "Cannot reference static methods using 'base' keyword.");
                }

                Node.EnsureAccessIsAllowed(this.DotToken, this.Owner, fd);

                return(new BaseMethodReference(this.FirstToken, this.DotToken, this.FieldToken, this.Owner));
            }

            if (root is ThisKeyword)
            {
                ClassDefinition cd    = null;
                TopLevelEntity  owner = this.TopLevelEntity;
                if (owner is FunctionDefinition)
                {
                    FunctionDefinition functionOwner = (FunctionDefinition)owner;
                    if (functionOwner.Modifiers.HasStatic)
                    {
                        throw new ParserException(this.Root, "'this' keyword cannot be used in static methods.");
                    }

                    if (!(functionOwner.Owner is ClassDefinition))
                    {
                        throw new ParserException(this.Root, "'this' keyword cannot be used in a function that isn't in a class.");
                    }

                    cd = (ClassDefinition)owner.Owner;
                }
                else if (owner is FieldDefinition)
                {
                    if (((FieldDefinition)owner).Modifiers.HasStatic)
                    {
                        throw new ParserException(this.Root, "'this' keyword cannot be used in static fields.");
                    }
                    cd = (ClassDefinition)owner.Owner;
                }
                else if (owner is ConstructorDefinition)
                {
                    if (((ConstructorDefinition)owner).Modifiers.HasStatic)
                    {
                        throw new ParserException(this.Root, "'this', keyword cannot be used in static constructors.");
                    }
                    cd = (ClassDefinition)owner.Owner;
                }
                else
                {
                    throw new ParserException(this.Root, "'this' keyword must be used inside a class.");
                }

                funcDef = cd.GetMethod(field, true);
                if (funcDef != null)
                {
                    if (funcDef.Modifiers.HasStatic)
                    {
                        throw new ParserException(this.DotToken, "This method is static and must be referenced by the class name, not 'this'.");
                    }
                    Node.EnsureAccessIsAllowed(this.DotToken, this.Owner, funcDef);
                    return(new FunctionReference(this.FirstToken, funcDef, this.Owner));
                }

                FieldDefinition fieldDef = cd.GetField(field, true);
                if (fieldDef != null)
                {
                    if (fieldDef.Modifiers.HasStatic)
                    {
                        throw new ParserException(this.DotToken, "This field is static and must be referenced by the class name, not 'this'.");
                    }
                    Node.EnsureAccessIsAllowed(this.DotToken, this.Owner, fieldDef);

                    return(new FieldReference(this.FirstToken, fieldDef, this.Owner));
                }

                // TODO: show suggestions in the error message for anything close to what was typed.
                throw new ParserException(this.FieldToken, "The class '" + cd.NameToken.Value + "' does not have a field named '" + field + "'.");
            }

            if (this.Root is EnumReference)
            {
                EnumDefinition enumDef = ((EnumReference)this.Root).EnumDefinition;

                if (field == parser.Keywords.FIELD_ENUM_LENGTH)
                {
                    return(new IntegerConstant(this.FirstToken, enumDef.Items.Length, this.Owner));
                }
                if (field == parser.Keywords.FIELD_ENUM_MAX)
                {
                    return(new SpecialEntity.EnumMaxFunction(this.FirstToken, enumDef, this.Owner));
                }
                if (field == parser.Keywords.FIELD_ENUM_VALUES)
                {
                    return(new SpecialEntity.EnumValuesFunction(this.FirstToken, enumDef, this.Owner));
                }

                return(new EnumFieldReference(this.FirstToken, enumDef, this.FieldToken, this.Owner));
            }

            // This is done here in the resolver instead of the parser because some unallowed
            // field names (such as .class) are valid.
            if (field == parser.Keywords.CLASS)
            {
                if (this.Root is Variable)
                {
                    throw new ParserException(this.Root, "'" + ((Variable)this.Root).Name + "' is not a class.");
                }
                throw new ParserException(this.DotToken, ".class can only be applied to class names.");
            }
            parser.VerifyIdentifier(this.FieldToken);

            return(this);
        }
Example #8
0
        internal override Expression ResolveNames(
            ParserContext parser)
        {
            FunctionDefinition funcDef; // used in multiple places.
            FieldDeclaration   fieldDec;

            this.Root = this.Root.ResolveNames(parser);
            Expression root  = this.Root;
            string     field = this.StepToken.Value;

            if (root is NamespaceReference)
            {
                // already a fully qualified namespace, therefore imports don't matter.
                string            fullyQualifiedName = ((NamespaceReference)root).Template.Name + "." + field;
                TopLevelConstruct entity             = this.Owner.FileScope.FileScopeEntityLookup.DoEntityLookup(fullyQualifiedName, parser.CurrentCodeContainer);
                if (entity != null)
                {
                    return(ResolverPipeline.ConvertStaticReferenceToExpression(entity, this.FirstToken, this.Owner));
                }

                NamespaceReferenceTemplate nrt = this.Owner.FileScope.FileScopeEntityLookup.DoNamespaceLookup(fullyQualifiedName, parser.CurrentCodeContainer);
                if (nrt != null)
                {
                    return(new NamespaceReference(this.FirstToken, this.Owner, nrt));
                }

                throw new ParserException(this.FirstToken, "Could not find class or function by the name of: '" + fullyQualifiedName + "'");
            }

            if (root is ClassReference)
            {
                ClassDefinition cd = ((ClassReference)root).ClassDefinition;

                funcDef = cd.GetMethod(field, false);
                if (funcDef != null)
                {
                    if (!funcDef.IsStaticMethod)
                    {
                        string className    = cd.NameToken.Value;
                        string functionName = funcDef.NameToken.Value;

                        throw new ParserException(this.DotToken, "'" + className + "." + functionName + "' is not a static method, but it is being used as though it is static.");
                    }

                    return(new FunctionReference(this.FirstToken, funcDef, this.Owner));
                }

                fieldDec = cd.GetField(field, false);
                if (fieldDec != null)
                {
                    if (!fieldDec.IsStaticField)
                    {
                        throw new ParserException(this.DotToken, "Cannot make a static reference to a non-static field.");
                    }

                    return(new FieldReference(this.FirstToken, fieldDec, this.Owner));
                }

                if (field == "class")
                {
                    return(new ClassReferenceLiteral(this.FirstToken, cd, this.Owner));
                }

                // TODO: nested classes, enums, constants

                // TODO: show spelling suggestions.
                throw new ParserException(this.StepToken, "No static fields or methods named '" + field + "' on the class " + cd.NameToken.Value + ".");
            }

            if (root is BaseKeyword)
            {
                ClassDefinition thisClass = null;
                if (this.Owner != null)
                {
                    if (this.Owner is FunctionDefinition)
                    {
                        thisClass = this.Owner.Owner as ClassDefinition;
                    }
                    else
                    {
                        thisClass = this.Owner as ClassDefinition;
                    }
                }

                if (thisClass == null)
                {
                    throw new ParserException(root.FirstToken, "'base' keyword can only be used inside classes.");
                }

                ClassDefinition cd = thisClass.BaseClass;
                if (cd == null)
                {
                    throw new ParserException(root.FirstToken, "'base' keyword can only be used inside classes that extend from another class.");
                }

                FunctionDefinition fd = cd.GetMethod(field, true);
                if (fd == null)
                {
                    throw new ParserException(this.DotToken, "Cannot find a method by that name in the base class chain.");
                }

                if (fd.IsStaticMethod)
                {
                    throw new ParserException(this.DotToken, "Cannot reference static methods using 'base' keyword.");
                }

                return(new BaseMethodReference(this.FirstToken, this.DotToken, this.StepToken, this.Owner));
            }

            if (root is ThisKeyword)
            {
                ClassDefinition cd = null;
                if (this.Owner != null)
                {
                    if (this.Owner is FunctionDefinition)
                    {
                        funcDef = this.Owner as FunctionDefinition;
                        if (funcDef.IsStaticMethod)
                        {
                            throw new ParserException(this.Root.FirstToken, "'this' keyword cannot be used in static methods.");
                        }
                        cd = funcDef.Owner as ClassDefinition;
                        if (cd == null)
                        {
                            throw new ParserException(this.Root.FirstToken, "'this' keyword must be used inside a class.");
                        }
                    }
                    else if (this.Owner is ClassDefinition)
                    {
                        cd = (ClassDefinition)this.Owner;
                    }
                }

                if (cd == null)
                {
                    throw new ParserException(this.Root.FirstToken, "'this' keyword is not allowed here.");
                }

                funcDef = cd.GetMethod(field, true);
                if (funcDef != null)
                {
                    if (funcDef.IsStaticMethod)
                    {
                        throw new ParserException(this.DotToken, "This method is static and must be referenced by the class name, not 'this'.");
                    }
                    return(new FunctionReference(this.FirstToken, funcDef, this.Owner));
                }

                FieldDeclaration fieldDef = cd.GetField(field, true);
                if (fieldDef != null)
                {
                    if (fieldDef.IsStaticField)
                    {
                        throw new ParserException(this.DotToken, "This field is static and must be referenced by the class name, not 'this'.");
                    }

                    return(new FieldReference(this.FirstToken, fieldDef, this.Owner));
                }

                // TODO: show suggestions in the error message for anything close to what was typed.
                throw new ParserException(this.StepToken, "The class '" + cd.NameToken.Value + "' does not have a field named '" + field + "'.");
            }

            // This is done here in the resolver instead of the parser because some unallowed
            // field names (such as .class) are valid.
            if (this.StepToken.Value == parser.Keywords.CLASS)
            {
                if (this.Root is Variable)
                {
                    throw new ParserException(this.Root.FirstToken, "'" + ((Variable)this.Root).Name + "' is not a class.");
                }
                throw new ParserException(this.DotToken, ".class can only be applied to class names.");
            }
            parser.VerifyIdentifier(this.StepToken);

            return(this);
        }