コード例 #1
0
ファイル: Lambda.cs プロジェクト: djlw78/crayon
        internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver)
        {
            int argCount = this.ArgTypes.Length;

            this.ResolvedArgTypes = new ResolvedType[argCount];
            for (int i = 0; i < argCount; ++i)
            {
                ResolvedType argType = typeResolver.ResolveType(this.ArgTypes[i]);
                this.ResolvedArgTypes[i] = argType;

                // TODO: this variableId will not always be non-null when the argument in a lambda is used by a
                // closure of another lambda inside the lambda. I'll have to change my strategy here. Possibly
                // tracking the VariableId's as another Args field.
                VariableId variableId = this.VariableScope.GetVarId(this.Args[i]);
                variableId.ResolvedType = argType;
            }

            foreach (Executable ex in this.Code)
            {
                ex.ResolveTypes(parser, typeResolver);
            }

            // TODO: how do you define the lambda return type in Acrylic? Snoop the nested returns, maybe?
            ResolvedType returnType = ResolvedType.ANY;

            this.ResolvedType = ResolvedType.GetFunctionType(returnType, this.ResolvedArgTypes, 0);

            return(this);
        }
コード例 #2
0
        internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver)
        {
            ResolvedType returnType = this.FunctionDefinition.ResolvedReturnType;

            ResolvedType[] argTypes      = this.FunctionDefinition.ResolvedArgTypes;
            int            optionalCount = argTypes.Length == 0 || this.FunctionDefinition.DefaultValues[argTypes.Length - 1] == null
                ? 0
                : this.FunctionDefinition.DefaultValues.Where(e => e != null).Count();

            this.ResolvedType = ResolvedType.GetFunctionType(returnType, argTypes, optionalCount);
            return(this);
        }
コード例 #3
0
 internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver)
 {
     this.ResolvedType = ResolvedType.GetFunctionType(this.FunctionDefinition);
     return(this);
 }
コード例 #4
0
ファイル: DotField.cs プロジェクト: djlw78/crayon
 private Expression BuildPrimitiveMethodWithOptionalArgs(ResolvedType returnType, int optionalCount, params ResolvedType[] argTypes)
 {
     return(new PrimitiveMethodReference(this.Root, this.DotToken, this.FieldToken, ResolvedType.GetFunctionType(returnType, argTypes, optionalCount), this.Owner));
 }
コード例 #5
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.");
            }
        }