示例#1
0
        internal override void EnsureModifierAndTypeSignatureConsistency()
        {
            bool            isStatic     = this.Modifiers.HasStatic;
            ClassDefinition classDef     = (ClassDefinition)this.Owner;
            ClassDefinition baseClass    = classDef.BaseClass;
            bool            hasBaseClass = baseClass != null;

            if (!isStatic && classDef.Modifiers.HasStatic && !this.IsDefault)
            {
                throw new ParserException(this, "Cannot have a non-static constructor in a static class.");
            }

            if (this.BaseToken != null)
            {
                if (isStatic)
                {
                    throw new ParserException(this.BaseToken, "Cannot invoke the base constructor from a static constructor.");
                }
                if (!hasBaseClass)
                {
                    throw new ParserException(this.BaseToken, "There is no base class for this constructor to invoke.");
                }
            }

            if (hasBaseClass && !Node.IsAccessAllowed(this, baseClass.Constructor))
            {
                throw new ParserException(this, "Cannot invoke the base constructor due to its access modifier.");
            }
        }
示例#2
0
        internal override Expression ResolveEntityNames(ParserContext parser)
        {
            this.BatchExpressionEntityNameResolver(parser, this.Args);
            // TODO: localize or create a dummy stub in Core
            if (this.Name == "List")
            {
                return(new ListDefinition(this.FirstToken, new List <Expression>(), this.Generics[0], this.Owner, false, null));
            }
            else if (this.Name == "Dictionary")
            {
                return(new DictionaryDefinition(
                           this.FirstToken,
                           this.Generics[0], this.Generics[1],
                           new List <Expression>(), new List <Expression>(),
                           this.Owner));
            }
            this.Class = this.FileScope.DoClassLookup(this.Owner, this.NameToken, this.Name);

            if (this.Class == null)
            {
                throw new ParserException(this, "No class named '" + this.Name + "'");
            }

            if (this.Class.Modifiers.HasStatic)
            {
                throw new ParserException(this, "Cannot instantiate a static class.");
            }

            Node.EnsureAccessIsAllowed(this.FirstToken, this.Owner, this.Class);
            if (!Node.IsAccessAllowed(this.Owner, this.Class.Constructor))
            {
                // TODO: word this better. Maybe just say "this class' constructor is marked as private/protected/etc"
                throw new ParserException(this.FirstToken, "This class' constructor's access modifier does not allow it to be constructed here.");
            }

            this.ConstructorReference = this.Class.Constructor;
            int  minArgCount = 0;
            int  maxArgCount = 0;
            bool isPrivate   = false;

            if (this.ConstructorReference != null)
            {
                minArgCount = this.ConstructorReference.MinArgCount;
                maxArgCount = this.ConstructorReference.MaxArgCount;
                isPrivate   = this.ConstructorReference.Annotations.IsPrivate();
            }

            if (isPrivate)
            {
                bool isValidUsage =
                    this.Class == this.Owner ||     // used in a field where the owner is the class directly
                    this.Class == this.Owner.Owner; // used in a function where the owner is the method whose owner is the class.

                if (!isValidUsage)
                {
                    throw new ParserException(this, "The constructor for " + this.Class.NameToken.Value + " is private and cannot be invoked from outside the class.");
                }
            }

            if (this.Args.Length < minArgCount ||
                this.Args.Length > maxArgCount)
            {
                string message = "This constructor has the wrong number of arguments. ";
                if (minArgCount == maxArgCount)
                {
                    message += "Expected " + minArgCount + " but found " + this.Args.Length;
                }
                else if (this.Args.Length < minArgCount)
                {
                    message += " At least " + minArgCount + " are required but found only " + this.Args.Length + ".";
                }
                else
                {
                    message += " At most " + maxArgCount + " are allowed but found " + this.Args.Length + ".";
                }
                throw new ParserException(this, message);
            }

            return(this);
        }
示例#3
0
文件: DotField.cs 项目: djlw78/crayon
        internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver)
        {
            this.Root.ResolveTypes(parser, typeResolver);

            string field = this.FieldToken.Value;

            if (this.Root is EnumReference)
            {
                throw new System.NotImplementedException();
            }

            ResolvedType rootType = this.Root.ResolvedType;

            // TODO: all of this needs to be localized.
            switch (rootType.Category)
            {
            case ResolvedTypeCategory.NULL:
                throw new ParserException(this.DotToken, "Cannot dereference a field from null.");

            case ResolvedTypeCategory.ANY:
                // ¯\_(ツ)_/¯
                this.ResolvedType = ResolvedType.ANY;
                return(this);

            case ResolvedTypeCategory.INTEGER:
                throw new ParserException(this.DotToken, "Integers do not have any fields.");

            case ResolvedTypeCategory.FLOAT:
                throw new ParserException(this.DotToken, "Floating point decimals do not have any fields.");

            case ResolvedTypeCategory.BOOLEAN:
                throw new ParserException(this.DotToken, "Booleans do not have any fields.");

            case ResolvedTypeCategory.STRING:
                switch (field)
                {
                case "length":
                    this.ResolvedType = ResolvedType.INTEGER;
                    if (this.Root is StringConstant)
                    {
                        return(new IntegerConstant(this.FirstToken, ((StringConstant)this.Root).Value.Length, this.Owner));
                    }
                    return(this);

                case "contains": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, ResolvedType.STRING));

                case "endsWith": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, ResolvedType.STRING));

                case "indexOf": return(BuildPrimitiveMethod(ResolvedType.INTEGER, ResolvedType.STRING));

                case "lower": return(BuildPrimitiveMethod(ResolvedType.STRING));

                case "ltrim": return(BuildPrimitiveMethod(ResolvedType.STRING));

                case "replace": return(BuildPrimitiveMethod(ResolvedType.STRING, ResolvedType.STRING, ResolvedType.STRING));

                case "reverse": return(BuildPrimitiveMethod(ResolvedType.STRING));

                case "rtrim": return(BuildPrimitiveMethod(ResolvedType.STRING));

                case "split": return(BuildPrimitiveMethod(ResolvedType.ListOrArrayOf(ResolvedType.STRING), ResolvedType.STRING));

                case "startsWith": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, ResolvedType.STRING));

                case "trim": return(BuildPrimitiveMethod(ResolvedType.STRING));

                case "upper": return(BuildPrimitiveMethod(ResolvedType.STRING));

                // common mistakes
                case "join":
                    throw new ParserException(this.DotToken, "Strings do not have a .join(list) method. Did you mean to do list.join(string)?");

                case "size":
                    throw new ParserException(this.DotToken, "Strings do not have a .size() method. Did you mean to use .length?");

                default:
                    throw new ParserException(this.DotToken, "Strings do not have that method.");
                }

            case ResolvedTypeCategory.LIST:
                ResolvedType itemType = rootType.ListItemType;
                switch (field)
                {
                case "length":
                    this.ResolvedType = ResolvedType.INTEGER;
                    return(this);

                case "filter":
                case "map":
                    if (this.CompilationScope.IsStaticallyTyped)
                    {
                        // TODO: for Acrylic, this needs to have a way to indicate that resolution should be attempted
                        // again once the function return type is known.
                        throw new System.NotImplementedException();
                    }
                    this.ResolvedType = ResolvedType.ANY;
                    return(this);

                case "add": return(BuildPrimitiveMethod(ResolvedType.VOID, itemType));

                case "choice": return(BuildPrimitiveMethod(ResolvedType.VOID));

                case "clear": return(BuildPrimitiveMethod(ResolvedType.VOID));

                case "clone": return(BuildPrimitiveMethod(rootType));

                case "concat": return(BuildPrimitiveMethod(rootType, rootType));

                case "contains": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, itemType));

                case "insert": return(BuildPrimitiveMethod(ResolvedType.VOID, ResolvedType.INTEGER, itemType));

                case "join": return(BuildPrimitiveMethodWithOptionalArgs(ResolvedType.STRING, 1, ResolvedType.STRING));

                case "pop": return(BuildPrimitiveMethod(itemType));

                case "remove": return(BuildPrimitiveMethod(ResolvedType.VOID, ResolvedType.INTEGER));

                case "reverse": return(BuildPrimitiveMethod(ResolvedType.VOID));

                case "shuffle": return(BuildPrimitiveMethod(ResolvedType.VOID));

                case "sort": return(BuildPrimitiveMethod(ResolvedType.VOID));

                // common mistakes
                case "count":
                case "size":
                    throw new ParserException(this.DotToken, "Lists do not have a ." + this.FieldToken.Value + "() method. Did you mean to use .length?");

                default:
                    throw new ParserException(this.DotToken, "Lists do not have that method.");
                }

            case ResolvedTypeCategory.DICTIONARY:
                ResolvedType keyType   = rootType.DictionaryKeyType;
                ResolvedType valueType = rootType.DictionaryValueType;
                switch (field)
                {
                case "length":
                    this.ResolvedType = ResolvedType.INTEGER;
                    return(this);

                case "clear": return(BuildPrimitiveMethod(ResolvedType.VOID));

                case "clone": return(BuildPrimitiveMethod(rootType));

                case "contains": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, keyType));

                case "get": return(BuildPrimitiveMethodWithOptionalArgs(valueType, 1, keyType, valueType));

                case "keys": return(BuildPrimitiveMethod(ResolvedType.ListOrArrayOf(keyType)));

                case "merge": return(BuildPrimitiveMethod(ResolvedType.VOID, rootType));

                case "remove": return(BuildPrimitiveMethod(ResolvedType.VOID, keyType));

                case "values": return(BuildPrimitiveMethod(ResolvedType.ListOrArrayOf(valueType)));

                default:
                    throw new ParserException(this.DotToken, "Dictionaries do not have that field.");
                }

            case ResolvedTypeCategory.CLASS_DEFINITION:
                throw new ParserException(this.DotToken, "Class definitions do not have that field.");

            case ResolvedTypeCategory.FUNCTION_POINTER:
                switch (field)
                {
                case "invoke":
                    return(BuildPrimitiveMethod(ResolvedType.ANY, ResolvedType.ListOrArrayOf(ResolvedType.ANY)));

                default:
                    throw new ParserException(this.DotToken, "Fucntions do not have that field.");
                }

            case ResolvedTypeCategory.INSTANCE:
                FieldDefinition fieldDef = rootType.ClassTypeOrReference.GetField(field, true);
                if (fieldDef != null)
                {
                    if (!Node.IsAccessAllowed(this, fieldDef))
                    {
                        ClassDefinition cd = fieldDef.ClassOwner;
                        throw new ParserException(FieldToken, "The field '" + cd.NameToken.Value + "." + this.FieldToken.Value + "' is not accessible from here due to its access scope.");
                    }

                    this.ResolvedType = fieldDef.ResolvedFieldType;
                    return(this);
                }
                FunctionDefinition funcDef = rootType.ClassTypeOrReference.GetMethod(field, true);
                if (funcDef != null)
                {
                    this.ResolvedType = ResolvedType.GetFunctionType(funcDef);
                    return(this);
                }
                throw new ParserException(this.DotToken, "The class '" + rootType.ClassTypeOrReference.NameToken.Value + "' does not have a field called '" + field + "'.");

            default:
                throw new ParserException(this.DotToken, "This field does not exist.");
            }
        }