Ejemplo n.º 1
0
        internal override Expression ResolveNames(Parser parser, System.Collections.Generic.Dictionary <string, Executable> lookup, string[] imports)
        {
            FunctionDefinition funcDef; // used in multiple places.
            FieldDeclaration   fieldDec;

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

            if (root is PartialNamespaceReference)
            {
                // already a fully qualified namespace, therefore imports don't matter.
                string fullyQualifiedName = ((PartialNamespaceReference)root).Name + "." + field;
                if (lookup.ContainsKey(fullyQualifiedName))
                {
                    return(Resolver.ConvertStaticReferenceToExpression(lookup[fullyQualifiedName], this.FirstToken, this.FunctionOrClassOwner));
                }

                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.FunctionOrClassOwner));
                }

                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.FunctionOrClassOwner));
                }

                // 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.FunctionOrClassOwner != null)
                {
                    if (this.FunctionOrClassOwner is FunctionDefinition)
                    {
                        thisClass = this.FunctionOrClassOwner.FunctionOrClassOwner as ClassDefinition;
                    }
                    else
                    {
                        thisClass = this.FunctionOrClassOwner 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.FunctionOrClassOwner));
            }

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

                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.FunctionOrClassOwner));
                }

                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.FunctionOrClassOwner));
                }

                // 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 + "'.");
            }

            return(this);
        }
Ejemplo n.º 2
0
        internal override Expression ResolveNames(
            Parser 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 PartialNamespaceReference)
            {
                // already a fully qualified namespace, therefore imports don't matter.
                string            fullyQualifiedName = ((PartialNamespaceReference)root).Name + "." + field;
                TopLevelConstruct entity             = this.Owner.FileScope.FileScopeEntityLookup.DoLookup(fullyQualifiedName, parser.CurrentCodeContainer);
                if (entity != null)
                {
                    return(Resolver.ConvertStaticReferenceToExpression(entity, this.FirstToken, this.Owner));
                }

                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);
        }
Ejemplo n.º 3
0
        internal override Expression ResolveNames(Parser parser)
        {
            if (this.Name == "$$$")
            {
                throw new ParserException(this.FirstToken, "Core function invocations cannot stand alone and must be immediately invoked.");
            }

            if (this.Name.StartsWith("$$"))
            {
                return(new LibraryFunctionReference(this.FirstToken, this.Name.Substring(2), this.Owner));
            }

            if (this.Name == "this" || this.Name == "base")
            {
                TopLevelConstruct container = parser.CurrentCodeContainer;

                if (container is FunctionDefinition)
                {
                    FunctionDefinition funcDef = (FunctionDefinition)this.Owner;
                    if (funcDef.IsStaticMethod)
                    {
                        throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a static method");
                    }

                    if (funcDef.Owner == null)
                    {
                        throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a function that isn't a class method.");
                    }
                }

                if (container is FieldDeclaration)
                {
                    if (((FieldDeclaration)container).IsStaticField)
                    {
                        throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a static field value.");
                    }
                }

                if (container is ConstructorDefinition)
                {
                    ConstructorDefinition constructor = (ConstructorDefinition)container;
                    if (constructor == ((ClassDefinition)constructor.Owner).StaticConstructor) // TODO: This check is silly. Add an IsStatic field to ConstructorDefinition.
                    {
                        throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a static constructor.");
                    }
                }

                if (this.Name == "this")
                {
                    return(new ThisKeyword(this.FirstToken, this.Owner));
                }
                return(new BaseKeyword(this.FirstToken, this.Owner));
            }

            TopLevelConstruct exec = this.Owner.FileScope.FileScopeEntityLookup.DoLookup(this.Name, this.Owner);

            if (exec != null)
            {
                return(Resolver.ConvertStaticReferenceToExpression(exec, this.FirstToken, this.Owner));
            }

            return(this);
        }