/// <summary> /// Looks up the state associated with the specified parameter expression by scanning the scoped symbol table, starting from the current scope. /// </summary> /// <param name="parameter">Parameter expression to look up.</param> /// <param name="state">State associated with the specified parameter expression.</param> /// <returns>true if the symbol was found; otherwise, false.</returns> protected bool TryLookup(ParameterExpression parameter, out TState state) { if (parameter == null) { throw new ArgumentNullException(nameof(parameter)); } if (_symbolTable.TryLookup(parameter, out Indexed <Indexed <TState> > value)) { state = value.Value.Value; return(true); } state = default; return(false); }
public void ScopedSymbolTable_Basics() { var res = default(Indexed <Indexed <string> >); var sst = new ScopedSymbolTable <string, string> { { "glb", "val" } }; var assertGlobal = new Action(() => { Assert.IsTrue(sst.TryLookup("glb", out res)); Assert.AreEqual(-1, res.Index); Assert.AreEqual(0, res.Value.Index); Assert.AreEqual("val", res.Value.Value); Assert.IsFalse(sst.TryLookup("blg", out res)); }); assertGlobal(); AssertPushPop(sst, () => { assertGlobal(); Assert.IsFalse(sst.TryLookup("bar", out res)); }, () => { sst.Add("bar", "foo"); sst.Add("baz", "qux"); AssertPushPop(sst, () => { assertGlobal(); Assert.IsTrue(sst.TryLookup("bar", out res)); Assert.AreEqual(0, res.Index); Assert.AreEqual(0, res.Value.Index); Assert.AreEqual("foo", res.Value.Value); Assert.IsTrue(sst.TryLookup("baz", out res)); Assert.AreEqual(0, res.Index); Assert.AreEqual(1, res.Value.Index); Assert.AreEqual("qux", res.Value.Value); }, () => { sst.Add("foo", "bar"); sst.Add("bar", "qux"); AssertPushPop(sst, () => { assertGlobal(); Assert.IsTrue(sst.TryLookup("foo", out res)); Assert.AreEqual(0, res.Index); Assert.AreEqual(0, res.Value.Index); Assert.AreEqual("bar", res.Value.Value); Assert.IsTrue(sst.TryLookup("bar", out res)); Assert.AreEqual(0, res.Index); Assert.AreEqual(1, res.Value.Index); Assert.AreEqual("qux", res.Value.Value); Assert.IsTrue(sst.TryLookup("baz", out res)); Assert.AreEqual(1, res.Index); Assert.AreEqual(1, res.Value.Index); Assert.AreEqual("qux", res.Value.Value); }, () => { sst.Add("qux", "baz"); AssertPushPop(sst, () => { assertGlobal(); Assert.IsTrue(sst.TryLookup("qux", out res)); Assert.AreEqual(0, res.Index); Assert.AreEqual(0, res.Value.Index); Assert.AreEqual("baz", res.Value.Value); Assert.IsTrue(sst.TryLookup("foo", out res)); Assert.AreEqual(1, res.Index); Assert.AreEqual(0, res.Value.Index); Assert.AreEqual("bar", res.Value.Value); Assert.IsTrue(sst.TryLookup("bar", out res)); Assert.AreEqual(1, res.Index); Assert.AreEqual(1, res.Value.Index); Assert.AreEqual("qux", res.Value.Value); Assert.IsTrue(sst.TryLookup("baz", out res)); Assert.AreEqual(2, res.Index); Assert.AreEqual(1, res.Value.Index); Assert.AreEqual("qux", res.Value.Value); }, () => { // NOTE: The test method pushes a frame before entering, so we're off by 1 for the outer indices. Assert.IsNotNull(((IEnumerable)sst).GetEnumerator()); var symbols = sst.SelectMany(ist => ist.Value, (o, i) => (Outer: o.Index, Inner: i.Index, Symbol: i.Value.Key, i.Value.Value)).ToArray(); Assert.IsTrue(symbols.SequenceEqual(new[] { (Outer: 1, Inner: 0, Symbol: "qux", Value: "baz"), (Outer: 2, Inner: 0, Symbol: "foo", Value: "bar"), (Outer: 2, Inner: 1, Symbol: "bar", Value: "qux"), (Outer: 3, Inner: 0, Symbol: "bar", Value: "foo"), (Outer: 3, Inner: 1, Symbol: "baz", Value: "qux"), (Outer: -1, Inner: 0, Symbol: "glb", Value: "val"), }));