d6bdd08002
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...)
125 lines
3.2 KiB
C#
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;
|
|
}
|
|
} |