public (Value success, Value cost, Value result) CompileMatchCase(Value matchWith, MatchCase matchCase) { LabelTarget failLabel = Expression.Label("fail"); LabelTarget finishLabel = Expression.Label("finish"); var successVar = Expression.Parameter(typeof(bool), "success"); var costVar = Expression.Parameter(typeof(int), "cost"); var compiler = new FunctionCompiler(scope); var matcher = new Matcher( compiler, implicitVariables: matchCase.ImplicitVariables ); var instr = new List <Expression>(); instr.Add(matcher.CompileMatch(matchWith, matchCase.MatchedValue, failLabel, MatchKind.exact)); foreach (var variable in matchCase.ImplicitVariables) { if (matcher.implicitVars[variable.name] == null) { throw new Exception($"{variable.name} was not instantiated at {matchCase.Location}"); } var value = matcher.implicitVars[variable.name]; if (variable.type.IsSome()) { var coerceResult = compiler.CompileCoerce(value, CompileExpr(variable.type.Get())); // TODO: this should always succeed due to type constraints instr.Add(Expression.IfThenElse( coerceResult.success.Expression, Expression.Block( Expression.AddAssign(costVar, coerceResult.cost.Expression), scope.CreateVariable(variable.name, coerceResult.value)), Expression.Goto(failLabel))); } else { instr.Add(scope.CreateVariable(variable.name, value)); } } instr.Add(Expression.Assign(successVar, Expression.Constant(true))); instr.Add(Expression.Goto(finishLabel)); instr.Add(Expression.Label(failLabel)); instr.Add(Expression.Assign(successVar, Expression.Constant(false))); instr.Add(Expression.Label(finishLabel)); return(Value.Seq(instr, Value.Dynamic(successVar)), Value.Dynamic(costVar), compiler.CompileExpr(matchCase.Body)); }
public Matcher(FunctionCompiler compiler, List <(string name, Optional <Expr> type)> implicitVariables)