internal unsafe CSSPseudoClass_Nth(byte* data, byte* dataEnd, CSSPseudoClass pseudoClass, out bool success) { success = true; #region odd/even? if (toLower(*data) == 'o' && toLower(*(data + 1)) == 'd' && toLower(*(data + 2)) == 'd') { p_Odd = true; return; } if (toLower(*data) == 'e' && toLower(*(data + 1)) == 'v' && toLower(*(data + 2)) == 'e' && toLower(*(data + 3)) == 'n') { p_Even = true; return; } #endregion //parse the data as an arithmetic expression p_Expression = ArithmeticQueue.Parse(ref data, dataEnd); ArithmeticQueue flatten = p_Expression.Flatten(); //does the expression contain any substitutes? //if so, we add "n" as a substitute (IF it is n, if //it isn't then it is an invalid nth* class. LinkedListNode<ArithmeticOperand> currentOperand = flatten.Operands.First; while (currentOperand != null) { //is the operand a substitute? ArithmeticOperand current = currentOperand.Value; if (!current.IsSubstitution) { currentOperand = currentOperand.Next; continue; } //invalid? (the name has to be "n") if ((char)current.Value != 'n') { success = false; break; } p_HasNSubstitute = true; break; } //if there is no "n" substitute, pre-calculate the expression //so we don't have to constantly calculate everytime we check. if (success && !p_HasNSubstitute) { p_ExpressionResult = (int)p_Expression.Calculate(); } }
private void processBIDMAS(ArithmeticOperator op) { //iterate through the operators LinkedListNode<ArithmeticOperator> currentOperator = p_Operators.First; LinkedListNode<ArithmeticOperand> currentOperand = p_Operands.First; while (currentOperator != null) { //operator we want to process? ArithmeticOperator currentOp = currentOperator.Value; if (op != currentOp) { currentOperator = currentOperator.Next; currentOperand = currentOperand.Next; continue; } //get the 2 operands for the operator ArithmeticOperand opAnd1 = currentOperand.Value; ArithmeticOperand opAnd2 = currentOperand.Next.Value; //group this operator into a scope ArithmeticQueue queue = new ArithmeticQueue(); queue.AddOperation(currentOp, opAnd1, opAnd2); //replace the operand with the queue currentOperand.Value = new ArithmeticOperand(queue); //since we have processed the second operand and //the operator, remove it LinkedListNode<ArithmeticOperator> nextOp = currentOperator.Next; p_Operands.Remove(currentOperand.Next); p_Operators.Remove(currentOperator); currentOperator = nextOp; } }
public static ArithmeticQueue Parse(ref byte* data, byte* dataEnd, bool useBIDMAS, LinkedList<ArithmeticFunction> functions) { //define the list of scopes, operators and operands LinkedList<ArithmeticOperator> operators = new LinkedList<ArithmeticOperator>(); LinkedList<ArithmeticOperand> operands = new LinkedList<ArithmeticOperand>(); //define the size of the numerical object the queue will return when //the calculate function is called (default of 1 (byte)) sbyte resultSize = 1; bool containsDecimal = false; //any functions in the list? bool functionsListed = functions.Count != 0; //iterate through the data bool negativeFlag = false; while (data < dataEnd) { //skip whitespaces so we are on a character if (Helpers.SkipWhitespaces(ref data, dataEnd)) { break; } //end the scope? if (*data == ')') { data++; break; } #region operator? ArithmeticOperator op = parseOperator(*data); if (op != ArithmeticOperator.None) { //if it's division, we make sure we don't lose //precision when dividing operators (e.g 1/3) if (op == ArithmeticOperator.Divide) { containsDecimal = true; } //make sure we do not process a negative number //and treat it as an operator bool isNegative = false; if (op == ArithmeticOperator.Subtract) { isNegative = operators.Count == operands.Count; negativeFlag = isNegative; } if (!isNegative) { operators.AddLast(op); } data++; continue; } #endregion #region function? if (functionsListed && isAlphabetic(*data)) { //read until an open queue byte* functionNameStart = data; byte* functionNameEnd = (byte*)0; byte* dataCopy = data; bool foundScope = false; while (dataCopy < dataEnd) { //scope? if (*dataCopy == '(') { foundScope = true; functionNameEnd = dataCopy - 1; dataCopy++; break; } //not a whitespace? if (*dataCopy != ' ' && *dataCopy != '\n' && *dataCopy != '\r' && *dataCopy != '\t' && !isAlphabetic(*dataCopy)) { break; } dataCopy++; } //did we find a scope? if (foundScope) { //trim the function name to remove whitespace while (functionNameEnd > data && !isAlphabetic(*functionNameEnd)) { functionNameEnd--; } //name must be at least 2 characters wide if (functionNameStart != functionNameEnd) { //it's a function, lookup its name data = dataCopy; string functionName = Helpers.ReadString(functionNameStart, functionNameEnd, Encoding.ASCII); //find the function from the functions list IEnumerator<ArithmeticFunction> e = functions.GetEnumerator(); ArithmeticFunction functionBase = null; while (e.MoveNext()) { ArithmeticFunction current = e.Current; if (current.Name == functionName) { functionBase = current; break; } } //found the function? if (functionBase == null) { throw new Exception("Function \"" + functionName + "\" does not exist!"); } //was there an operand behind the substitute? //if not, (e.g 5(5)) we multiple the previous operand with the scope if (operands.Count != operators.Count) { operators.AddLast(ArithmeticOperator.Multiply); } //parse the function call arguments ArithmeticQueue args = ArithmeticQueue.Parse(ref data, dataEnd, useBIDMAS, functions); //add the function as an operand ArithmeticFunction function = functionBase.Create(args); operands.AddLast(new ArithmeticOperand(function, negativeFlag)); negativeFlag = false; continue; } } } #endregion #region queue if (*data == '(') { //was there an operand behind the substitute? //if not, (e.g 5(5)) we multiple the previous operand with the scope if (operands.Count != operators.Count) { operators.AddLast(ArithmeticOperator.Multiply); } data++; ArithmeticQueue scope = Parse(ref data, dataEnd, functions); operands.AddLast(new ArithmeticOperand(scope, negativeFlag)); negativeFlag = false; continue; } #endregion #region numeric? if (*data >= '0' && *data <= '9') { byte* numPtr = data; byte* numPtrEnd = dataEnd - 1; //read the numeric bool isDecimal = false; while (data < dataEnd) { //decimal? if (*data == '.') { isDecimal = true; containsDecimal = true; data++; continue; } //end of numerical? if (!((*data >= '0' && *data <= '9'))) { numPtrEnd = data - 1; break; } data++; } //calculate how much memory this number will take //and see if the current result size can fit it, if //not, expand it byte charLength = (byte)((numPtrEnd - numPtr) + 1); sbyte memSize = ArithmeticNumeric.RequiredMemory(charLength, isDecimal); if (memSize > resultSize) { resultSize = memSize; } //add the number as an operand string numStr = Helpers.ReadString(numPtr, numPtrEnd, Encoding.ASCII); ArithmeticNumeric opValue = ArithmeticNumeric.FromString(numStr, isDecimal, charLength); operands.AddLast(new ArithmeticOperand(opValue, negativeFlag)); negativeFlag = false; continue; } #endregion #region substitute? else { //was there an operand behind the substitute? //if not, (e.g 5n) we multiple the previous operand with n if (operands.Count != operators.Count) { operators.AddLast(ArithmeticOperator.Multiply); } operands.AddLast(new ArithmeticOperand((char)*data, negativeFlag)); negativeFlag = false; data++; } #endregion } ArithmeticQueue buffer = new ArithmeticQueue(resultSize, containsDecimal, operators, operands); //bidmas? if (useBIDMAS) { buffer.SortBIDMAS(); } return buffer; }
private void flattenQueue(LinkedList<ArithmeticOperator> newOperators, LinkedList<ArithmeticOperand> newOperands, ArithmeticQueue q) { LinkedListNode<ArithmeticOperator> currentOperator = q.p_Operators.First; LinkedListNode<ArithmeticOperand> currentOperand = q.p_Operands.First; //no operands? if (currentOperand == null) { return; } //add the first operand if (currentOperand.Value.IsQueue) { flattenQueue( newOperators, newOperands, (ArithmeticQueue)currentOperand.Value.Value); } else { newOperands.AddLast(currentOperand.Value); } currentOperand = currentOperand.Next; //no operators? if (currentOperator == null) { return; } //iterate over the operators while (currentOperator != null) { //add the operator newOperators.AddLast(currentOperator.Value); //grab the operand ArithmeticOperand operand = currentOperand.Value; //queue? if (operand.IsQueue) { flattenQueue( newOperators, newOperands, (ArithmeticQueue)operand.Value); } else { newOperands.AddLast(operand); } currentOperand = currentOperand.Next; currentOperator = currentOperator.Next; } }
public abstract ArithmeticFunction Create(ArithmeticQueue queue);
public ArithmeticNumeric Call(ArithmeticQueue queue, LinkedList<ArithmeticSubstitute> substitutes) { return OnCall(queue.Calculate(substitutes)); }
public ArithmeticNumeric Call(ArithmeticQueue queue) { return OnCall(queue.Calculate()); }
public override ArithmeticFunction Create(ArithmeticQueue queue) { return new arithmeticFunctionDelegation(p_Name, p_Handler, queue); }
private arithmeticFunctionDelegation(string name, OnCallHandler handler, ArithmeticQueue queue) : base(name) { p_Queue = queue; p_Handler = handler; }