Esempio n. 1
0
        private Expression TryConsolidate()
        {
            if (!(this.Left is IConstantValue && this.Right is IConstantValue))
            {
                return(this);
            }

            ResolvedType         leftType          = this.Left.ResolvedType;
            ResolvedType         rightType         = this.Right.ResolvedType;
            ResolvedTypeCategory leftTypeCategory  = leftType.Category;
            ResolvedTypeCategory rightTypeCategory = rightType.Category;

            if (leftType == ResolvedType.ANY || rightType == ResolvedType.ANY)
            {
                // This shouldn't be possible if it's already confirmed that the left and right inputs are constants.
                throw new Exception();
            }

            OperationType ot = GetOperation(leftTypeCategory, rightTypeCategory, this.OpToken.Value);

            if (ot != null && ot.CanDoConstantOperationAtRuntime)
            {
                return(ot.PerformOperation.Invoke(this));
            }

            throw new ParserException(this.OpToken, "This operator is invalid for types: " + leftType + ", " + rightType + ".");
        }
Esempio n. 2
0
        internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver)
        {
            TypeContext tc = parser.TypeContext;

            this.Root  = this.Root.ResolveTypes(parser, typeResolver);
            this.Index = this.Index.ResolveTypes(parser, typeResolver);
            ResolvedTypeCategory indexType = this.Index.ResolvedType.Category;

            switch (this.Root.ResolvedType.Category)
            {
            case ResolvedTypeCategory.ANY:
                this.ResolvedType = tc.ANY;
                switch (indexType)
                {
                case ResolvedTypeCategory.ANY:
                case ResolvedTypeCategory.INTEGER:
                case ResolvedTypeCategory.STRING:
                case ResolvedTypeCategory.INSTANCE:
                    // these are possibly fine
                    break;

                default:
                    throw new ParserException(this.Index, "Cannot use this value as an index.");
                }
                break;

            case ResolvedTypeCategory.LIST:
                this.ResolvedType = this.Root.ResolvedType.ListItemType;
                if (!this.Index.ResolvedType.CanAssignToA(tc.INTEGER))
                {
                    throw new ParserException(this.Index, "Can only index into a list with an integer.");
                }
                break;

            case ResolvedTypeCategory.DICTIONARY:
                this.ResolvedType = this.Root.ResolvedType.DictionaryValueType;
                if (!this.Index.ResolvedType.CanAssignToA(this.Root.ResolvedType.DictionaryKeyType))
                {
                    throw new ParserException(this.Index, "Cannot index into this dictionary with this type.");
                }
                break;

            case ResolvedTypeCategory.STRING:
                this.ResolvedType = tc.STRING;
                if (!this.Index.ResolvedType.CanAssignToA(tc.INTEGER))
                {
                    throw new ParserException(this.Index, "Can only index into a string with an integer.");
                }
                break;

            case ResolvedTypeCategory.INSTANCE:
                throw new ParserException(this.Index, "Cannot use brackets to index into an instance of " + this.Root.ResolvedType.ClassTypeOrReference.NameToken.Value + ".");

            default:
                throw new ParserException(this.Root, "Cannot index into this kind of value.");
            }
            return(this);
        }
Esempio n. 3
0
        internal override void ResolveTypes(ParserContext parser, TypeResolver typeResolver)
        {
            this.Value = this.Value.ResolveTypes(parser, typeResolver);
            if (this.type == AssignmentType.TYPED_VARIABLE_DECLARATION)
            {
                VariableId varId        = this.TargetAsVariable.VarId;
                AType      variableType = varId.Type;
                varId.ResolvedType = typeResolver.ResolveType(varId.Type);
            }
            else if (this.type == AssignmentType.VARIABLE && this.CompilationScope.IsCrayon)
            {
                VariableId varId = this.TargetAsVariable.VarId;
                if (varId.ResolvedType == null)
                {
                    varId.ResolvedType = parser.TypeContext.ANY;
                }
            }

            this.Target = this.Target.ResolveTypes(parser, typeResolver);

            // These are special cases that are valid:
            //   list *= num,
            //   string *= num,
            //   string += any non-null value
            ResolvedTypeCategory leftCategory  = this.Target.ResolvedType.Category;
            ResolvedTypeCategory rightCategory = this.Value.ResolvedType.Category;
            bool specialCase = false;

            if ((leftCategory == ResolvedTypeCategory.STRING || leftCategory == ResolvedTypeCategory.LIST) &&
                rightCategory == ResolvedTypeCategory.INTEGER &&
                this.Op == Ops.MULTIPLICATION)
            {
                specialCase = true;
            }
            else if (leftCategory == ResolvedTypeCategory.STRING && this.Op == Ops.ADDITION)
            {
                if (rightCategory != ResolvedTypeCategory.NULL)
                {
                    specialCase = true;
                }
            }

            if (!this.Target.CanAssignTo)
            {
                throw new ParserException(this.Target, "Cannot assign to this type of expression.");
            }

            if (!specialCase)
            {
                this.Value.ResolvedType.EnsureCanAssignToA(this.Value.FirstToken, this.Target.ResolvedType);
            }
        }
Esempio n. 4
0
 public OperationType(
     ResolvedTypeCategory leftType,
     ResolvedTypeCategory rightType,
     string op,
     ResolvedType outputType,
     Func <OpChain, Expression> constantOperation)
 {
     this.LeftType         = leftType;
     this.Op               = op;
     this.RightType        = rightType;
     this.OutputType       = outputType;
     this.PerformOperation = constantOperation;
 }
Esempio n. 5
0
        internal override void ResolveTypes(ParserContext parser, TypeResolver typeResolver)
        {
            this.Condition = this.Condition.ResolveTypes(parser, typeResolver);
            ResolvedTypeCategory type = this.Condition.ResolvedType.Category;

            if (type != ResolvedTypeCategory.BOOLEAN && type != ResolvedTypeCategory.ANY)
            {
                throw new ParserException(this.Condition, "Boolean expected.");
            }

            foreach (Executable ex in this.TrueCode.Concat(this.FalseCode))
            {
                ex.ResolveTypes(parser, typeResolver);
            }
        }
Esempio n. 6
0
        private static ResolvedType GetClassTypeImpl(ResolvedTypeCategory cat, ClassDefinition cd)
        {
            ResolvedType output;
            Dictionary <ClassDefinition, ResolvedType> lookup = cat == ResolvedTypeCategory.CLASS_DEFINITION
                ? classRefTypes
                : instanceTypes;

            if (!lookup.TryGetValue(cd, out output))
            {
                output = new ResolvedType(cat)
                {
                    ClassTypeOrReference = cd
                };
                lookup[cd] = output;
            }
            return(output);
        }
Esempio n. 7
0
 private ResolvedType(ResolvedTypeCategory category)
 {
     this.Category = category;
     this.id       = idAlloc++;
 }
Esempio n. 8
0
        public bool CanAssignToA(ResolvedType targetType)
        {
            if (this.Category == ResolvedTypeCategory.ANY)
            {
                return(true);
            }
            ResolvedTypeCategory targetCategory = targetType.Category;

            if (targetCategory == ResolvedTypeCategory.ANY)
            {
                return(true);
            }
            if (targetCategory == ResolvedTypeCategory.OBJECT)
            {
                return(true);
            }
            if (this.Category == ResolvedTypeCategory.NULL)
            {
                switch (targetCategory)
                {
                case ResolvedTypeCategory.INSTANCE:
                case ResolvedTypeCategory.CLASS_DEFINITION:
                case ResolvedTypeCategory.FUNCTION_POINTER:
                case ResolvedTypeCategory.STRING:
                case ResolvedTypeCategory.LIST:
                case ResolvedTypeCategory.DICTIONARY:
                    return(true);

                default:
                    return(false);
                }
            }

            if (this.Category == ResolvedTypeCategory.VOID)
            {
                return(false);
            }

            if (this.Category == ResolvedTypeCategory.INTEGER &&
                targetCategory == ResolvedTypeCategory.FLOAT)
            {
                return(true);
            }

            if (this.Category != targetCategory)
            {
                return(false);
            }

            if (targetCategory == ResolvedTypeCategory.INSTANCE)
            {
                ClassDefinition targetClass     = targetType.ClassTypeOrReference;
                ClassDefinition baseClassWalker = this.ClassTypeOrReference;
                while (baseClassWalker != null)
                {
                    if (baseClassWalker == targetClass)
                    {
                        return(true);
                    }
                    baseClassWalker = baseClassWalker.BaseClass;
                }
                return(false);
            }

            if (this.Category == ResolvedTypeCategory.LIST || this.Category == ResolvedTypeCategory.DICTIONARY)
            {
                for (int i = 0; i < this.Generics.Length; ++i)
                {
                    if (this.Generics[i] == targetType.Generics[i])
                    {
                    }
                    else if (this.Generics[i] == ANY && targetType.Generics[i] == OBJECT)
                    {
                    }
                    else
                    {
                        return(false);
                    }
                }
                return(true);
            }

            return(true);
        }
Esempio n. 9
0
        private OperationType GetOperation(
            ResolvedTypeCategory leftType,
            ResolvedTypeCategory rightType,
            string op)
        {
            if (consolidationLookup == null)
            {
                consolidationLookup = new Dictionary <string, Dictionary <ResolvedTypeCategory, Dictionary <ResolvedTypeCategory, OperationType> > >();

                OperationType[] operations = new OperationType[] {
                    new OperationType(ResolvedTypeCategory.NULL, ResolvedTypeCategory.NULL, "==", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, true)); }),
                    new OperationType(ResolvedTypeCategory.NULL, ResolvedTypeCategory.NULL, "!=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, false)); }),
                    new OperationType(ResolvedTypeCategory.BOOLEAN, ResolvedTypeCategory.BOOLEAN, "==", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetBool(opChain.Left) == GetBool(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.BOOLEAN, ResolvedTypeCategory.BOOLEAN, "!=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetBool(opChain.Left) != GetBool(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "&", ResolvedType.INTEGER, (opChain) => { return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) & GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "|", ResolvedType.INTEGER, (opChain) => { return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) | GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "^", ResolvedType.INTEGER, (opChain) => { return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) ^ GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "<<", ResolvedType.INTEGER, (opChain) =>
                    {
                        int right = GetInt(opChain.Right);
                        if (right < 0)
                        {
                            throw new ParserException(opChain.FirstToken, "Cannot bit shift by a negative number.");
                        }
                        return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) << right));
                    }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, ">>", ResolvedType.INTEGER, (opChain) =>
                    {
                        int right = GetInt(opChain.Right);
                        if (right < 0)
                        {
                            throw new ParserException(opChain.FirstToken, "Cannot bit shift by a negative number.");
                        }
                        return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) >> right));
                    }),

                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "+", ResolvedType.INTEGER, (opChain) => { return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) + GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "-", ResolvedType.INTEGER, (opChain) => { return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) - GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "*", ResolvedType.INTEGER, (opChain) => { return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) * GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "/", ResolvedType.INTEGER, (opChain) => { CheckZero(opChain.Right); return(MakeInt(opChain.FirstToken, GetInt(opChain.Left) / GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "%", ResolvedType.INTEGER, (opChain) => { return(MakeInt(opChain.FirstToken, PositiveModInt(opChain.Left, opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "<=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) <= GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, ">=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) >= GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "<", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) < GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, ">", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) > GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "==", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) == GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "!=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) != GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.INTEGER, "**", ResolvedType.FLOAT, (opChain) =>
                    {
                        int right = GetInt(opChain.Right);
                        int left  = GetInt(opChain.Left);
                        if (right == 0)
                        {
                            return(MakeFloat(opChain.FirstToken, 1.0));
                        }
                        return(MakeFloat(opChain.FirstToken, Math.Pow(left, right)));
                    }),

                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "+", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetInt(opChain.Left) + GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "-", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetInt(opChain.Left) - GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "*", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetInt(opChain.Left) * GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "/", ResolvedType.FLOAT, (opChain) => { CheckZero(opChain.Right); return(MakeFloat(opChain.FirstToken, GetInt(opChain.Left) / GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "%", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, PositiveModFloat(opChain.Left, opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "<=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) <= GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, ">=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) >= GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "<", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) < GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, ">", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) > GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "==", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) == GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "!=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetInt(opChain.Left) != GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.FLOAT, "**", ResolvedType.FLOAT, (opChain) =>
                    {
                        double right = GetFloat(opChain.Right);
                        int left     = GetInt(opChain.Left);
                        if (FloatUtil.FloatAbsoluteEqualsNoEpislon(right, 0))
                        {
                            return(MakeFloat(opChain.FirstToken, 1.0));
                        }
                        if (!FloatUtil.FloatAbsoluteEqualsNoEpislon(right % 1, 0) && left < 0)
                        {
                            throw new ParserException(opChain.OpToken, "Exponent creates a complex expression.");
                        }
                        return(MakeFloat(opChain.FirstToken, Math.Pow(left, right)));
                    }),

                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "+", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetFloat(opChain.Left) + GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "-", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetFloat(opChain.Left) - GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "*", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetFloat(opChain.Left) * GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "/", ResolvedType.FLOAT, (opChain) => { CheckZero(opChain.Right); return(MakeFloat(opChain.FirstToken, GetFloat(opChain.Left) / GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "%", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, PositiveModFloat(opChain.Left, opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "<=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) <= GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, ">=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) >= GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "<", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) < GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, ">", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) > GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "==", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) == GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "!=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) != GetInt(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.INTEGER, "**", ResolvedType.FLOAT, (opChain) =>
                    {
                        int right   = GetInt(opChain.Right);
                        double left = GetFloat(opChain.Left);
                        if (right == 0)
                        {
                            return(MakeFloat(opChain.FirstToken, 1.0));
                        }
                        return(MakeFloat(opChain.FirstToken, Math.Pow(left, right)));
                    }),

                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "+", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetFloat(opChain.Left) + GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "-", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetFloat(opChain.Left) - GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "*", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, GetFloat(opChain.Left) * GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "/", ResolvedType.FLOAT, (opChain) => { CheckZero(opChain.Right); return(MakeFloat(opChain.FirstToken, GetFloat(opChain.Left) / GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "%", ResolvedType.FLOAT, (opChain) => { return(MakeFloat(opChain.FirstToken, PositiveModFloat(opChain.Left, opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "<=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) <= GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, ">=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) >= GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "<", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) < GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, ">", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) > GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "==", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) == GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "!=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetFloat(opChain.Left) != GetFloat(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.FLOAT, "**", ResolvedType.FLOAT, (opChain) =>
                    {
                        double right = GetFloat(opChain.Right);
                        double left  = GetFloat(opChain.Left);
                        if (FloatUtil.FloatAbsoluteEqualsNoEpislon(right, 0))
                        {
                            return(MakeFloat(opChain.FirstToken, 1.0));
                        }
                        if (!FloatUtil.FloatAbsoluteEqualsNoEpislon(right % 1, 0) && left < 0)
                        {
                            throw new ParserException(opChain.OpToken, "Exponent creates a complex expression.");
                        }
                        return(MakeFloat(opChain.FirstToken, Math.Pow(left, right)));
                    }),

                    new OperationType(ResolvedTypeCategory.BOOLEAN, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, (opChain) => { return(MakeString(opChain.FirstToken, GetBool(opChain.Left).ToString() + GetString(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, (opChain) => { return(MakeString(opChain.FirstToken, GetInt(opChain.Left).ToString() + GetString(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.FLOAT, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, (opChain) => { return(MakeString(opChain.FirstToken, GetFloatAsString(opChain.Left) + GetString(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.BOOLEAN, "+", ResolvedType.STRING, (opChain) => { return(MakeString(opChain.FirstToken, GetString(opChain.Left) + GetBool(opChain.Right).ToString())); }),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.INTEGER, "+", ResolvedType.STRING, (opChain) => { return(MakeString(opChain.FirstToken, GetString(opChain.Left) + GetInt(opChain.Right).ToString())); }),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.FLOAT, "+", ResolvedType.STRING, (opChain) => { return(MakeString(opChain.FirstToken, GetString(opChain.Left) + GetFloatAsString(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, (opChain) => { return(MakeString(opChain.FirstToken, GetString(opChain.Left) + GetString(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.STRING, "==", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetString(opChain.Left) == GetString(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.STRING, "!=", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetString(opChain.Left) != GetString(opChain.Right))); }),

                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.INSTANCE, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.INSTANCE, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.CLASS_DEFINITION, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.CLASS_DEFINITION, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.FUNCTION_POINTER, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.FUNCTION_POINTER, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.LIST, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.LIST, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.DICTIONARY, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.DICTIONARY, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.OBJECT, "+", ResolvedType.STRING, null),
                    new OperationType(ResolvedTypeCategory.OBJECT, ResolvedTypeCategory.STRING, "+", ResolvedType.STRING, null),

                    new OperationType(ResolvedTypeCategory.BOOLEAN, ResolvedTypeCategory.BOOLEAN, "&&", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetBool(opChain.Left) && GetBool(opChain.Right))); }),
                    new OperationType(ResolvedTypeCategory.BOOLEAN, ResolvedTypeCategory.BOOLEAN, "||", ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, GetBool(opChain.Left) || GetBool(opChain.Right))); }),

                    new OperationType(ResolvedTypeCategory.INTEGER, ResolvedTypeCategory.STRING, "*", ResolvedType.STRING, (opChain) => { return(GenerateMultipliedStringIfNotTooLong(opChain, opChain.Left, opChain.Right)); }),
                    new OperationType(ResolvedTypeCategory.STRING, ResolvedTypeCategory.INTEGER, "*", ResolvedType.STRING, (opChain) => { return(GenerateMultipliedStringIfNotTooLong(opChain, opChain.Left, opChain.Right)); }),
                };

                foreach (OperationType ot in operations)
                {
                    if (!consolidationLookup.ContainsKey(ot.Op))
                    {
                        consolidationLookup[ot.Op] = new Dictionary <ResolvedTypeCategory, Dictionary <ResolvedTypeCategory, OperationType> >();
                    }
                    if (!consolidationLookup[ot.Op].ContainsKey(ot.LeftType))
                    {
                        consolidationLookup[ot.Op][ot.LeftType] = new Dictionary <ResolvedTypeCategory, OperationType>();
                    }
                    consolidationLookup[ot.Op][ot.LeftType].Add(ot.RightType, ot); // causes exception if duplicate
                }
            }

            // The op will always have some types registered, so you can dereference the first level of lookups without checking.
            Dictionary <ResolvedTypeCategory, Dictionary <ResolvedTypeCategory, OperationType> > l1 = consolidationLookup[op];

            if (l1.ContainsKey(leftType))
            {
                Dictionary <ResolvedTypeCategory, OperationType> l2 = l1[leftType];
                if (l2.ContainsKey(rightType))
                {
                    return(l2[rightType]);
                }
            }

            if (op == "==")
            {
                // == comparisons between different kinds of objects should resolve to false at compile time.
                // Lazily initialize these operation types as they are encountered.
                if (leftType != rightType &&
                    !(leftType == ResolvedTypeCategory.INTEGER && rightType == ResolvedTypeCategory.FLOAT) &&
                    !(leftType == ResolvedTypeCategory.FLOAT && rightType == ResolvedTypeCategory.INTEGER) &&
                    leftType != ResolvedTypeCategory.ANY &&
                    rightType != ResolvedTypeCategory.ANY &&
                    leftType != ResolvedTypeCategory.OBJECT &&
                    rightType != ResolvedTypeCategory.OBJECT)
                {
                    if (!consolidationLookup[op].ContainsKey(leftType))
                    {
                        consolidationLookup[op][leftType] = new Dictionary <ResolvedTypeCategory, OperationType>();
                    }
                    OperationType ot = new OperationType(leftType, rightType, op, ResolvedType.BOOLEAN, (opChain) => { return(MakeBool(opChain.FirstToken, false)); });
                    consolidationLookup[op][leftType][rightType] = ot;
                    return(ot);
                }
            }

            return(null);
        }
Esempio n. 10
0
 internal ResolvedType(TypeContext ctx, ResolvedTypeCategory category)
 {
     this.ctx      = ctx;
     this.Category = category;
     this.id       = ctx.GetNextId();
 }