private void CheckZero(Expression expr) { bool isZero = false; if (expr is IntegerConstant) { isZero = ((IntegerConstant)expr).Value == 0; } else { isZero = FloatUtil.FloatAbsoluteEqualsNoEpislon(((FloatConstant)expr).Value, 0); } if (isZero) { throw new ParserException(expr, "Division by 0 error."); } }
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); }