Represents a node in the abstract syntax tree.
Example #1
0
        /// <summary>
        /// Gets a null denotation token for given token using the null denotation getter.
        /// </summary>
        /// <param name="self"></param>
        /// <returns></returns>
        public Token GetNullDenotation(Token self)
        {
            if (this.NullDenotationGetter == null)
                throw new InvalidOperationException("Unable to invoke null denotation getter: getter is not set.");
            if (self.Type != this.TokenType)
                throw new ArgumentException("Unable to invoke null denotation getter: invalid self type.", "self");

            return this.NullDenotationGetter(self);
        }
Example #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Token"/> class with given NumPlurals and abstract syntax tree.
        /// </summary>
        /// <param name="numPlurals"></param>
        /// <param name="astRoot">Abstract syntax tree root.</param>
        public AstPluralRule(int numPlurals, Token astRoot)
        {
            if (numPlurals <= 0)
                throw new ArgumentOutOfRangeException("numPlurals");
            if (astRoot == null)
                throw new ArgumentNullException("astRoot");

            this.NumPlurals = numPlurals;
            this.AstRoot = astRoot;
        }
Example #3
0
        /// <summary>
        /// Compiles a plural rule abstract syntax tree into managed dynamic method delegate using an IL code generator.
        /// </summary>
        /// <param name="astRoot">abstract syntax tree root node.</param>
        /// <param name="outputDelegateType">Type of output delegate.</param>
        /// <returns>Compiled dynamic method of given type.</returns>
        public virtual Delegate CompileToDynamicMethod(Token astRoot, Type outputDelegateType)
        {
            var dynamicMethod = this.CreateDynamicMethod(outputDelegateType);
            var il = dynamicMethod.GetILGenerator();

            this.CompileStart(il);
            this.CompileNode(il, astRoot);
            this.CompileFinish(il);

            return dynamicMethod.CreateDelegate(outputDelegateType);
        }
Example #4
0
        /// <summary>
        /// Recursively compiles an AST node to the IL instructions.
        /// </summary>
        /// <param name="il">IL generator instance.</param>
        /// <param name="node">AST node.</param>
        protected virtual void CompileNode(ILGenerator il, Token node)
        {
            switch (node.Type)
            {
                case TokenType.Number:
                    il.Emit(OpCodes.Ldc_I8, node.Value);
                    break;

                case TokenType.N:
                    il.Emit(OpCodes.Ldarg_0);
                    break;

                case TokenType.Plus:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    il.Emit(OpCodes.Add);
                    break;

                case TokenType.Minus:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    il.Emit(OpCodes.Sub);
                    break;

                case TokenType.Divide:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    il.Emit(OpCodes.Div);
                    break;

                case TokenType.Multiply:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    il.Emit(OpCodes.Mul);
                    break;

                case TokenType.Modulo:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    il.Emit(OpCodes.Rem);
                    break;

                case TokenType.GreaterThan:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    this.EmitConditionalValue(il, OpCodes.Bgt);
                    break;

                case TokenType.GreaterOrEquals:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    this.EmitConditionalValue(il, OpCodes.Bge);
                    break;

                case TokenType.LessThan:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    this.EmitConditionalValue(il, OpCodes.Blt);
                    break;

                case TokenType.LessOrEquals:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    this.EmitConditionalValue(il, OpCodes.Ble);
                    break;

                case TokenType.Equals:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    this.EmitConditionalValue(il, OpCodes.Beq);
                    break;

                case TokenType.NotEquals:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    this.EmitConditionalValue(il, OpCodes.Beq, 0, 1);
                    break;

                case TokenType.And:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    il.Emit(OpCodes.And);
                    break;

                case TokenType.Or:
                    this.CompileNode(il, node.Children[0]);
                    this.CompileNode(il, node.Children[1]);
                    il.Emit(OpCodes.Or);
                    break;

                case TokenType.Not:
                    this.CompileNode(il, node.Children[0]);
                    this.EmitConditionalValue(il, OpCodes.Brfalse);
                    break;

                case TokenType.TernaryIf:
                    this.CompileNode(il, node.Children[0]);
                    this.EmitConditionalBranch(il, OpCodes.Brtrue, node.Children[1], node.Children[2]);
                    break;
            }
        }
Example #5
0
        /// <summary>
        /// Emits instructions required for conditional branch using given OpCode to check condition and given nodes for positive and negative branches.
        /// </summary>
        /// <param name="il">IL generator instance.</param>
        /// <param name="conditionOpCode">OpCode of the condition check operation.</param>
        /// <param name="trueNode">AST node that will be executed when condition returns positive result.</param>
        /// <param name="falseNode">AST node that will be executed when condition returns negative result.</param>
        protected virtual void EmitConditionalBranch(ILGenerator il, OpCode conditionOpCode, Token trueNode, Token falseNode)
        {
            var trueLabel = il.DefineLabel();
            var endLabel = il.DefineLabel();

            il.Emit(conditionOpCode, trueLabel);
            this.CompileNode(il, falseNode);
            il.Emit(OpCodes.Br, endLabel);

            il.MarkLabel(trueLabel);
            this.CompileNode(il, trueNode);

            il.MarkLabel(endLabel);
        }
Example #6
0
        protected long Evaluate(Token node, long number)
        {
            switch (node.Type)
            {
                case TokenType.Number:
                    return node.Value;

                case TokenType.N:
                    return number;

                case TokenType.Plus:
                    return this.Evaluate(node.Children[0], number)
                         + this.Evaluate(node.Children[1], number);

                case TokenType.Minus:
                    return this.Evaluate(node.Children[0], number)
                         - this.Evaluate(node.Children[1], number);

                case TokenType.Divide:
                    return this.Evaluate(node.Children[0], number)
                         / this.Evaluate(node.Children[1], number);

                case TokenType.Multiply:
                    return this.Evaluate(node.Children[0], number)
                         * this.Evaluate(node.Children[1], number);

                case TokenType.Modulo:
                    return this.Evaluate(node.Children[0], number)
                         % this.Evaluate(node.Children[1], number);

                case TokenType.GreaterThan:
                    return this.Evaluate(node.Children[0], number)
                         > this.Evaluate(node.Children[1], number)
                         ? 1 : 0;

                case TokenType.GreaterOrEquals:
                    return this.Evaluate(node.Children[0], number)
                        >= this.Evaluate(node.Children[1], number)
                         ? 1 : 0;

                case TokenType.LessThan:
                    return this.Evaluate(node.Children[0], number)
                         < this.Evaluate(node.Children[1], number)
                         ? 1 : 0;

                case TokenType.LessOrEquals:
                    return this.Evaluate(node.Children[0], number)
                        <= this.Evaluate(node.Children[1], number)
                         ? 1 : 0;

                case TokenType.Equals:
                    return this.Evaluate(node.Children[0], number)
                        == this.Evaluate(node.Children[1], number)
                         ? 1 : 0;

                case TokenType.NotEquals:
                    return this.Evaluate(node.Children[0], number)
                        != this.Evaluate(node.Children[1], number)
                         ? 1 : 0;

                case TokenType.And:
                    return this.Evaluate(node.Children[0], number) != 0
                        && this.Evaluate(node.Children[1], number) != 0
                         ? 1 : 0;

                case TokenType.Or:
                    return this.Evaluate(node.Children[0], number) != 0
                        || this.Evaluate(node.Children[1], number) != 0
                         ? 1 : 0;

                case TokenType.Not:
                    return this.Evaluate(node.Children[0], number) == 0
                         ? 1 : 0;

                case TokenType.TernaryIf:
                    return this.Evaluate(node.Children[0], number) != 0
                         ? this.Evaluate(node.Children[1], number)
                         : this.Evaluate(node.Children[2], number);

                default:
                    throw new InvalidOperationException(String.Format("Can not evaluate token: {0}.", node.Type));
            }
        }
Example #7
0
        /// <summary>
        /// Parses the input string that contains a plural rule formula and generates an abstract syntax tree.
        /// </summary>
        /// <param name="input">Input string.</param>
        /// <returns>Root node of the abstract syntax tree.</returns>
        public Token Parse(string input)
        {
            this.Input = input + "\0";
            this.Position = 0;
            this.CurrentToken = this.GetNextToken();

            return this.ParseNextExpression();
        }
Example #8
0
        protected Token ParseNextExpression(int rightBindingPower = 0)
        {
            var token = this.CurrentToken;
            this.CurrentToken = this.GetNextToken();
            var left = this.GetDefinition(token.Type).GetNullDenotation(token);

            while (rightBindingPower < this.GetDefinition(this.CurrentToken.Type).LeftBindingPower)
            {
                token = this.CurrentToken;
                this.CurrentToken = this.GetNextToken();
                left = this.GetDefinition(token.Type).GetLeftDenotation(token, left);
            }

            return left;
        }
Example #9
0
 protected void AdvancePosition()
 {
     this.CurrentToken = this.GetNextToken();
 }