/// <summary>Add a new overload to the list</summary> internal void Add(ValueFunction function) { if (m_functions.AsArray.Count == 0) { // first function decides if it's pre/in/postfix m_bConsumesPrevious = function.ConsumesPrevious; m_bConsumesNext = function.ConsumesNext; m_bRequiresBody = function.RequiresBody(); // copy all metadata except parameters from single function to overload foreach (string key in function.Metadata.Raw.Keys) if (key != ValueFunction.keyPreviousPattern && key != ValueFunction.keyNextPattern) WritableMetadata[key] = function.Metadata[key]; AddFunction(function); } else { // other functions must match fix if (m_bConsumesPrevious != function.ConsumesPrevious || m_bConsumesNext != function.ConsumesNext) { string expected = GetFix(m_bConsumesPrevious, m_bConsumesNext); string actual = GetFix(function.ConsumesPrevious, function.ConsumesNext); throw new Loki3Exception().AddWrongFix(expected, actual); } // other function must have same body requirement if (m_bRequiresBody != function.RequiresBody()) throw new Loki3Exception().AddMissingBody(function); // copy all metadata from overload to new function foreach (string key in Metadata.Raw.Keys) function.WritableMetadata[key] = Metadata[key]; AddFunction(function); } }
internal BoundFunction(ValueFunction function, IScope scope) { m_function = function; m_scope = scope; foreach (string key in function.Metadata.Raw.Keys) WritableMetadata[key] = function.Metadata[key]; }
/// <summary> /// If function requires a body & it follows current line, add on body. /// 'requestor' will be advanced to the first line after the body. /// </summary> /// <returns>new function with body attached</returns> internal static Value DoAddBody(ValueFunction function, IScope scope, ILineRequestor requestor) { List<DelimiterList> body = DoGetBody(scope, requestor); // if no body to add to function, leave as-is if (body.Count == 0) return function; // we've built the entire body - now pass it to function Map map = new Map(); map[ValueFunction.keyBody] = new ValueLine(body, scope); ValueFunctionPre functionPre = function as ValueFunctionPre; return functionPre.Eval(new ValueMap(map), new ScopeChain(scope)); }
/// <summary> /// Create a function that waits for the missing pre or post parameter, /// then bundles them all up and calls the first function /// </summary> /// <param name="nested">function to call once we get remaining parameters</param> /// <param name="passed">arguments that have already been passed</param> internal PartialFunctionIn(ValueFunction nested, DelimiterNode prev, DelimiterNode next) { m_nested = nested; m_prev = prev; m_next = next; // our pattern is the missing parameter; use same precedence as nested func Map meta = nested.Metadata; if (meta.ContainsKey(ValueFunctionOverload.keyIsOverload)) WritableMetadata[ValueFunctionOverload.keyIsOverload] = new ValueBool(true); else if (m_prev != null) Init(null, meta[keyNextPattern], nested.Order); else Init(meta[keyPreviousPattern], null, nested.Order); }
public void Exit() { if (m_onExitFunction != null) { ValueFunction func = m_onExitFunction; DelimiterNodeValue prev = (m_onExitPrevValue == ValueNil.Nil ? null : new DelimiterNodeValue(m_onExitPrevValue)); DelimiterNodeValue next = (m_onExitNextValue == ValueNil.Nil ? null : new DelimiterNodeValue(m_onExitNextValue)); m_onExitFunction = null; func.Eval(prev, next, this, this, null, null); } }
public void AddOnExit(ValueFunction function, Value prevValue, Value nextValue) { m_onExitFunction = function; m_onExitPrevValue = prevValue; m_onExitNextValue = nextValue; }
internal ValueFunctionOverload(ValueFunction function) { WritableMetadata[keyIsOverload] = new ValueBool(true); Add(function); }
/// <summary>Figure out how specific overload is and add to sorted list</summary> private void AddFunction(ValueFunction function) { // calc the overload level of this function based on the params it expects, // store the level on the function int countParams = 0; int level = 0; if (function.ConsumesPrevious) { Value pattern = function.Metadata[ValueFunction.keyPreviousPattern]; countParams += pattern.Count; level += CalcLevel(pattern); } if (function.ConsumesNext) { Value pattern = function.Metadata[ValueFunction.keyNextPattern]; countParams += pattern.Count; level += CalcLevel(pattern); } level += PointsPerParam * countParams * (countParams - 1) / 2; function.WritableMetadata[keyOverloadLevel] = new ValueInt(level); // list is sorted from largest to smallest overload levels List<Value> list = m_functions.AsArray; int count = list.Count; bool bAdded = false; // todo: make this a binary search for (int i = 0; i < count; i++) { Value currentV = list[i]; int currentLevel = currentV.Metadata[keyOverloadLevel].AsInt; if (level > currentLevel) { list.Insert(i, function); bAdded = true; break; } } if (!bAdded) list.Add(function); }
/// <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; } }
internal NodeEval(DelimiterNode node, IScope scope) { m_node = node; Token token = node.Token; if (token != null) { Value value = scope.GetValue(token); m_func = value as ValueFunction; if (m_func != null) { // function m_state = NodeState.Node; m_order = (int)m_func.Order; } else if (value != null) { // variable m_value = value; m_state = NodeState.Value; } else { // built-in try { m_value = EvalBuiltin.DoNoThrow(token); if (m_value != null) m_state = NodeState.Value; } catch (Exception) { } } } else if (node.List != null) { m_state = NodeState.Node; m_order = (int)Order.Lowest; } else if (node.Value != null) { m_value = node.Value; m_order = (int)m_value.Order; m_func = m_value as ValueFunction; m_state = (m_func == null ? NodeState.Value : NodeState.Function); } }
/// <summary> /// Delimited contents will be passed off to function to be evaluated /// </summary> /// <param name="function">function must take a next parameter of specified type</param> internal ValueDelimiter(string end, DelimiterType type, ValueFunction function) { Init(end, type, function); }
private void Init(string end, DelimiterType type, ValueFunction function) { Map meta = WritableMetadata; meta[keyDelimEnd] = new ValueString(end); meta[keyDelimType] = new ValueInt((int)type); if (function != null) meta[keyDelimFunction] = function; }
/// <summary>A function required a body but a body wasn't provided</summary> internal Loki3Exception AddMissingBody(ValueFunction function) { m_map[keyMissingBody] = function; return this; }