Esempio n. 1
0
            internal override Value Eval(DelimiterNode prev, DelimiterNode next, IScope paramScope, IScope bodyScope, INodeRequestor nodes, ILineRequestor requestor)
            {
                // if we need prev or next params but they're not there, simply return the function
                if ((m_usePrevious || m_useNext) && prev == null && next == null)
                    return this;

                // scope we'll add prev/next/body params to
                ScopeChain localScope = new ScopeChain();

                if (m_usePrevious)
                {
                    if (prev == null)
                    {
                        if (m_useNext)
                            return new PartialFunctionIn(this, null, next);
                        throw new Loki3Exception().AddMissingValue(true/*bPrevious*/);
                    }

                    Value value1 = ComputeParam(Metadata[keyPreviousPattern], prev, paramScope, nodes, requestor);
                    Value match, leftover;
                    if (!PatternChecker.Do(value1, Metadata[keyPreviousPattern], false/*bShortPat*/, out match, out leftover))
                        throw new Loki3Exception().AddWrongPattern(Metadata[keyPreviousPattern], value1);

                    if (leftover != null)
                    {
                        if (m_useNext)
                            // currently can't do partials for infix
                            throw new Loki3Exception().AddWrongPattern(Metadata[keyPreviousPattern], value1);
                        // create a partial function that starts w/ match & still needs leftover
                        return new UserFunction(this, match, leftover, null);
                    }

                    Utility.AddToScope(m_pattern1, match, localScope);
                }
                if (m_useNext)
                {
                    if (next == null)
                    {
                        if (m_usePrevious)
                            return new PartialFunctionIn(this, prev, null);
                        throw new Loki3Exception().AddMissingValue(false/*bPrevious*/);
                    }

                    Value value2 = ComputeParam(Metadata[keyNextPattern], next, paramScope, nodes, requestor);
                    Value match, leftover;
                    if (!PatternChecker.Do(value2, Metadata[keyNextPattern], false/*bShortPat*/, out match, out leftover))
                        throw new Loki3Exception().AddWrongPattern(Metadata[keyNextPattern], value2);

                    // if we created a function that needs a body, add it if present
                    ValueFunction matchFunc = match as ValueFunction;
                    if (matchFunc != null && matchFunc.RequiresBody() && requestor != null)
                        match = EvalList.DoAddBody(matchFunc, bodyScope, requestor);

                    if (leftover != null)
                    {
                        if (m_usePrevious)
                            // currently can't do partials for infix
                            throw new Loki3Exception().AddWrongPattern(Metadata[keyNextPattern], value2);
                        // create a partial function that starts w/ match & still needs leftover
                        return new UserFunction(this, match, null, leftover);
                    }

                    Utility.AddToScope(m_pattern2, match, localScope);
                }

                // tack on body if requested
                if (Metadata.GetOptionalT<bool>("body?", false))
                {
                    bool foundBody = false;

                    // if there's a following node, use it
                    DelimiterNode possibleBody = nodes.GetNext();
                    if (possibleBody != null)
                    {
                        localScope.SetValue("body", UseNodeAsBody(possibleBody));
                        foundBody = true;
                    }

                    // if no body, use the following lines
                    if (!foundBody && requestor != null)
                    {
                        List<DelimiterList> body = EvalList.DoGetBody(bodyScope, requestor);
                        if (body.Count != 0)
                        {
                            localScope.SetValue("body", new ValueLine(body, bodyScope));
                            foundBody = true;
                        }
                    }

                    if (!foundBody)
                        // create a partial function that only needs a body
                        return new UserFunction(this, localScope);
                }

                // create a new scope and add passed in arguments...
                ScopeChain scope = (ShouldCreateScope ? new ScopeChain(bodyScope) : bodyScope as ScopeChain);
                scope.Function = this;
                if (m_fullPattern != null && m_passed != null)
                    Utility.AddToScope(m_fullPattern, m_passed, scope);
                // ...and the prev/next/body params we just extracted
                Utility.AddToScope(localScope, scope);
                if (m_passedScope != null)
                    Utility.AddToScope(m_passedScope, scope);

                // lazily parse
                EnsureParsed(bodyScope);

                // eval each line using current scope
                try
                {
                    Value retval = EvalBody.Do(m_parsedLines, scope);
                    scope.Exit();
                    return retval;
                }
                catch (PopStackException pop)
                {	// if we're supposed to pop back to here then return, else keep throwing up the stack
                    if (pop.ScopeName == scope.Name)
                        return pop.Return;
                    throw pop;
                }
                catch (Loki3Exception e)
                {	// if this scope catches exceptions, stop here
                    if (Loki3Exception.catchScopeName == scope.Name)
                    {
                        if (scope.Parent != null)
                            scope.Parent.SetValue(Loki3Exception.exceptionKey, new ValueMap(e.Errors));
                        return ValueNil.Nil;
                    }
                    throw e;
                }
            }
Esempio n. 2
0
        /// <summary>
        /// Evaluates a token, possibly requesting the previous and next values.
        /// Returns a value.
        /// </summary>
        /// <param name="token">token representing a function or variable</param>
        /// <param name="scope">used to request functions, variables, and delimiters if there's no scope attached to the node</param>
        /// <param name="nodes">used to request previous and next nodes</param>
        internal static Value Do(DelimiterNode node, IScope scope, INodeRequestor nodes, ILineRequestor requestor)
        {
            if (node.Value != null)
            {	// node has already been evaluated
                return node.Value;
            }
            else if (node.Token != null)
            {	// function/variable or built-in
                Token token = node.Token;
                Value value = scope.GetValue(token);
                if (value is ValueFunction && nodes != null)
                {
                    ValueFunction function = value as ValueFunction;
                    // get previous & next nodes if needed
                    DelimiterNode previous = (function.ConsumesPrevious ? nodes.GetPrevious() : null);
                    DelimiterNode next = (function.ConsumesNext ? nodes.GetNext() : null);

                    scope.FunctionName = token.Value;

                    // evaluate
                    try
                    {
                        return function.Eval(previous, next, scope, scope, nodes, requestor);
                    }
                    catch (Loki3Exception e)
                    {	// this function is the correct context if there isn't already one there
                        if (!e.Errors.ContainsKey(Loki3Exception.keyFunction))
                            e.AddFunction(token.Value);
                        if (!e.Errors.ContainsKey(Loki3Exception.keyScope))
                            e.AddScope(scope);
                        throw e;
                    }
                }
                else if (value != null)
                {
                    return value;
                }
                else
                {
                    return EvalBuiltin.Do(token);
                }
            }
            else if (node.List != null)
            {	// delimited list of nodes
                Value value = null;
                DelimiterList list = node.List;
                IScope listScope = (list.Scope != null ? list.Scope : scope);
                DelimiterType type = list.Delimiter.DelimiterType;

                // get contents as a Value
                switch (type)
                {
                    case DelimiterType.AsString:
                        value = new ValueString(list.Original);
                        break;
                    case DelimiterType.AsValue:
                        value = EvalList.Do(list.Nodes, listScope);
                        break;
                    case DelimiterType.AsArray:
                        List<Value> values = new List<Value>(list.Nodes.Count);
                        foreach (DelimiterNode subnode in list.Nodes)
                        {	// note: 'nodes' is null so functions don't get evaled
                            Value subvalue = Do(subnode, listScope, null, requestor);
                            values.Add(subvalue);
                        }
                        value = new ValueArray(values);
                        break;
                    case DelimiterType.AsEvaledArray:
                        value = EvalList.DoEvaledArray(list.Nodes, listScope);
                        break;
                    case DelimiterType.AsRaw:
                        value = new ValueRaw(list, listScope);
                        break;
                    case DelimiterType.AsArrayOfRaw:
                        List<Value> rawvalues = new List<Value>(list.Nodes.Count);
                        foreach (DelimiterNode subnode in list.Nodes)
                            rawvalues.Add(new ValueRaw(subnode, listScope));
                        value = new ValueArray(rawvalues);
                        break;
                }

                // run contents through a function if specified
                ValueFunction function = list.Delimiter.Function;
                if (function == null)
                    return value;
                DelimiterNode next = new DelimiterNodeValue(value);
                return function.Eval(null, next, scope, scope, nodes, requestor);
            }
            return new ValueNil();
        }
Esempio n. 3
0
            /// <summary>Evaluate this node, possibly consuming adjacent nodes</summary>
            internal void Eval(IScope scope, INodeRequestor nodes, ILineRequestor requestor)
            {
                if (m_state != NodeState.Node && m_state != NodeState.Function)
                    return;

                // get new value
                if (m_state == NodeState.Node)
                {	// hasn't been evaled at all
                    m_value = EvalNode.Do(m_node, scope, nodes, requestor);
                }
                else if (m_state == NodeState.Function)
                {	// previously resolved to a function
                    DelimiterNode previous = (m_func.ConsumesPrevious ? previous = nodes.GetPrevious() : null);
                    DelimiterNode next = (m_func.ConsumesNext ? next = nodes.GetNext() : null);
                    if ((m_func.ConsumesPrevious || m_func.ConsumesNext) && (previous == null && next == null))
                    {	// no prev/next parameters passed, perhaps it can use body?
                        if (m_func.RequiresBody() && requestor != null)
                        {	// tack on body if present
                            m_value = EvalList.DoAddBody(m_func, scope, requestor);
                        }
                        else
                        {	// function can't be evaled further
                            m_state = NodeState.Value;
                            return;
                        }
                    }
                    else
                    {
                        if (!m_func.ConsumesPrevious && !m_func.ConsumesNext && !m_func.RequiresBody() && !m_func.ForceEval)
                        {	// function can't be evaled further
                            m_state = NodeState.Value;
                            return;
                        }
                        m_value = m_func.Eval(previous, next, scope, scope, nodes, requestor);
                    }
                }

                if (m_value == null)
                {	// e.g. because node was a comment
                    m_state = NodeState.Empty;
                    return;
                }

                // store new info about this node
                m_node = new DelimiterNodeValue(m_value);
                m_order = (int)m_value.Order;
                if (m_value.Type == ValueType.Function)
                {
                    m_state = NodeState.Function;
                    m_func = m_value as ValueFunction;
                }
                else
                {
                    m_state = NodeState.Value;
                }
            }