meowlang/typechecker/Scope.cs
Gwendolyn d6bdd08002 loooots of stuff
the typechecker project can collect all the top level types from a file, which is pretty cool I think
(except for pointers, those aren't implemented yet...)
2022-02-13 02:41:16 +01:00

125 lines
3.2 KiB
C#

namespace meowlang.typechecker;
public class Scope
{
private readonly Dictionary<string, TypeId> _variableScope = new();
private readonly Dictionary<(string, int), Guid> _typeScope = new();
private readonly TypeRegistry _typeRegistry;
private readonly Scope? _parent;
public Scope? DebugGetParent => _parent;
public Dictionary<string, TypeId> 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;
}
}