private static bool MergeModulus(ExpressionBase left, ExpressionBase right, out ExpressionBase result) { // if either side is a float, convert both to float if (left.Type == ExpressionType.FloatConstant || right.Type == ExpressionType.FloatConstant) { if (!ConvertToFloat(ref left, ref right, out result)) { return(false); } if (((FloatConstantExpression)right).Value == 0.0) { result = new ParseErrorExpression("Division by zero"); return(false); } result = new FloatConstantExpression(((FloatConstantExpression)left).Value % ((FloatConstantExpression)right).Value); return(true); } if (left.Type == ExpressionType.IntegerConstant && right.Type == ExpressionType.IntegerConstant) { if (((IntegerConstantExpression)right).Value == 0) { result = new ParseErrorExpression("Division by zero"); return(false); } result = new IntegerConstantExpression(((IntegerConstantExpression)left).Value % ((IntegerConstantExpression)right).Value); return(true); } result = new ParseErrorExpression("Cannot modulus expressions"); return(false); }
private static bool MergeAddition(ExpressionBase left, ExpressionBase right, out ExpressionBase result) { // if either side is a string, combine to a larger string if (left.Type == ExpressionType.StringConstant || right.Type == ExpressionType.StringConstant) { var builder = new StringBuilder(); left.AppendStringLiteral(builder); right.AppendStringLiteral(builder); result = new StringConstantExpression(builder.ToString()); return(true); } // if either side is a float, convert both to float if (left.Type == ExpressionType.FloatConstant || right.Type == ExpressionType.FloatConstant) { if (!ConvertToFloat(ref left, ref right, out result)) { return(false); } result = new FloatConstantExpression(((FloatConstantExpression)left).Value + ((FloatConstantExpression)right).Value); return(true); } if (left.Type == ExpressionType.IntegerConstant && right.Type == ExpressionType.IntegerConstant) { result = new IntegerConstantExpression(((IntegerConstantExpression)left).Value + ((IntegerConstantExpression)right).Value); return(true); } result = new ParseErrorExpression("Cannot add expressions"); return(false); }
protected static bool ConvertToFloat(ref ExpressionBase left, ref ExpressionBase right, out ExpressionBase result) { left = FloatConstantExpression.ConvertFrom(left); if (left.Type != ExpressionType.FloatConstant) { result = left; return(false); } right = FloatConstantExpression.ConvertFrom(right); if (right.Type != ExpressionType.FloatConstant) { result = right; return(false); } result = null; return(true); }
private static bool IsMultiple(ExpressionBase left, ExpressionBase right) { var leftInteger = left as IntegerConstantExpression; var rightInteger = right as IntegerConstantExpression; if (leftInteger != null && rightInteger != null) { return((leftInteger.Value % rightInteger.Value) == 0); } var leftFloat = FloatConstantExpression.ConvertFrom(left) as FloatConstantExpression; var rightFloat = FloatConstantExpression.ConvertFrom(right) as FloatConstantExpression; if (leftFloat == null || rightFloat == null) { return(false); } return((leftFloat.Value % rightFloat.Value) == 0.0f); }
/// <summary> /// Attempts to convert an expression to a <see cref="FloatConstantExpression"/>. /// </summary> /// <param name="expression">The expression to convert.</param> /// <returns>The converted expression, or a <see cref="ParseErrorExpression"/> if the expression could not be converted.</returns> public static ExpressionBase ConvertFrom(ExpressionBase expression) { FloatConstantExpression floatExpression; switch (expression.Type) { case ExpressionType.FloatConstant: return(expression); case ExpressionType.IntegerConstant: floatExpression = new FloatConstantExpression((float)((IntegerConstantExpression)expression).Value); break; default: return(new ParseErrorExpression("Cannot convert to float", expression)); } expression.CopyLocation(floatExpression); return(floatExpression); }
private static bool MergeNonConstantMathematic(MathematicExpression mathematicLeft, MathematicOperation operation, ExpressionBase right, out ExpressionBase result) { var left = mathematicLeft.Right; result = null; var newLeft = mathematicLeft.Left; var newOperation = mathematicLeft.Operation; ExpressionBase newRight; switch (mathematicLeft.Operation) { case MathematicOperation.Add: if (operation == MathematicOperation.Add) { // (a + 3) + 2 => a + (3 + 2) if (!MergeAddition(left, right, out newRight)) { result = newRight; return(false); } } else if (operation == MathematicOperation.Subtract) { if (IsGreater(left, right)) { // (a + 3) - 2 => a + (3 - 2) if (!MergeSubtraction(left, right, out newRight)) { result = newRight; return(false); } } else { // (a + 2) - 3 => a - (3 - 2) if (!MergeSubtraction(right, left, out newRight)) { result = newRight; return(false); } newOperation = MathematicOperation.Subtract; } } else { return(false); } break; case MathematicOperation.Subtract: if (operation == MathematicOperation.Add) { if (IsGreater(left, right)) { // (a - 3) + 2 => a - (3 - 2) if (!MergeSubtraction(left, right, out newRight)) { result = newRight; return(false); } } else { // (a - 2) + 3 => a + (3 - 2) if (!MergeSubtraction(right, left, out newRight)) { result = newRight; return(false); } newOperation = MathematicOperation.Add; } } else if (operation == MathematicOperation.Subtract) { // (a - 3) - 2 => a - (3 + 2) if (!MergeAddition(left, right, out newRight)) { result = newRight; return(false); } } else { return(false); } break; case MathematicOperation.Multiply: switch (operation) { case MathematicOperation.Multiply: // (a * 3) * 2 => a * (3 * 2) if (!MergeMultiplication(left, right, out newRight)) { result = newRight; return(false); } break; case MathematicOperation.Divide: if (left.Type == ExpressionType.FloatConstant) { right = FloatConstantExpression.ConvertFrom(right); if (right.Type == ExpressionType.ParseError) { return(false); } } else if (right.Type == ExpressionType.FloatConstant) { left = FloatConstantExpression.ConvertFrom(left); if (left.Type == ExpressionType.ParseError) { return(false); } } else { // (a * 8) / 4 => a * (8 / 4) => a * 2 // can only merge these if the constant on the left is a multiple of the constant on the right if (!IsMultiple(left, right)) { return(false); } } if (!MergeDivision(left, right, out newRight)) { result = newRight; return(false); } break; case MathematicOperation.Modulus: // (a * 8) % 4 => a % 4 // can only merge these if the constant on the left is a multiple of the constant on the right if (!IsMultiple(left, right)) { return(false); } newRight = right; newOperation = MathematicOperation.Modulus; break; default: return(false); } break; case MathematicOperation.Divide: if (operation == MathematicOperation.Divide) { // (a / 3) / 2 => a / (3 * 2) var multiplication = new MathematicExpression(left, MathematicOperation.Multiply, right); if (!MergeMultiplication(left, right, out newRight)) { result = newRight; return(false); } } else if (operation == MathematicOperation.Multiply) { if (left.Type == ExpressionType.FloatConstant || right.Type == ExpressionType.FloatConstant) { // (a / 3.0) * 2.0 => a * (2.0 / 3.0) if (!MergeDivision(right, left, out newRight)) { result = newRight; return(false); } newOperation = MathematicOperation.Multiply; } else { // (a / 3) * 2 => a * (2 / 3) // when integer division is performed first, the result may be floored before applying // the multiplication, so don't automatically merge them. return(false); } } else { return(false); } break; case MathematicOperation.BitwiseAnd: // (a & 12) & 5 => a & (12 & 5) if (operation != MathematicOperation.BitwiseAnd) { return(false); } if (!MergeBitwiseAnd(left, right, out newRight)) { result = newRight; return(false); } break; default: return(false); } return(MergeOperands(newLeft, newOperation, newRight, out result)); }
private static ExpressionBase ParseClauseCore(PositionalTokenizer tokenizer) { ExpressionBase clause; switch (tokenizer.NextChar) { case '!': tokenizer.Advance(); clause = ParseClause(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } return(new ConditionalExpression(null, ConditionalOperation.Not, clause)); case '(': if (AnonymousUserFunctionDefinitionExpression.IsAnonymousParameterList(tokenizer)) { return(AnonymousUserFunctionDefinitionExpression.ParseAnonymous(tokenizer)); } tokenizer.Advance(); clause = ExpressionBase.Parse(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } if (tokenizer.NextChar != ')') { if (tokenizer.NextChar == '\0') { return(ParseError(tokenizer, "No closing parenthesis found")); } return(ParseError(tokenizer, "Expected closing parenthesis, found: " + tokenizer.NextChar)); } clause.IsLogicalUnit = true; tokenizer.Advance(); return(clause); case '"': try { var stringValue = tokenizer.ReadQuotedString().ToString(); return(new StringConstantExpression(stringValue)); } catch (InvalidOperationException ex) { return(ParseError(tokenizer, ex.Message)); } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return(ParseNumber(tokenizer, true)); case '-': var tokenStart = tokenizer.Location; tokenizer.Advance(); if (tokenizer.NextChar >= '0' && tokenizer.NextChar <= '9') { var result = ParseNumber(tokenizer, false); var tokenEnd = result.Location.End; switch (result.Type) { case ExpressionType.IntegerConstant: result = new IntegerConstantExpression(-((IntegerConstantExpression)result).Value); break; case ExpressionType.FloatConstant: result = new FloatConstantExpression(-((FloatConstantExpression)result).Value); break; default: return(result); } result.Location = new TextRange(tokenStart, tokenEnd); return(result); } return(ParseError(tokenizer, "Minus without value", tokenStart.Line, tokenStart.Column)); case '{': tokenizer.Advance(); return(DictionaryExpression.Parse(tokenizer)); case '[': tokenizer.Advance(); return(ParseArray(tokenizer)); default: var line = tokenizer.Line; var column = tokenizer.Column; var identifier = tokenizer.ReadIdentifier(); if (identifier.IsEmpty) { var error = ParseError(tokenizer, "Unexpected character: " + tokenizer.NextChar); tokenizer.Advance(); return(error); } SkipWhitespace(tokenizer); if (identifier == "return") { clause = ExpressionBase.Parse(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } return(new ReturnExpression(new KeywordExpression(identifier.ToString(), line, column), clause)); } if (identifier == "function") { return(UserFunctionDefinitionExpression.Parse(tokenizer, line, column)); } if (identifier == "for") { return(ForExpression.Parse(tokenizer, line, column)); } if (identifier == "if") { return(IfExpression.Parse(tokenizer, line, column)); } if (identifier == "true") { return(new BooleanConstantExpression(true, line, column)); } if (identifier == "false") { return(new BooleanConstantExpression(false, line, column)); } if (tokenizer.NextChar == '(') { tokenizer.Advance(); var parameters = new List <ExpressionBase>(); ParseParameters(tokenizer, parameters); var functionCall = new FunctionCallExpression(new FunctionNameExpression(identifier.ToString(), line, column), parameters); functionCall.Location = new TextRange(line, column, tokenizer.Line, tokenizer.Column - 1); return(functionCall); } if (tokenizer.NextChar == '[') { IndexedVariableExpression parent = null; do { tokenizer.Advance(); var index = ExpressionBase.Parse(tokenizer); if (index.Type == ExpressionType.ParseError) { return(index); } SkipWhitespace(tokenizer); if (tokenizer.NextChar != ']') { return(ParseError(tokenizer, "Expecting closing bracket after index")); } tokenizer.Advance(); SkipWhitespace(tokenizer); if (parent != null) { parent = new IndexedVariableExpression(parent, index); } else { parent = new IndexedVariableExpression(new VariableExpression(identifier.ToString(), line, column), index); } } while (tokenizer.NextChar == '['); return(parent); } return(new VariableExpression(identifier.ToString(), line, column)); } }
private static ExpressionBase ParseNumber(PositionalTokenizer tokenizer, bool isUnsigned) { int line = tokenizer.Line; int column = tokenizer.Column; int endLine = line; int endColumn = column; uint value; string number = ""; if (tokenizer.Match("0x")) { while (Char.IsDigit(tokenizer.NextChar) || (tokenizer.NextChar >= 'A' && tokenizer.NextChar <= 'F') || (tokenizer.NextChar >= 'a' && tokenizer.NextChar <= 'f')) { number += tokenizer.NextChar; endLine = tokenizer.Line; endColumn = tokenizer.Column; tokenizer.Advance(); } if (!UInt32.TryParse(number, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.CurrentCulture, out value)) { return(new ParseErrorExpression("Number too large")); } } else { while (Char.IsDigit(tokenizer.NextChar)) { number += tokenizer.NextChar; endLine = tokenizer.Line; endColumn = tokenizer.Column; tokenizer.Advance(); } if (tokenizer.NextChar == '.') { number += tokenizer.NextChar; tokenizer.Advance(); while (Char.IsDigit(tokenizer.NextChar)) { number += tokenizer.NextChar; endLine = tokenizer.Line; endColumn = tokenizer.Column; tokenizer.Advance(); } float floatValue; if (!float.TryParse(number, System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture, out floatValue)) { return(new ParseErrorExpression("Number too large")); } var floatExpression = new FloatConstantExpression(floatValue); floatExpression.Location = new TextRange(line, column, endLine, endColumn); return(floatExpression); } if (!UInt32.TryParse(number, out value)) { return(new ParseErrorExpression("Number too large")); } } if (value > Int32.MaxValue && !isUnsigned) { return(new ParseErrorExpression("Number too large")); } var integerExpression = new IntegerConstantExpression((int)value); integerExpression.Location = new TextRange(line, column, endLine, endColumn); return(integerExpression); }