나는 구문 트리를 얻기 위해 연산자 오버로딩을 사용하는 것이 최선의 방법은 아니라고 생각합니다. 아마도 구문 트리를 탐색하여 필요한 정보를 추출하는 것이 좋습니다. 슬프게도 C# 람다 식의 AST는 IronPython AST와 호환되지 않습니다. 그래서 IronPython AST를 Linq AST로 변환하는 변환 프로 시저를 설정했습니다. | &와 함께
static System.Linq.Expressions.Expression GetLinqExpressionFromPyExpression(string pyExpression, ScriptScope scope)
{
ScriptEngine engine = scope.Engine;
ScriptSource source =
engine.CreateScriptSourceFromString(pyExpression, SourceCodeKind.Expression);
SourceUnit sourceUnit = HostingHelpers.GetSourceUnit(source);
LanguageContext context = HostingHelpers.GetLanguageContext(engine);
Parser parser = Parser.CreateParser(
new CompilerContext(sourceUnit, context.GetCompilerOptions(), ThrowingErrorSink.Default),
(PythonOptions)context.Options);
PythonAst ast = parser.ParseFile(true);
SuiteStatement suite = (SuiteStatement)ast.Body;
ExpressionStatement statement = (ExpressionStatement)suite.Statements[0];
IronPython.Compiler.Ast.Expression expression = statement.Expression;
return Convert(expression, scope);
}
static readonly Dictionary<PythonOperator, ExpressionType> linqOpFromPyOp = new Dictionary<PythonOperator, ExpressionType>{
{ PythonOperator.Not, System.Linq.Expressions.ExpressionType.Not },
{ PythonOperator.Pos, System.Linq.Expressions.ExpressionType.UnaryPlus },
{ PythonOperator.Invert, System.Linq.Expressions.ExpressionType.OnesComplement },
{ PythonOperator.Negate, System.Linq.Expressions.ExpressionType.NegateChecked },
{ PythonOperator.Add, System.Linq.Expressions.ExpressionType.AddChecked },
{ PythonOperator.Subtract, System.Linq.Expressions.ExpressionType.SubtractChecked },
{ PythonOperator.Multiply, System.Linq.Expressions.ExpressionType.MultiplyChecked },
{ PythonOperator.Divide, System.Linq.Expressions.ExpressionType.Divide },
{ PythonOperator.TrueDivide, System.Linq.Expressions.ExpressionType.Divide },
{ PythonOperator.Mod, System.Linq.Expressions.ExpressionType.Modulo },
{ PythonOperator.BitwiseAnd, System.Linq.Expressions.ExpressionType.And },
{ PythonOperator.BitwiseOr, System.Linq.Expressions.ExpressionType.Or },
{ PythonOperator.ExclusiveOr, System.Linq.Expressions.ExpressionType.ExclusiveOr },
{ PythonOperator.LeftShift, System.Linq.Expressions.ExpressionType.LeftShift },
{ PythonOperator.RightShift, System.Linq.Expressions.ExpressionType.RightShift },
{ PythonOperator.Power, System.Linq.Expressions.ExpressionType.Power },
//{ PythonOperator.FloorDivide, System.Linq.Expressions.ExpressionType.Divide }, // TODO
{ PythonOperator.LessThan, System.Linq.Expressions.ExpressionType.LessThan },
{ PythonOperator.LessThanOrEqual, System.Linq.Expressions.ExpressionType.LessThanOrEqual },
{ PythonOperator.GreaterThan, System.Linq.Expressions.ExpressionType.GreaterThan },
{ PythonOperator.GreaterThanOrEqual, System.Linq.Expressions.ExpressionType.GreaterThanOrEqual },
{ PythonOperator.Equal, System.Linq.Expressions.ExpressionType.Equal },
{ PythonOperator.NotEqual, System.Linq.Expressions.ExpressionType.NotEqual },
//{ PythonOperator.In, System.Linq.Expressions.ExpressionType. }, // TODO
//{ PythonOperator.NotIn, System.Linq.Expressions.ExpressionType. }, // TODO
//{ PythonOperator.IsNot, System.Linq.Expressions.ExpressionType.TypeIs }, // TODO
{ PythonOperator.Is, System.Linq.Expressions.ExpressionType.TypeIs },
};
static System.Linq.Expressions.Expression Convert(IronPython.Compiler.Ast.Expression node, ScriptScope scope)
{
switch (node.NodeName)
{
case "AndExpression":
{
var _node = (IronPython.Compiler.Ast.AndExpression)node;
return System.Linq.Expressions.BinaryExpression.AndAlso(
Convert(_node.Left, scope),
Convert(_node.Right, scope));
}
case "BinaryExpression":
{
var _node = (IronPython.Compiler.Ast.BinaryExpression)node;
// TODO: do conversion if left and right have different types
return System.Linq.Expressions.BinaryExpression.MakeBinary(
linqOpFromPyOp[_node.Operator],
Convert(_node.Left, scope),
Convert(_node.Right, scope));
}
case "OrExpression":
{
var _node = (IronPython.Compiler.Ast.OrExpression)node;
return System.Linq.Expressions.BinaryExpression.OrElse(
Convert(_node.Left, scope),
Convert(_node.Right, scope));
}
case "NameExpression":
{
var _node = (IronPython.Compiler.Ast.NameExpression)node;
return System.Linq.Expressions.Expression.Parameter(
scope.GetVariable(_node.Name).GetType(),
_node.Name);
}
// TODO: Add further Python Expression types
default:
throw new ArgumentTypeException("unhandled NodeType '" + node.NodeName + "'");
}
}
internal class ThrowingErrorSink : ErrorSink
{
public static new readonly ThrowingErrorSink/*!*/ Default = new ThrowingErrorSink();
private ThrowingErrorSink() { }
public override void Add(SourceUnit sourceUnit, string message, SourceSpan span, int errorCode, Severity severity)
{
if (severity == Severity.Warning)
{
PythonOps.SyntaxWarning(message, sourceUnit, span, errorCode);
}
else
{
throw PythonOps.SyntaxError(message, sourceUnit, span, errorCode);
}
}
}
문제 :
그리고 여기에 (불완전한) 변환 절차입니다 :
출력은 비교 연산자 (==, <, >, ...)보다 적게 바인딩하므로 "a == b | b == c"와 같이 뭔가 부 자연스럽게 보이는 괄호 만 사용합니다. "not"라고 쓰면 이상하지만, &와 |를 사용해야합니다. 인스 티 언트 및/또는 – Rauhotz
그 이유는 내가 단서 회로 연산자를 오버로드 할 수 없기 때문에, 당신이 만날 의도가있는 정확한 동작을 달성 할 수 없다는 것입니다. –