public DynamicExpressionData( OperatorBuilder topOperator, ParameterExpression[] orderedParameters) { OgExpressionStringValue = topOperator.ToString(); var builderQueue = new Queue <OperatorBuilder>(); builderQueue.Enqueue(topOperator); while (builderQueue.Count > 0) { var nextNode = builderQueue.Dequeue(); if (nextNode.type == OperatorType.CONSTANT_VALUE) { definitionList.Add(new OperatorDefinition { operatorType = OperatorType.CONSTANT_VALUE, nodeValue = nextNode.nodeValue }); } else if (nextNode.type == OperatorType.PARAMETER_VALUE) { var paramIndex = Array.IndexOf(orderedParameters, nextNode.parameter); definitionList.Add(new OperatorDefinition { operatorType = OperatorType.PARAMETER_VALUE, parameterIndex = paramIndex }); } else if (nextNode.IsUnary) { var rhsIndex = definitionList.Count + builderQueue.Count + 1; definitionList.Add(new OperatorDefinition { operatorType = nextNode.type, rhs = (ushort)rhsIndex }); builderQueue.Enqueue(nextNode.rhs); } else if (nextNode.IsBinary) { var lhsIndex = definitionList.Count + builderQueue.Count + 1; var rhsIndex = definitionList.Count + builderQueue.Count + 2; definitionList.Add(new OperatorDefinition { operatorType = nextNode.type, lhs = (ushort)lhsIndex, rhs = (ushort)rhsIndex }); builderQueue.Enqueue(nextNode.lhs); builderQueue.Enqueue(nextNode.rhs); } else { throw new Exception("unrecognized node type"); } } }
public static OperatorBuilder Unary(OperatorType opType, OperatorBuilder single) { if (opType != OperatorType.BOOLEAN_NOT && opType != OperatorType.NEGATE_UNARY) { throw new SyntaxException($"Unsupported Unary Operator {Enum.GetName(typeof(OperatorType), opType)}"); } return(new OperatorBuilder { type = opType, rhs = single, }); }
public static OperatorBuilder Binary(OperatorType opType, OperatorBuilder lhs, OperatorBuilder rhs) { if (opType == OperatorType.BOOLEAN_NOT || opType == OperatorType.NEGATE_UNARY || opType == OperatorType.CONSTANT_VALUE || opType == OperatorType.PARAMETER_VALUE) { throw new SyntaxException($"Unsupported Binary Operator {Enum.GetName(typeof(OperatorType), opType)}"); } return(new OperatorBuilder { type = opType, rhs = rhs, lhs = lhs }); }
/// <summary> /// assumes the open paren has already been consumed /// </summary> /// <param name="enumerator"></param> /// <returns></returns> private IEnumerable <TokenTarget> ParseToTokenExpressionTillNextParen(IEnumerator <Token> enumerator) { while (enumerator.MoveNext() && enumerator.Current.token != TokenType.RIGHT_PAREN) { var current = enumerator.Current; var tokenType = current.token; if (tokenType == TokenType.LEFT_PAREN) { yield return(new TokenExpression( ParseToTokenExpressionTillNextParen(enumerator).ToList(), new CompilerContext(current.context, enumerator.Current.context))); } else if (expressions.HasFlag(tokenType)) { if (tokenType == TokenType.CONSTANT) { yield return(new TokenExpression(OperatorBuilder.ConstantValue(current.value), current.context)); } else if (tokenType == TokenType.VARIABLE) { if (!parameters.TryGetValue(current.name, out var parameterExp)) { throw current.context.ExceptionHere($"no parameter found for '{current.name}'"); } yield return(new TokenExpression(OperatorBuilder.ParameterReference(parameterExp), current.context)); } else { throw current.context.ExceptionHere($"Invalid Expression Token Type: '{Enum.GetName(typeof(TokenType), tokenType)}'"); } } else { // the token must be an operator yield return(new TokenOperator(current.context) { type = tokenType, }); } } }
public OperatorBuilder CompileSelfToExpression() { if (!isTokenSeries) { return(compiledExpression); } // detect unaries int totalPrecedingOperators = 1; var unaryOperatorIndexes = new List <int>(); for (int i = 0; i < tokenSeries.Count; i++) { if (tokenSeries[i] is TokenOperator) { totalPrecedingOperators++; if (totalPrecedingOperators == 2) { unaryOperatorIndexes.Add(i); } else if (totalPrecedingOperators > 2) { throw tokenSeries[i].context.ExceptionHere( $"{totalPrecedingOperators} consecutive operators detected"); } } else { totalPrecedingOperators = 0; } } foreach (var unaryIndex in ((IEnumerable <int>)unaryOperatorIndexes).Reverse()) { var op = tokenSeries[unaryIndex] as TokenOperator; tokenSeries.RemoveAt(unaryIndex); if (tokenSeries.Count <= unaryIndex) { throw op.context.ExceptionHere("Stranded Operator"); } var value = tokenSeries[unaryIndex] as TokenExpression; var valuesExpression = value.CompileSelfToExpression(); switch (op.type) { case TokenType.SUBTRACT: tokenSeries[unaryIndex] = new TokenExpression(OperatorBuilder.Unary(OperatorType.NEGATE_UNARY, valuesExpression), op.context); break; case TokenType.BOOLEAN_NOT: tokenSeries[unaryIndex] = new TokenExpression(OperatorBuilder.Unary(OperatorType.BOOLEAN_NOT, valuesExpression), op.context); break; default: throw op.context.ExceptionHere($"Unsupported unary operator: {Enum.GetName(typeof(TokenType), op.type)}"); } } var operatorNodes = new List <LinkedListNode <TokenTarget> >(); var tokenLinkedList = new LinkedList <TokenTarget>(tokenSeries); var currentNode = tokenLinkedList.First; do { if (currentNode.Value is TokenOperator op) { operatorNodes.Add(currentNode); } } while ((currentNode = currentNode.Next) != null); operatorNodes.Sort((a, b) => Token.OPERATOR_PRECIDENCE[(a.Value as TokenOperator).type] - Token.OPERATOR_PRECIDENCE[(b.Value as TokenOperator).type]); foreach (var operatorNode in operatorNodes) { var firstVal = operatorNode.Previous.Value as TokenExpression; var op = operatorNode.Value as TokenOperator; var secondVal = operatorNode.Next.Value as TokenExpression; var newVal = new TokenExpression( GetExpressionFromBinaryOperator( firstVal.CompileSelfToExpression(), op, secondVal.CompileSelfToExpression()), firstVal.context); tokenLinkedList.Remove(firstVal); operatorNode.Value = newVal; tokenLinkedList.Remove(secondVal); } //should be all compiled if (tokenLinkedList.Count != 1) { if (tokenLinkedList.Count > 0) { throw tokenLinkedList.First.Value.context.ExceptionHere("Compilation error: token string could not compile to one expression"); } else { throw new SyntaxException("Compilation error: token string could not compile to one expression"); } } // the final node could be uncompiled if this was a simple nested paren. call compile method just in case, rely on short-circuit if already compiled. return((tokenLinkedList.First.Value as TokenExpression).CompileSelfToExpression()); }
public TokenExpression(OperatorBuilder expression, CompilerContext context) : base(context) { compiledExpression = expression; isTokenSeries = false; }
private OperatorBuilder GetExpressionFromBinaryOperator(OperatorBuilder a, TokenOperator op, OperatorBuilder b) { OperatorType newOpType = default; switch (op.type) { case TokenType.MULTIPLY: newOpType = OperatorType.MULTIPLY; break; case TokenType.DIVIDE: newOpType = OperatorType.DIVIDE; break; case TokenType.REMAINDER: newOpType = OperatorType.REMAINDER; break; case TokenType.EXPONENT: newOpType = OperatorType.EXPONENT; break; case TokenType.ADD: newOpType = OperatorType.ADD; break; case TokenType.SUBTRACT: newOpType = OperatorType.SUBTRACT; break; case TokenType.GREATER_THAN: newOpType = OperatorType.GREATER_THAN; break; case TokenType.LESS_THAN: newOpType = OperatorType.LESS_THAN; break; case TokenType.GREATER_THAN_OR_EQ: newOpType = OperatorType.GREATER_THAN_OR_EQ; break; case TokenType.LESS_THAN_OR_EQ: newOpType = OperatorType.LESS_THAN_OR_EQ; break; case TokenType.EQUAL: newOpType = OperatorType.EQUAL; break; case TokenType.NOT_EQUAL: newOpType = OperatorType.NOT_EQUAL; break; case TokenType.BOOLEAN_AND: newOpType = OperatorType.BOOLEAN_AND; break; case TokenType.BOOLEAN_OR: newOpType = OperatorType.BOOLEAN_OR; break; default: throw op.context.ExceptionHere($"Invalid binary operator symbol: {Enum.GetName(typeof(TokenType), op.type)}"); } return(OperatorBuilder.Binary(newOpType, a, b)); }