Power operator implementation

May 9, 2012 at 3:29 PM
Edited May 10, 2012 at 1:52 PM

Hi there,

It seems, that the power operator is not yet implemented (at least in the archive available in the download section). As a quick & dirty workaround people might consider derivating their own LanguageRuntime (or add the code directely at InitBinaryOperatorImplementationsForMatchedTypes ):

public class MyLanguageRuntime : LanguageRuntime
    {
        public MyLanguageRuntime(LanguageData language)
        : base(language)
        {
        }

        public override void InitBinaryOperatorImplementationsForMatchedTypes()
        {
            // let's add the powerfunction implementation here such that the 
            // base class adds all the convenience functions (overflow check, 
            // type conversions) on its own
            var op = ExpressionType.Power;
            AddBinary(op, typeof(Int32), (x, y) => checked((Int32)Math.Pow((Int32)x, (Int32)y)));
            AddBinary(op, typeof(UInt32), (x, y) => checked((UInt32)Math.Pow((UInt32)x, (UInt32)y)));
            AddBinary(op, typeof(Int64), (x, y) => checked((Int64)Math.Pow((Int64)x, (Int64)y)));
            AddBinary(op, typeof(UInt64), (x, y) => checked((UInt64)Math.Pow((UInt64)x, (UInt64)y)));
            AddBinary(op, typeof(Single), (x, y) => checked((Single)Math.Pow((Single)x, (Single)y)));
            AddBinary(op, typeof(double), (x, y) => checked(Math.Pow((double)x, (double)y)));

            // continue with the base implementation
            base.InitBinaryOperatorImplementationsForMatchedTypes();
        }
    }

If someone has a hint, how to elegantly change the operator mapping from '**' to '^', I would be very happy.

Best regards,

Lukas

Coordinator
May 11, 2012 at 5:08 AM

operator mappings (symbol - ExpressionType) are defined in OperatorHandler class which is passed to AstInterpreterContext constructor. 

You can inherit from this class and redefine power mapping. Yeah, it's a bit too complicated for such a simple thing, we should simplify it in the future

May 11, 2012 at 11:55 AM

Hi Roman,

Thanks for pointing that out (and for your very nice framework)! Hope, this thread helps someone in the feature.

Cheers,
Lukas

May 20, 2014 at 3:35 PM
Maybe it will help someone. To change the Operator mapping for Power I inherited from OperatorHandler like this:
    public class FormulaLanguageOperatorHandler : OperatorHandler
    {
        public FormulaLanguageOperatorHandler(bool languageCaseSensitive)
            : base(languageCaseSensitive)
        {
        }

        public override OperatorInfoDictionary BuildDefaultOperatorMappings()
        {
            var dict = base.BuildDefaultOperatorMappings();
            var operatorInfo = dict["^"];
            operatorInfo.ExpressionType = System.Linq.Expressions.ExpressionType.Power;
            operatorInfo.Precedence = dict["**"].Precedence;
            return dict;
        }
    }
And I pass it to AstInterpreterContext in InterpretedLanguageGrammar.BuildAst:
    public class FormulaGrammer : InterpretedLanguageGrammar
    {
        ...

        public override void BuildAst(LanguageData language, ParseTree parseTree)
        {
            var opHandler = new FormulaLanguageOperatorHandler(language.Grammar.CaseSensitive);
            Util.Check(!parseTree.HasErrors(), "ParseTree has errors, cannot build AST.");
            var astContext = new InterpreterAstContext(language, opHandler);
            var astBuilder = new Irony.Ast.AstBuilder(astContext);
            astBuilder.BuildAst(parseTree);
        }
    }
Works great for me.