Esempio n. 1
0
 /// <summary>
 /// Call when a variable has been encountered.
 /// </summary>
 /// <param name="args">The event arguments.</param>
 protected void OnVariableFound(VariableFoundEventArgs <T> args) => VariableFound?.Invoke(this, args);
Esempio n. 2
0
        /// <inheritdoc/>
        public override void Push(Node node)
        {
            Label lblBypass, lblEnd;

            switch (node)
            {
            case BinaryOperatorNode bn:

                // Execution
                switch (bn.NodeType)
                {
                case NodeTypes.Add:
                    Call(Complex.Add, new[] { bn.Left, bn.Right });
                    return;

                case NodeTypes.Subtract:
                    Call(Complex.Subtract, new[] { bn.Left, bn.Right });
                    return;

                case NodeTypes.Multiply:
                    Call(Complex.Multiply, new[] { bn.Left, bn.Right });
                    return;

                case NodeTypes.Divide:
                    Push(bn.Left);
                    Push(bn.Right);
                    Generator.Emit(OpCodes.Call, _safeDiv);
                    return;

                case NodeTypes.Modulo:
                    PushReal(bn.Left);
                    PushReal(bn.Right);
                    Generator.Emit(OpCodes.Rem);
                    RealToComplex();
                    return;

                case NodeTypes.GreaterThan:
                    PushReal(bn.Left);
                    PushReal(bn.Right);
                    PushCheck(OpCodes.Bgt_S, 1.0, 0.0);
                    return;

                case NodeTypes.LessThan:
                    PushReal(bn.Left);
                    PushReal(bn.Right);
                    PushCheck(OpCodes.Blt_S, 1.0, 0.0);
                    return;

                case NodeTypes.GreaterThanOrEqual:
                    PushReal(bn.Left);
                    PushReal(bn.Right);
                    PushCheck(OpCodes.Bge_S, 1.0, 0.0);
                    return;

                case NodeTypes.LessThanOrEqual:
                    PushReal(bn.Left);
                    PushReal(bn.Right);
                    PushCheck(OpCodes.Ble_S, 1.0, 0.0);
                    return;

                case NodeTypes.Equals:
                    Push(bn.Left);
                    Push(bn.Right);
                    PushDouble(Builder.RelativeTolerance);
                    PushDouble(Builder.AbsoluteTolerance);
                    Generator.Emit(OpCodes.Call, _equals);
                    PushCheck(OpCodes.Brtrue_S, 1.0, 0.0);
                    return;

                case NodeTypes.NotEquals:
                    Push(bn.Left);
                    Push(bn.Right);
                    PushDouble(Builder.RelativeTolerance);
                    PushDouble(Builder.AbsoluteTolerance);
                    Generator.Emit(OpCodes.Call, _equals);
                    PushCheck(OpCodes.Brfalse_S, 1.0, 0.0);
                    return;

                case NodeTypes.And:
                    lblBypass = Generator.DefineLabel();
                    lblEnd    = Generator.DefineLabel();

                    PushReal(bn.Left); PushDouble(0.5);
                    Generator.Emit(OpCodes.Ble_S, lblBypass);
                    PushReal(bn.Right); PushDouble(0.5);
                    Generator.Emit(OpCodes.Ble_S, lblBypass);
                    Push(new Complex(1.0, 0.0));
                    Generator.Emit(OpCodes.Br_S, lblEnd);
                    Generator.MarkLabel(lblBypass);
                    Push(new Complex());
                    Generator.MarkLabel(lblEnd);
                    return;

                case NodeTypes.Or:
                    lblBypass = Generator.DefineLabel();
                    lblEnd    = Generator.DefineLabel();

                    PushReal(bn.Left); PushDouble(0.5);
                    Generator.Emit(OpCodes.Bgt_S, lblBypass);
                    PushReal(bn.Right); PushDouble(0.5);
                    Generator.Emit(OpCodes.Bgt_S, lblBypass);
                    Push(new Complex());
                    Generator.Emit(OpCodes.Br_S, lblEnd);
                    Generator.MarkLabel(lblBypass);
                    Push(new Complex(1, 0));
                    Generator.MarkLabel(lblEnd);
                    return;

                case NodeTypes.Xor:
                    PushReal(bn.Left); PushDouble(0.5);
                    Generator.Emit(OpCodes.Cgt);
                    PushReal(bn.Right); PushDouble(0.5);
                    Generator.Emit(OpCodes.Cgt);
                    Generator.Emit(OpCodes.Xor);
                    PushCheck(OpCodes.Brtrue, 1.0, 0.0);
                    return;

                case NodeTypes.Pow:
                    Call(HelperFunctions.Power, new[] { bn.Left, bn.Right });
                    return;
                }
                break;

            case ConstantNode cn:
                Push(new Complex(cn.Literal, 0.0));
                return;

            case UnaryOperatorNode un:

                switch (un.NodeType)
                {
                case NodeTypes.Plus:
                    Push(un.Argument);
                    return;

                case NodeTypes.Minus:
                    Call(Complex.Negate, new[] { un.Argument });
                    return;

                case NodeTypes.Not:
                    PushReal(un.Argument);
                    PushDouble(0.5);
                    PushCheck(OpCodes.Ble_S, 1.0, 0.0);
                    return;
                }
                break;

            case FunctionNode fn:
                var fnargs = new FunctionFoundEventArgs <Complex>(fn, this);
                OnFunctionFound(fnargs);
                if (!fnargs.Created)
                {
                    throw new SpiceSharpException($"Unrecognized function {fn.Name}");
                }
                return;

            case VariableNode vn:
                var varargs = new VariableFoundEventArgs <Complex>(vn);
                OnVariableFound(varargs);
                if (varargs.Variable == null)
                {
                    throw new SpiceSharpException($"Unrecognized variable {vn.Name}");
                }
                var variable = varargs.Variable;
                Call(() => variable.Value);
                return;

            case TernaryOperatorNode tn:
                lblBypass = Generator.DefineLabel();
                lblEnd    = Generator.DefineLabel();
                PushReal(tn.Condition); PushDouble(0.5);
                Generator.Emit(OpCodes.Ble_S, lblBypass);
                Push(tn.IfTrue);
                Generator.Emit(OpCodes.Br_S, lblEnd);
                Generator.MarkLabel(lblBypass);
                Push(tn.IfFalse);
                Generator.MarkLabel(lblEnd);
                return;
            }

            throw new Exception("Unrecognized node {0}".FormatString(node));
        }