示例#1
0
        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);
        }
示例#2
0
        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);
        }
示例#3
0
        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);
        }
示例#4
0
        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);
        }
示例#5
0
        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));
            }
        }
示例#6
0
        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));
            }
        }
示例#7
0
        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);
        }
示例#8
0
        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));
        }
示例#9
0
        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);
        }
示例#10
0
文件: Expr.cs 项目: taiab/nledger
 public Expr(ExprOp op, Scope context = null)
     : base(context)
 {
     Op = op;
 }
示例#11
0
        /// <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;
            }
        }
示例#12
0
        /// <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);
        }
示例#13
0
        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);
        }
示例#14
0
        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);
        }