コード例 #1
0
ファイル: TypeResolver.cs プロジェクト: jimjag/crayon
        public ResolvedType ResolveType(AType type)
        {
            if (type.IsAnyType)
            {
                return(this.typeContext.ANY);
            }

            switch (type.RootType)
            {
            case "void": return(this.typeContext.VOID);

            case "int": return(this.typeContext.INTEGER);

            case "bool": return(this.typeContext.BOOLEAN);

            case "float": return(this.typeContext.FLOAT);

            case "string": return(this.typeContext.STRING);

            case "object": return(this.typeContext.OBJECT);

            case "[":
            case "List":
                if (type.Generics.Length != 1)
                {
                    throw new ParserException(type.FirstToken, "A list type has 1 generic.");
                }
                return(ResolvedType.ListOrArrayOf(ResolveType(type.Generics[0])));

            case "Dictionary":
                if (type.Generics.Length != 2)
                {
                    throw new ParserException(type.FirstToken, "A dictionary type has 2 generics.");
                }
                ResolvedType keyType   = ResolveType(type.Generics[0]);
                ResolvedType valueType = ResolveType(type.Generics[1]);
                switch (keyType.Category)
                {
                case ResolvedTypeCategory.INSTANCE:
                case ResolvedTypeCategory.INTEGER:
                case ResolvedTypeCategory.STRING:
                    // This is fine.
                    break;

                default:
                    throw new ParserException(type.Generics[0].FirstToken, "This is not a valid key type for a dictionary.");
                }
                return(ResolvedType.GetDictionaryType(keyType, valueType));

            default:
                ClassDefinition classDef = this.owner.FileScope.DoClassLookup(this.owner, type.FirstToken, type.RootType);
                return(ResolvedType.GetInstanceType(this.typeContext, classDef));
            }
        }
コード例 #2
0
        internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver)
        {
            ResolvedType itemType = typeResolver.ResolveType(this.ListType);

            this.ResolvedType = ResolvedType.ListOrArrayOf(itemType);
            for (int i = 0; i < this.Items.Length; ++i)
            {
                this.Items[i] = this.Items[i].ResolveTypes(parser, typeResolver);
                if (!this.Items[i].ResolvedType.CanAssignToA(itemType))
                {
                    throw new ParserException(this.Items[i], "This item cannot exist in a list of this type.");
                }
            }

            return(this);
        }
コード例 #3
0
ファイル: SpecialEntity.cs プロジェクト: djlw78/crayon
 internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver)
 {
     this.ResolvedType = ResolvedType.ListOrArrayOf(ResolvedType.ANY);
     return(this);
 }
コード例 #4
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.");
            }
        }