namespace meowlang.typechecker; public class Scope { private readonly Dictionary _variableScope = new(); private readonly Dictionary<(string, int), Guid> _typeScope = new(); private readonly TypeRegistry _typeRegistry; private readonly Scope? _parent; public Scope? DebugGetParent => _parent; public Dictionary DebugGetVariableScope => _variableScope; public Dictionary<(string, int), Guid> DebugGetTypeScope => _typeScope; public Scope(TypeRegistry typeRegistry, Scope? parent = null) { _typeRegistry = typeRegistry; _parent = parent; } public void AddVariable(string name, TypeId type) { if (_variableScope.ContainsKey(name)) { throw new DuplicateVariableNameException(name); } _variableScope[name] = type; } public bool HasVariable(string name) { if (_variableScope.ContainsKey(name)) return true; return _parent?.HasVariable(name) ?? false; } public TypeId GetVariableType(string name) { return _variableScope.TryGetValue(name, out var value) ? value : throw new UnknownVariableNameException(name); } public Guid AddAnonymousType(TypeDescription type) { var guid = Guid.NewGuid(); _typeRegistry.Add(guid, type); return guid; } public Guid AddNamedType(string name, int arity, TypeDescription type) { Guid guid; if (_typeScope.TryGetValue((name, arity), out guid)) { if (_typeRegistry.Has(guid)) { throw new DuplicateTypeNameException(name, arity); } } else { if (HasType(name, arity)) { throw new DuplicateTypeNameException(name, arity); } guid = Guid.NewGuid(); _typeScope[(name, arity)] = guid; } _typeRegistry.Add(guid, type); return guid; } public bool HasType(string name, int arity) { if (_typeScope.ContainsKey((name, arity))) return true; return _parent?.HasType(name, arity) ?? false; } public TypeDescription GetType(Guid guid) { return _typeRegistry.Get(guid); } private Guid? GetTypeGuidWithoutCreate(string name, int arity) { if (_typeScope.ContainsKey((name, arity))) return _typeScope[(name, arity)]; return _parent?.GetTypeGuidWithoutCreate(name, arity); } public Guid GetTypeGuid(string name, int arity) { var key = GetTypeGuidWithoutCreate(name, arity); if (key == null) { key = Guid.NewGuid(); _typeScope[(name, arity)] = key.Value; } return key.Value; } } public class UnknownTypeException : Exception { private readonly string _name; private readonly int _arity; public UnknownTypeException(string name, int arity): base($"unknown type `{name}` with arity {arity}") { _name = name; _arity = arity; } } public class UnknownVariableNameException : Exception { public string Name { get; } public UnknownVariableNameException(string name) : base($"unknown variable `{name}`") { Name = name; } }