0

我正在 IronPython 中实现 DSL。

假设我有一个用 C# 实现的值层次结构,要在 Iron python 中使用:

 public abstract Value
 {

 }

 public abstract DoubleValue : Value
 {
   // Constructors...      

   public double magnitude;

   // Arithmetic operators overloaded...
 }

 public abstract FractionValue : Value
 {
   // Constructors....

   public int numerator;
   public int denominator;

   // Arithmetic operators overloaded...
 }

由于 C# 中的运算符重载,我可以在 Python 中执行此操作:

 # a, b are of type Value
 def Sum(a,b):
    return a + b

一切正常,该函数返回一个类型 = 值的对象。

但如果我想使用 PythonConstant:

 # a is of type Value
 def Sum5(a):
     return a + 5

你得到一个错误类型,因为常量 5 不是 Value 类型。

一种解决方案是重载 + 运算符以工作整数,例如:

public DoubleValue operator+(DoubleValue, int)

但是随后您会得到大量可能的组合,并最终在 Value 框架中出现数百个重载。无论如何,您仍然会遇到此问题:

def ReturnFive():
    return 5

在这种情况下,返回的值不是 Value 类型,您应该执行以下操作:

def ReturnFive():
    return DoubleValue(5.0)

但这对我的 DSL 来说是一种非常丑陋的语法。

你会推荐什么?

非常感谢。

4

1 回答 1

1

这是 DSEL 的主要问题:它们并不总是与原生类型很好地配合。通常你需要包装原生类型;一种选择是引入一个名称非常短的函数(例如_),它包装传入的值并触发运算符重载。

IronPython 只有三种感兴趣的数字类型——System.Int32 (int)、System.Double (float) 和 System.Numerics.BigInteger (long)——所以没有太多需要处理的情况。

在 C# 方面,你会有类似的东西:

class Value {
    static Value WrapLiteral(object literal) {
        if(literal is System.Double) {
            return DoubleValue((System.Double)literal);
        } // etc ...
    }
}

当您为用户脚本创建范围时,使用短名称添加该函数:

scope.SetVariable("_", Value.WrapLiteral);

然后从用户端,用户只需要做:

def ReturnFive():
    return _(5)

它仍然有点难看,但还不错。

于 2012-06-01T22:10:19.253 回答