private Value CallLambda(ExprOp func, Scope scope, CallScope callArgs, ExprOp locus, int depth) { int argsIndex = 0; long argsCount = callArgs.Size; SymbolScope argsScope = new SymbolScope(Scope.EmptyScope); for (ExprOp sym = func.Left; sym != null; sym = sym.HasRight ? sym.Right : null) { ExprOp varName = sym.Kind == OpKindEnum.O_CONS ? sym.Left : sym; if (!varName.IsIdent) { throw new CalcError(CalcError.ErrorMessageInvalidFunctionDefinition); } if (argsIndex == argsCount) { Logger.Current.Debug("expr.calc", () => String.Format("Defining function argument as null: {0}", varName.AsIdent)); argsScope.Define(SymbolKindEnum.FUNCTION, varName.AsIdent, WrapValue(Value.Empty)); } else { Logger.Current.Debug("expr.calc", () => String.Format("Defining function argument from call_args: {0}", varName.AsIdent)); argsScope.Define(SymbolKindEnum.FUNCTION, varName.AsIdent, WrapValue(callArgs[argsIndex++])); } } if (argsIndex < argsCount) { throw new CalcError(String.Format(CalcError.ErrorMessageTooFewArgumentsInFunctionCall, argsCount, argsIndex)); } if (func.Right.IsScope) { BindScope outerScope = new BindScope(scope, func.Right.AsScope); BindScope boundScope = new BindScope(outerScope, argsScope); return(func.Right.Left.Calc(boundScope, locus, depth + 1)); } else { return(func.Right.Calc(argsScope, locus, depth + 1)); } }
public void SymbolScope_Define_AddsSymbolToSymbols() { MockScope mockScope = new MockScope(); SymbolScope symbolScope = new SymbolScope(mockScope); SymbolKindEnum kind = SymbolKindEnum.FUNCTION; string name = "the-name"; ExprOp exprOp = new ExprOp(OpKindEnum.CONSTANTS); symbolScope.Define(kind, name, exprOp); Assert.Equal(1, symbolScope.Symbols.Count); Assert.Equal(kind, symbolScope.Symbols.First().Key.Kind); Assert.Equal(name, symbolScope.Symbols.First().Key.Name); Assert.Equal(exprOp, symbolScope.Symbols.First().Key.Definition); Assert.Equal(exprOp, symbolScope.Symbols[symbolScope.Symbols.First().Key]); }
public void SymbolScope_Lookup_TriesGetAValueFromSymbols() { MockScope mockScope = new MockScope(); SymbolScope symbolScope = new SymbolScope(mockScope); SymbolKindEnum kind = SymbolKindEnum.FUNCTION; string name = "the-name"; ExprOp exprOp = new ExprOp(OpKindEnum.CONSTANTS); symbolScope.Define(kind, name, exprOp); ExprOp result = symbolScope.Lookup(kind, name); Assert.Equal(exprOp, result); ExprOp result2 = symbolScope.Lookup(SymbolKindEnum.OPTION, "dummy"); Assert.Equal(mockScope.LookupResult, result2); }
/// <summary> /// Ported from expr_t::ptr_op_t expr_t::op_t::compile /// </summary> public ExprOp Compile(Scope scope, int depth = 0, Scope paramScope = null) { ExprOp result = null; Scope boundScope; Logger.Current.Debug("expr.compile", () => new String('.', depth)); if (Kind >= OpKindEnum.LAST) { throw new InvalidOperationException(); } if (IsIdent) { Logger.Current.Debug("expr.compile", () => String.Format("Lookup: {0} in {1}", AsIdent, scope)); ExprOp def = null; if (paramScope != null) { def = paramScope.Lookup(SymbolKindEnum.FUNCTION, AsIdent); } if (def == null) { def = scope.Lookup(SymbolKindEnum.FUNCTION, AsIdent); } if (def != null) { // Identifier references are first looked up at the point of // definition, and then at the point of every use if they could // not be found there. Logger.Current.Debug("expr.compile", () => String.Format("Found definition:{0}", def.Dump())); result = Copy(def); } else if (Left != null) { result = Copy(); } else { result = this; } } else if (IsScope) { Scope subScope = new SymbolScope(Scope.EmptyScope); AsScope = subScope; boundScope = new BindScope(scope, subScope); scope = boundScope; } else if (Kind < OpKindEnum.TERMINALS) { result = this; } else if (Kind == OpKindEnum.O_DEFINE) { switch (Left.Kind) { case OpKindEnum.IDENT: { ExprOp node = Right.Compile(scope, depth + 1, paramScope); Logger.Current.Debug("expr.compile", () => String.Format("Defining {0} in {1}", Left.AsIdent, scope)); scope.Define(SymbolKindEnum.FUNCTION, Left.AsIdent, node); } break; case OpKindEnum.O_CALL: if (Left.Left.IsIdent) { ExprOp node = new ExprOp(OpKindEnum.O_LAMBDA); node.Left = Left.Right; node.Right = Right; node.Compile(scope, depth + 1, paramScope); Logger.Current.Debug("expr.compile", () => String.Format("Defining {0} in {1}", Left.Left.AsIdent, scope)); scope.Define(SymbolKindEnum.FUNCTION, Left.Left.AsIdent, node); break; } throw new CompileError(CompileError.ErrorMessageInvalidFunctionDefinition); default: throw new CompileError(CompileError.ErrorMessageInvalidFunctionDefinition); } result = WrapValue(Value.Empty); } else if (Kind == OpKindEnum.O_LAMBDA) { SymbolScope parms = new SymbolScope(paramScope ?? Scope.EmptyScope); for (ExprOp sym = Left; sym != null; sym = sym.HasRight ? sym.Right : null) { ExprOp varName = sym.Kind == OpKindEnum.O_CONS ? sym.Left : sym; if (!varName.IsIdent) { string buf = varName.Dump(); throw new CalcError(String.Format(CalcError.ErrorMessageInvalidFunctionOrLambdaParameter, buf)); } else { Logger.Current.Debug("expr.compile", () => String.Format("Defining function parameter {0}", varName.AsIdent)); parms.Define(SymbolKindEnum.FUNCTION, varName.AsIdent, new ExprOp(OpKindEnum.PLUG)); } } ExprOp rhs = Right.Compile(scope, depth + 1, parms); if (rhs == Right) { result = this; } else { result = Copy(Left, rhs); } } if (result == null) { if (Left == null) { throw new CalcError(CalcError.ErrorMessageSyntaxError); } ExprOp lhs = Left.Compile(scope, depth + 1, paramScope); ExprOp rhs = Kind > OpKindEnum.UNARY_OPERATORS && HasRight ? (Kind == OpKindEnum.O_LOOKUP ? Right : Right.Compile(scope, depth + 1, paramScope)) : null; if (lhs == Left && (rhs == null || rhs == Right)) { result = this; } else { ExprOp intermediate = Copy(lhs, rhs); // Reduce constants immediately if possible if ((lhs == null || lhs.IsValue) && (rhs == null || rhs.IsValue)) { result = WrapValue(intermediate.Calc(scope, null, depth + 1)); } else { result = intermediate; } } } Logger.Current.Debug("expr.compile", () => new String('.', depth)); return(result); }
/// <summary> /// Ported from void posts_to_org_table::operator()(post_t& post) /// </summary> public override void Handle(Post post) { if (!post.HasXData || !post.XData.Displayed) { StringBuilder sb = new StringBuilder(); BindScope boundScope = new BindScope(Report, post); if (!HeaderPrinted) { sb.AppendLine("|Date|Code|Payee|X|Account|Amount|Total|Note|"); sb.AppendLine("|-|"); sb.AppendLine("|||<20>|||<r>|<r>|<20>|"); HeaderPrinted = true; } if (!String.IsNullOrEmpty(ReportTitle)) { if (FirstReportTitle) { FirstReportTitle = false; } else { sb.AppendLine(); } ValueScope valScope = new ValueScope(boundScope, Value.StringValue(ReportTitle)); Format groupTitleFormat = new Format(Report.GroupTitleFormatHandler.Str()); sb.AppendLine("|-|"); sb.Append("|" + groupTitleFormat.Calc(valScope)); sb.AppendLine("|-|"); ReportTitle = String.Empty; } if (PrependFormat != null) { sb.Append("|" + PrependFormat.Calc(boundScope)); } if (LastXact != post.Xact) { sb.Append(FirstLineFormat.Calc(boundScope)); LastXact = post.Xact; } else if (LastPost != null && LastPost.GetDate() != post.GetDate()) { sb.Append(FirstLineFormat.Calc(boundScope)); } else { sb.Append(NextLineFormat.Calc(boundScope)); } Value amt = new Expr("display_amount").Calc(boundScope).Simplified(); Value tot = new Expr("display_total").Calc(boundScope).Simplified(); if (amt.Type == ValueTypeEnum.Balance || tot.Type == ValueTypeEnum.Balance) { Balance amtBal = amt.AsBalance; Balance totBal = tot.AsBalance; var i = amtBal.Amounts.GetIterator(); var j = totBal.Amounts.GetIterator(); bool first = true; while (!i.IsEnd || !j.IsEnd) { if (first) { first = false; if (!i.IsEnd) { i.MoveNext(); } if (!j.IsEnd) { j.MoveNext(); } } else { SymbolScope callScope = new SymbolScope(boundScope); bool assigned = false; if (!i.IsEnd) { if (i.Current.Value != null) { Logger.Current.Debug(DebugOrgNextAmount, () => String.Format("next_amount = {0}", i.Current.Value)); callScope.Define(SymbolKindEnum.FUNCTION, "next_amount", ExprOp.WrapValue(Value.Get(i.Current.Value))); i.MoveNext(); assigned = true; } else { callScope.Define(SymbolKindEnum.FUNCTION, "next_amount", ExprOp.WrapValue(Value.StringValue(String.Empty))); i.MoveNext(); } } else { callScope.Define(SymbolKindEnum.FUNCTION, "next_amount", ExprOp.WrapValue(Value.StringValue(String.Empty))); } if (!j.IsEnd) { if (j.Current.Value != null) { Logger.Current.Debug(DebugOrgNextTotal, () => String.Format("next_total = {0}", j.Current.Value)); callScope.Define(SymbolKindEnum.FUNCTION, "next_total", ExprOp.WrapValue(Value.Get(j.Current.Value))); j.MoveNext(); Logger.Current.Debug(DebugOrgNextTotal, () => String.Format("2.next_total = {0}", callScope.Lookup(SymbolKindEnum.FUNCTION, "next_total").AsValue)); assigned = true; } else { callScope.Define(SymbolKindEnum.FUNCTION, "next_total", ExprOp.WrapValue(Value.StringValue(String.Empty))); j.MoveNext(); } } else { callScope.Define(SymbolKindEnum.FUNCTION, "next_total", ExprOp.WrapValue(Value.StringValue(String.Empty))); } if (assigned) { AmountLinesFormat.MarkUncomplited(); sb.Append(AmountLinesFormat.Calc(callScope)); } } } } post.XData.Displayed = true; LastPost = post; Report.OutputStream.Write(sb.ToString()); } }