public ImmutableHashSet <object> VisitZenListCaseExpr <TList, TResult>(ZenListCaseExpr <TList, TResult> expression, Unit parameter) { return(LookupOrCompute(expression, () => { var x = expression.ListExpr.Accept(this, parameter); var e = expression.EmptyCase.Accept(this, parameter); return x.Union(e); // no easy way to evaluate cons case. })); }
public Expression VisitZenListCaseExpr <TList, TResult>(ZenListCaseExpr <TList, TResult> expression, ExpressionConverterEnvironment parameter) { return(LookupOrCompute(expression, () => { var immutableListType = typeof(ImmutableList <TList>); // compile the list expression var listExpr = expression.ListExpr.Accept(this, parameter); // Console.WriteLine($"listExpr: {listExpr}"); // cast to an immutable list, since it will return IList var toImmutableListMethod = typeof(CommonUtilities) .GetMethodCached("ToImmutableList") .MakeGenericMethod(typeof(TList)); var immutableListExpr = Expression.Call(toImmutableListMethod, listExpr); var listVariable = FreshVariable(immutableListType); this.Variables.Add(listVariable); this.BlockExpressions.Add(Expression.Assign(listVariable, immutableListExpr)); // check if list is empty, if so return the empty case var isEmptyExpr = Expression.PropertyOrField(listVariable, "IsEmpty"); // call SplitHead to get the tuple result. var splitMethod = typeof(CommonUtilities).GetMethodCached("SplitHead").MakeGenericMethod(typeof(TList)); var splitExpr = Expression.Call(splitMethod, listVariable); var splitVariable = FreshVariable(typeof(ValueTuple <TList, IList <TList> >)); // extract the head and tail var hdExpr = Expression.PropertyOrField(splitVariable, "Item1"); var tlExpr = Expression.PropertyOrField(splitVariable, "Item2"); // compile the empty expression var emptyExpr = expression.EmptyCase.Accept(this, parameter); // run the cons lambda var runMethod = typeof(Interpreter) .GetMethodCached("CompileRunHelper") .MakeGenericMethod(typeof(TList), typeof(IList <TList>), typeof(TResult)); // create the bound arguments by constructing the immutable list var dictType = typeof(ImmutableDictionary <long, object>); var dictField = dictType.GetFieldCached("Empty"); Expression argsExpr = Expression.Field(null, dictField); var dictAddMethod = dictType.GetMethodCached("Add"); foreach (var kv in parameter.ArgumentAssignment) { argsExpr = Expression.Call( argsExpr, dictAddMethod, Expression.Constant(kv.Key), Expression.Convert(kv.Value, typeof(object))); } // either unroll the match one level, or hand off the the interpreter. Expression consExpr; if (this.currentMatchUnrollingDepth == this.maxMatchUnrollingDepth) { var function = Expression.Constant(expression.ConsCase); consExpr = Expression.Call(runMethod, function, hdExpr, tlExpr, argsExpr); } else { var newAssignment = parameter.ArgumentAssignment; var argHd = new ZenArgumentExpr <TList>(); newAssignment = newAssignment.Add(argHd.ArgumentId, hdExpr); var argTl = new ZenArgumentExpr <IList <TList> >(); newAssignment = newAssignment.Add(argTl.ArgumentId, tlExpr); var zenConsExpr = expression.ConsCase(argHd, argTl); consExpr = CodeGenerator.CompileToBlock( zenConsExpr, new ExpressionConverterEnvironment(newAssignment), this.SubexpressionCache, this.currentMatchUnrollingDepth + 1, this.maxMatchUnrollingDepth); } var nonEmptyBlock = Expression.Block( new List <ParameterExpression> { splitVariable }, Expression.Assign(splitVariable, splitExpr), consExpr); return Expression.Condition(isEmptyExpr, emptyExpr, nonEmptyBlock); })); }