using System.Diagnostics.CodeAnalysis; namespace KumiScript.Interpreter { public class Environment { readonly Environment? _outer; readonly Dictionary _bindings; public Environment() { _bindings = new Dictionary(SymbolComparer.GetInstance()); } public Environment(Environment outer) { _bindings = new Dictionary(SymbolComparer.GetInstance()); _outer = outer; } public Expression Lookup(Symbol symbol) { Expression? result; _bindings.TryGetValue(symbol, out result); if (result is not null) return result; if (_outer is null) throw new InterpreterUnboundSymbolException(); return _outer.Lookup(symbol); } public void AddSymbol(Symbol symbol, Expression value) { _bindings.Add(symbol, value); return; } public void RedefineSymbol(Symbol symbol, Expression value) { if (_bindings.ContainsKey(symbol)) { _bindings.Remove(symbol); _bindings.Add(symbol, value); return; } if (_outer is null) throw new InterpreterUnboundSymbolException(symbol.ToString()); _outer.RedefineSymbol(symbol, value); } } internal class SymbolComparer : IEqualityComparer { private static SymbolComparer? _instance; private SymbolComparer() { } public static SymbolComparer GetInstance() { if (_instance is null) _instance = new SymbolComparer(); return _instance; } public bool Equals(Symbol? x, Symbol? y) { if (x is not Symbol || y is not Symbol) return false; return x.Equals(y); } public int GetHashCode([DisallowNull] Symbol obj) { return obj.ToString().GetHashCode(); } } }