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 + "."); }
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); }
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); } }
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; }
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); } }
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); }
private ResolvedType(ResolvedTypeCategory category) { this.Category = category; this.id = idAlloc++; }
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); }
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); }
internal ResolvedType(TypeContext ctx, ResolvedTypeCategory category) { this.ctx = ctx; this.Category = category; this.id = ctx.GetNextId(); }