/// <summary> /// Look up a value in this dictionary, walking the __isa chain to find /// it in a parent object if necessary; return both the value found an /// (via the output parameter) the map it was found in. /// </summary> /// <param name="key">key to search for</param> /// <returns>value associated with that key, or null if not found</returns> public Value Lookup(Value key, out ValMap valueFoundIn) { if (key == null) { key = ValNull.instance; } Value result = null; ValMap obj = this; while (obj != null) { if (obj.TryGetValue(key, out result)) { valueFoundIn = obj; return(result); } Value parent; if (!obj.TryGetValue(ValString.magicIsA, out parent)) { break; } obj = parent as ValMap; } valueFoundIn = null; return(null); }
/// <summary> /// Get the value of a local variable ONLY -- does not check any other /// scopes, nor check for special built-in identifiers like "globals". /// Used mainly by host apps to easily look up an argument to an /// intrinsic function call by the parameter name. /// </summary> public Value GetLocal(string identifier, Value defaultValue = null) { Value result; if (variables != null && variables.TryGetValue(identifier, out result)) { return(result); } return(defaultValue); }
/// <summary> /// Get the value of a variable available in this context (including /// locals, globals, and intrinsics). Raise an exception if no such /// identifier can be found. /// </summary> /// <param name="identifier">name of identifier to look up</param> /// <returns>value of that identifier</returns> public Value GetVar(string identifier) { // check for special built-in identifiers 'locals' and 'globals' if (identifier == "locals") { if (variables == null) { variables = new ValMap(); } return(variables); } if (identifier == "globals") { if (root.variables == null) { root.variables = new ValMap(); } return(root.variables); } // check for a local variable Value result; if (variables != null && variables.TryGetValue(identifier, out result)) { return(result); } // OK, we don't have a local variable with that name. // Check higher scopes. Context c = parent; while (c != null) { if (c.variables != null && c.variables.ContainsKey(identifier)) { return(c.variables[identifier]); } c = c.parent; } // Finally, check intrinsics. Intrinsic intrinsic = Intrinsic.GetByName(identifier); if (intrinsic != null) { return(intrinsic.GetFunc()); } // No luck there either? Undefined identifier. throw new UndefinedIdentifierException(identifier); }
/// <summary> /// Get the value of a variable available in this context (including /// locals, globals, and intrinsics). Raise an exception if no such /// identifier can be found. /// </summary> /// <param name="identifier">name of identifier to look up</param> /// <returns>value of that identifier</returns> public Value GetVar(string identifier) { // check for special built-in identifiers 'locals' and 'globals' if (identifier == "locals") { if (variables == null) { variables = ValMap.Create(); } return(variables); } if (identifier == "globals") { if (root.variables == null) { root.variables = ValMap.Create(); } return(root.variables); } if (identifier == "outer") { // return module variables, if we have them; else globals if (outerVars != null) { return(outerVars); } if (root.variables == null) { root.variables = ValMap.Create(); } return(root.variables); } // check for a local variable Value result; if (variables != null && variables.TryGetValue(identifier, out result)) { return(result); } // check for a module variable if (outerVars != null && outerVars.TryGetValue(identifier, out result)) { return(result); } // OK, we don't have a local or module variable with that name. // Check the global scope (if that's not us already). if (parent != null) { Context globals = root; if (globals.variables != null && globals.variables.ContainsKey(identifier)) { return(globals.variables[identifier]); } } // Finally, check intrinsics. Intrinsic intrinsic = Intrinsic.GetByName(identifier); if (intrinsic != null) { return(intrinsic.GetFunc()); } // No luck there either? Undefined identifier. throw new UndefinedIdentifierException(identifier); }
/// <summary> /// Look up the given identifier in the given sequence, walking the type chain /// until we either find it, or fail. /// </summary> /// <param name="sequence">Sequence (object) to look in.</param> /// <param name="identifier">Identifier to look for.</param> /// <param name="context">Context.</param> public static Value Resolve(Value sequence, string identifier, Context context, out ValMap valueFoundIn) { var includeMapType = true; valueFoundIn = null; int loopsLeft = 1000; // (max __isa chain depth) while (sequence != null) { int seqTypeInt = sequence.GetBaseMiniscriptType(); //if (sequence is ValTemp || sequence is ValVar) if (seqTypeInt == MiniscriptTypeInts.ValTempTypeInt || seqTypeInt == MiniscriptTypeInts.ValVarTypeInt) { sequence = sequence.Val(context, false); seqTypeInt = sequence == null ? -1 : sequence.GetBaseMiniscriptType(); } //if (sequence is ValMap) { if (seqTypeInt == MiniscriptTypeInts.ValMapTypeInt) { // If the map contains this identifier, return its value. ValMap seqMap = sequence as ValMap; Value result = null; var idVal = ValString.Create(identifier); bool found = seqMap.TryGetValue(idVal, out result); idVal.Unref(); if (found) { valueFoundIn = seqMap; return(result); } // Otherwise, if we have an __isa, try that next. if (loopsLeft < 0) { return(null); // (unless we've hit the loop limit) } if (!seqMap.TryGetValue(ValString.magicIsA, out sequence)) { // ...and if we don't have an __isa, try the generic map type if allowed if (!includeMapType) { throw new KeyException(identifier); } sequence = context.vm.mapType ?? Intrinsics.MapType(); includeMapType = false; } //} else if (sequence is ValList) { } else if (seqTypeInt == MiniscriptTypeInts.ValListTypeInt) { sequence = context.vm.listType ?? Intrinsics.ListType(); includeMapType = false; //} else if (sequence is ValString) { } else if (seqTypeInt == MiniscriptTypeInts.ValStringTypeInt) { sequence = context.vm.stringType ?? Intrinsics.StringType(); includeMapType = false; //} else if (sequence is ValNumber) { } else if (seqTypeInt == MiniscriptTypeInts.ValNumberTypeInt) { sequence = context.vm.numberType ?? Intrinsics.NumberType(); includeMapType = false; //} else if (sequence is ValFunction) { } else if (seqTypeInt == MiniscriptTypeInts.ValFunctionTypeInt) { sequence = context.vm.functionType ?? Intrinsics.FunctionType(); includeMapType = false; } else if (seqTypeInt == MiniscriptTypeInts.ValCustomTypeInt) { ValCustom custom = sequence as ValCustom; if (custom.Resolve(identifier, out Value result)) { //valueFoundIn return(result); } return(null); } else { throw new TypeException("Type Error (while attempting to look up " + identifier + ")"); } loopsLeft--; } return(null); }