protected override Value RealCalc(Scope scope) { if (Op != null) { ExprOp locus = null; try { return(Op.Calc(scope, locus)); } catch { if (locus != null) { string currentContext = ErrorContext.Current.GetContext(); ErrorContext.Current.AddErrorContext("While evaluating value expression:"); ErrorContext.Current.AddErrorContext(ErrorContext.OpContext(Op, locus)); if (Logger.Current.ShowInfo()) { ErrorContext.Current.AddErrorContext("The value expression tree was:"); ErrorContext.Current.AddErrorContext(Op.Dump()); } if (!String.IsNullOrEmpty(currentContext)) { ErrorContext.Current.AddErrorContext(currentContext); } } throw; } } return(new Value()); }
public override string ContextToStr() { return(Op != null?ErrorContext.OpContext(Op) : "<empty expression>"); }
/// <summary> /// Ported from value_t expr_t::op_t::calc /// </summary> public Value Calc(Scope scope, ExprOp locus = null, int depth = 0) { try { Value result = Value.Empty; Logger.Current.Debug("expr.calc", () => String.Format("{0}{1} => ...", new String('.', depth), ErrorContext.OpContext(this))); switch (Kind) { case OpKindEnum.VALUE: result = AsValue; break; case OpKindEnum.O_DEFINE: result = Value.Empty; break; case OpKindEnum.IDENT: ExprOp definition = LookupIdent(this, scope); if (definition != null) { // Evaluating an identifier is the same as calling its definition // directly result = definition.Calc(scope, locus, depth + 1); CheckTypeContext(scope, result); } break; case OpKindEnum.FUNCTION: // Evaluating a FUNCTION is the same as calling it directly; this // happens when certain functions-that-look-like-variables (such as // "amount") are resolved. CallScope callArgs = new CallScope(scope, locus, depth + 1); result = AsFunction(callArgs); CheckTypeContext(scope, result); break; case OpKindEnum.SCOPE: // assert(! is_scope_unset()); - does not make sense here if (IsScopeUnset) { SymbolScope subscope = new SymbolScope(scope); result = Left.Calc(subscope, locus, depth + 1); } else { BindScope boundScope = new BindScope(scope, AsScope); result = Left.Calc(boundScope, locus, depth + 1); } break; case OpKindEnum.O_LOOKUP: ContextScope contextScope = new ContextScope(scope, ValueTypeEnum.Scope); bool scopeError = true; Value obj = Left.Calc(contextScope, locus, depth + 1); if (obj != null) { if (obj.Type == ValueTypeEnum.Scope && obj.AsScope != null) { BindScope boundScope = new BindScope(scope, obj.AsScope); result = Right.Calc(boundScope, locus, depth + 1); scopeError = false; } } if (scopeError) { throw new CalcError(CalcError.ErrorMessageLeftOperandDoesNotEvaluateToObject); } break; case OpKindEnum.O_CALL: result = CalcCall(scope, locus, depth); CheckTypeContext(scope, result); break; case OpKindEnum.O_LAMBDA: result = Value.Get(this); break; case OpKindEnum.O_MATCH: result = Value.Get(Right.Calc(scope, locus, depth + 1).AsMask.Match(Left.Calc(scope, locus, depth + 1).ToString())); break; case OpKindEnum.O_EQ: result = Value.Get(Left.Calc(scope, locus, depth + 1).IsEqualTo(Right.Calc(scope, locus, depth + 1))); break; case OpKindEnum.O_LT: result = Value.Get(Left.Calc(scope, locus, depth + 1).IsLessThan(Right.Calc(scope, locus, depth + 1))); break; case OpKindEnum.O_LTE: result = Value.Get(!Left.Calc(scope, locus, depth + 1).IsGreaterThan(Right.Calc(scope, locus, depth + 1))); break; case OpKindEnum.O_GT: result = Value.Get(Left.Calc(scope, locus, depth + 1).IsGreaterThan(Right.Calc(scope, locus, depth + 1))); break; case OpKindEnum.O_GTE: result = Value.Get(!Left.Calc(scope, locus, depth + 1).IsLessThan(Right.Calc(scope, locus, depth + 1))); break; case OpKindEnum.O_ADD: result = Left.Calc(scope, locus, depth + 1) + Right.Calc(scope, locus, depth + 1); break; case OpKindEnum.O_SUB: result = Left.Calc(scope, locus, depth + 1) - Right.Calc(scope, locus, depth + 1); break; case OpKindEnum.O_MUL: result = Left.Calc(scope, locus, depth + 1) * Right.Calc(scope, locus, depth + 1); break; case OpKindEnum.O_DIV: result = Left.Calc(scope, locus, depth + 1) / Right.Calc(scope, locus, depth + 1); break; case OpKindEnum.O_NEG: result = Left.Calc(scope, locus, depth + 1).Negated(); break; case OpKindEnum.O_NOT: result = Value.Get(!Left.Calc(scope, locus, depth + 1).Bool); break; case OpKindEnum.O_AND: if (Left.Calc(scope, locus, depth + 1).Bool) { result = Right.Calc(scope, locus, depth + 1); } else { result = Value.Get(false); } break; case OpKindEnum.O_OR: Value temp_O_OR = Left.Calc(scope, locus, depth + 1); if (temp_O_OR.Bool) { result = temp_O_OR; } else { result = Right.Calc(scope, locus, depth + 1); } break; case OpKindEnum.O_QUERY: if (Right == null || Right.Kind != OpKindEnum.O_COLON) { throw new InvalidOperationException("O_QUERY"); } Value temp = Left.Calc(scope, locus, depth + 1); if (temp.Bool) { result = Right.Left.Calc(scope, locus, depth + 1); } else { result = Right.Right.Calc(scope, locus, depth + 1); } break; case OpKindEnum.O_COLON: throw new InvalidOperationException("We should never calculate an O_COLON operator"); case OpKindEnum.O_CONS: result = CalcCons(scope, locus, depth); break; case OpKindEnum.O_SEQ: result = CalcSeq(scope, locus, depth); break; default: throw new CalcError(String.Format(CalcError.ErrorMessageUnexpectedExprNode, this)); } Logger.Current.Debug("expr.calc", () => String.Format("{0}{1} => {2}", new String('.', depth), ErrorContext.OpContext(this), result.Dump(true))); return(result); } catch { if (locus == null) { locus = this; } throw; } }