private ExprOp Copy(ExprOp left = null, ExprOp right = null) { ExprOp node = NewNode(Kind, left, right); if (Kind < OpKindEnum.TERMINALS) { if (!Data.IsEmpty) { node.Data.SetValue(Data.Value); } } return(node); }
public static ExprOp NewNode(OpKindEnum kind, ExprOp left = null, ExprOp right = null) { ExprOp node = new ExprOp() { Kind = kind }; if (left != null) { node.Left = left; } if (right != null) { node.Right = right; } return(node); }
public void MakeOptionHandlers(OptionCollection options) { if (options == null) { throw new ArgumentNullException("options"); } Tuple <OptionCollection, IDictionary <Option, ExprOp> > optionItems = new Tuple <OptionCollection, IDictionary <Option, ExprOp> > (options, new Dictionary <Option, ExprOp>()); foreach (Option option in options.Options) { optionItems.Item2[option] = ExprOp.WrapFunctor(scope => option.Handler((CallScope)scope)); } LookupKindOptionItems.Add(SymbolKindEnum.OPTION, optionItems); }
public static ExprOp LookupIdent(ExprOp op, Scope scope) { ExprOp def = op.Left; // If no definition was pre-compiled for this identifier, look it up // in the current scope. if (def == null || def.Kind == OpKindEnum.PLUG) { def = scope.Lookup(SymbolKindEnum.FUNCTION, op.AsIdent); } if (def == null) { throw new CalcError(String.Format(CalcError.ErrorMessageUnknownIdentifier, op.AsIdent)); } return(def); }
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 Value Call(Value args, Scope scope, ExprOp locus = null, int depth = 0) { CallScope callArgs = new CallScope(scope, locus, depth + 1); callArgs.Args = args; if (IsFunction) { return(AsFunction(callArgs)); } else if (Kind == OpKindEnum.O_LAMBDA) { return(CallLambda(this, scope, callArgs, locus, depth)); } else { return(FindDefinition(this, scope, locus, depth).Calc(callArgs, locus, depth)); } }
public ExprOp ParseCommaExpr(InputTextStream inStream, AmountParseFlagsEnum tFlags) { ExprOp node = ParseQuerycolonExpr(inStream, tFlags); if (node != null && !tFlags.HasFlag(AmountParseFlagsEnum.PARSE_SINGLE)) { ExprOp next = null; while (true) { ExprToken tok = NextToken(inStream, tFlags | AmountParseFlagsEnum.PARSE_OP_CONTEXT); if (tok.Kind == ExprTokenKind.COMMA) { if (next == null) { ExprOp prev = node; node = new ExprOp(OpKindEnum.O_CONS); node.Left = prev; next = node; } ExprToken ntok = NextToken(inStream, tFlags); PushToken(ntok); if (ntok.Kind == ExprTokenKind.RPAREN) { break; } ExprOp chain = new ExprOp(OpKindEnum.O_CONS); chain.Left = ParseQuerycolonExpr(inStream, tFlags); next.Right = chain; next = chain; } else { PushToken(tok); break; } } } return(node); }
public static ExprOp FindDefinition(ExprOp op, Scope scope, ExprOp locus, int depth, int recursionDepth = 0) { // If the object we are apply call notation to is a FUNCTION value // or a O_LAMBDA expression, then this is the object we want to // call. if (op.IsFunction || op.Kind == OpKindEnum.O_LAMBDA) { return(op); } if (recursionDepth > 256) { throw new ValueError(ValueError.ValueFunctionRecursionDepthTooDeep); } // If it's an identifier, look up its definition and see if it's a // function. if (op.IsIdent) { return(FindDefinition(LookupIdent(op, scope), scope, locus, depth, recursionDepth + 1)); } // Value objects might be callable if they contain an expression. if (op.IsValue) { Value def = op.AsValue; if (Expr.IsExpr(def)) { return(FindDefinition(Expr.AsExpr(def), scope, locus, depth, recursionDepth + 1)); } else { throw new ValueError(String.Format(ValueError.CannotCallSmthAsFunction, def)); } } // Resolve ordinary expressions. return(FindDefinition(WrapValue(op.Calc(scope, locus, depth + 1)), scope, locus, depth + 1, recursionDepth + 1)); }
public ExprOp ParseValueExpr(InputTextStream inStream, AmountParseFlagsEnum tFlags) { ExprOp node = ParseAssingExpr(inStream, tFlags); if (node != null && !tFlags.HasFlag(AmountParseFlagsEnum.PARSE_SINGLE)) { ExprOp chain = null; while (true) { ExprToken tok = NextToken(inStream, tFlags | AmountParseFlagsEnum.PARSE_OP_CONTEXT); if (tok.Kind == ExprTokenKind.SEMI) { ExprOp seq = new ExprOp(OpKindEnum.O_SEQ); if (chain == null) { seq.Left = node; node = seq; } else { seq.Left = chain.Right; chain.Right = seq; } seq.Right = ParseAssingExpr(inStream, tFlags); chain = seq; } else { PushToken(tok); break; } } } return(node); }
public Expr(ExprOp op, Scope context = null) : base(context) { Op = op; }
/// <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; } }
/// <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); }
public ExprOp ParseQuerycolonExpr(InputTextStream inStream, AmountParseFlagsEnum tFlags) { ExprOp node = ParseOrExpr(inStream, tFlags); if (node != null && !tFlags.HasFlag(AmountParseFlagsEnum.PARSE_SINGLE)) { ExprToken tok = NextToken(inStream, tFlags |= AmountParseFlagsEnum.PARSE_OP_CONTEXT); if (tok.Kind == ExprTokenKind.QUERY) { ExprOp prev = node; node = new ExprOp(OpKindEnum.O_QUERY); node.Left = prev; node.Right = ParseOrExpr(inStream, tFlags); if (node.Right == null) { throw new ParseError(String.Format(ParseError.ParseError_OperatorNotFollowedByArgument, tok.Symbol)); } NextToken(inStream, tFlags |= AmountParseFlagsEnum.PARSE_OP_CONTEXT, ExprTokenKind.COLON); prev = node.Right; ExprOp subNode = new ExprOp(OpKindEnum.O_COLON); subNode.Left = prev; subNode.Right = ParseOrExpr(inStream, tFlags); if (subNode.Right == null) { throw new ParseError(String.Format(ParseError.ParseError_OperatorNotFollowedByArgument, tok.Symbol)); } node.Right = subNode; } else if (tok.Kind == ExprTokenKind.KW_IF) { ExprOp ifOp = ParseOrExpr(inStream, tFlags); if (ifOp == null) { throw new ParseError("'if' keyword not followed by argument"); } tok = NextToken(inStream, tFlags |= AmountParseFlagsEnum.PARSE_OP_CONTEXT); if (tok.Kind == ExprTokenKind.KW_ELSE) { ExprOp elseOp = ParseOrExpr(inStream, tFlags); if (elseOp == null) { throw new ParseError("'else' keyword not followed by argument"); } ExprOp subNode = new ExprOp(OpKindEnum.O_COLON); subNode.Left = node; subNode.Right = elseOp; node = new ExprOp(OpKindEnum.O_QUERY); node.Left = ifOp; node.Right = subNode; } else { ExprOp nullNode = new ExprOp(OpKindEnum.VALUE); nullNode.AsValue = Value.Empty; ExprOp subNode = new ExprOp(OpKindEnum.O_COLON); subNode.Left = node; subNode.Right = nullNode; node = new ExprOp(OpKindEnum.O_QUERY); node.Left = ifOp; node.Right = subNode; PushToken(tok); } } else { PushToken(tok); } } return(node); }
public ExprOp ParseLogicExpr(InputTextStream inStream, AmountParseFlagsEnum tFlags) { ExprOp node = ParseAddExpr(inStream, tFlags); if (node != null && !tFlags.HasFlag(AmountParseFlagsEnum.PARSE_SINGLE)) { while (true) { OpKindEnum kind = OpKindEnum.LAST; AmountParseFlagsEnum flags = tFlags; ExprToken tok = NextToken(inStream, tFlags | AmountParseFlagsEnum.PARSE_OP_CONTEXT); bool negate = false; switch (tok.Kind) { case ExprTokenKind.EQUAL: if (tFlags.HasFlag(AmountParseFlagsEnum.PARSE_NO_ASSIGN)) { tok.Rewind(inStream); } else { kind = OpKindEnum.O_EQ; } break; case ExprTokenKind.NEQUAL: kind = OpKindEnum.O_EQ; negate = true; break; case ExprTokenKind.MATCH: kind = OpKindEnum.O_MATCH; break; case ExprTokenKind.NMATCH: kind = OpKindEnum.O_MATCH; negate = true; break; case ExprTokenKind.LESS: kind = OpKindEnum.O_LT; break; case ExprTokenKind.LESSEQ: kind = OpKindEnum.O_LTE; break; case ExprTokenKind.GREATER: kind = OpKindEnum.O_GT; break; case ExprTokenKind.GREATEREQ: kind = OpKindEnum.O_GTE; break; default: PushToken(tok); goto exitLoop; } if (kind != OpKindEnum.LAST) { ExprOp prev = node; node = new ExprOp(kind); node.Left = prev; node.Right = ParseAddExpr(inStream, flags); if (node.Right == null) { throw new ParseError(String.Format(ParseError.ParseError_OperatorNotFollowedByArgument, tok.Symbol)); } if (negate) { prev = node; node = new ExprOp(OpKindEnum.O_NOT); node.Left = prev; } } } } exitLoop: return(node); }