meowlang/parser/Visitor.cs
2022-02-12 02:29:25 +01:00

412 lines
17 KiB
C#

using System.Reflection.Metadata;
using System.Text;
using System.Text.RegularExpressions;
using Antlr4.Runtime;
using meowlang.parser.antlr;
namespace meowlang.parser;
public class InvalidEscapeSequenceException : Exception
{
public InvalidEscapeSequenceException(string escapeSequence) : base($"invalid escape sequence `{escapeSequence}`")
{
}
}
public class MeowVisitorException : Exception
{
public IToken Token { get; }
public MeowVisitorException(IToken token, string message) : base(message)
{
Token = token;
}
}
public class InvalidImportPathException : MeowVisitorException
{
public InvalidImportPathException(IToken context, string message) : base(context, message)
{
}
}
public class Visitor : MeowBaseVisitor<Model>
{
public override Model VisitFile(MeowParser.FileContext context)
{
var imports = context.importStatement().Select(x => new ImportVisitor().Visit(x)).ToList();
var declarations = context.declaration().Select(x => new DeclarationVisitor().Visit(x)).ToList();
return new Model(context.GetSpan(), imports, declarations);
}
}
public class ImportVisitor : MeowBaseVisitor<ImportModel>
{
private static readonly string PathSegmentPattern = "[a-z][a-z0-9_]*";
private static readonly Regex ProjectRegex = new Regex("^[a-z][a-z0-9_]*$");
private static readonly Regex PathRegexNoProject =
new Regex($"^({PathSegmentPattern}|\\.|\\.\\.)(/{PathSegmentPattern})*$");
private static readonly Regex PathRegex = new Regex($"^{PathSegmentPattern}(/{PathSegmentPattern})*$");
public override ImportModel VisitImportStatement(MeowParser.ImportStatementContext context)
{
var path = context.importpath.Text[1..^1].Unescape();
string? project = null;
if (path.Contains(':'))
{
var parts = path.Split(':');
project = parts[0];
if (!ProjectRegex.IsMatch(project))
{
throw new InvalidImportPathException(context.importpath, "malformed project name");
}
path = parts[1];
if (!PathRegex.IsMatch(path))
{
throw new InvalidImportPathException(context.importpath, "malformed path");
}
}
else
{
if (!PathRegexNoProject.IsMatch(path))
{
throw new InvalidImportPathException(context.importpath, "malformed path");
}
}
var alias = context.importname?.Text;
return new ImportModel(context.GetSpan(), project, path, alias);
}
}
public class DeclarationVisitor : MeowBaseVisitor<DeclarationModel>
{
public override DeclarationModel VisitFunction(MeowParser.FunctionContext context)
{
var attributes = context.attribute().Select(x => new AttributeVisitor().Visit(x)).ToList();
var pub = context.pub != null;
var name = context.name.Text;
var typeParameters =
context.genericParameters()?._name.Select(x => new TypeParameterModel(x.GetSpan(), x.Text)).ToList() ??
new List<TypeParameterModel>();
var functionParameters = context.functionParameters().functionParameter()
.Select(x => new FunctionParameterVisitor().Visit(x)).ToList();
var functionReturns = context.functionReturn()?.typeReference().Select(x => new TypeReferenceVisitor().Visit(x))
.ToList() ?? new List<TypeReferenceModel>();
var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitor().Visit(x)).ToList() ??
new List<ConstraintModel>();
return new FunctionModel(context.GetSpan(), attributes, pub, name, typeParameters, functionParameters,
functionReturns, constraints,
new FunctionBodyModel(context.functionBody().GetSpan())); // TODO: visit function body
}
public override ConstraintDeclarationModel VisitConstraintDeclaration(
MeowParser.ConstraintDeclarationContext context)
{
var name = context.name.Text;
var typeNames = context._types.Select(x => x.Text).ToList();
var rules = context.constraintRule().Select(x => new ConstraintRuleVisitor().Visit(x)).ToList();
return new ConstraintDeclarationModel(context.GetSpan(), name, typeNames, rules);
}
public override DeclarationModel VisitStructDeclaration(MeowParser.StructDeclarationContext context)
{
var name = context.name.Text;
var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List<string>();
var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitor().Visit(x)).ToList() ??
new List<ConstraintModel>();
var structModel = new TypeReferenceVisitor().Visit(context.structType()) as StructTypeModel;
return new StructDeclarationModel(context.GetSpan(), name, typeParameters, constraints, structModel!);
}
public override DeclarationModel VisitEnumDeclaration(MeowParser.EnumDeclarationContext context)
{
var name = context.name.Text;
var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List<string>();
var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitor().Visit(x)).ToList() ??
new List<ConstraintModel>();
var enumModel = new TypeReferenceVisitor().Visit(context.enumType()) as EnumTypeModel;
return new EnumDeclarationModel(context.GetSpan(), name, typeParameters, constraints, enumModel!);
}
public override DeclarationModel VisitTupleDeclaration(MeowParser.TupleDeclarationContext context)
{
var name = context.name.Text;
var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List<string>();
var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitor().Visit(x)).ToList() ??
new List<ConstraintModel>();
var tupleModel = new TypeReferenceVisitor().Visit(context.tupleType()) as TupleTypeModel;
return new TupleDeclarationModel(context.GetSpan(), name, typeParameters, constraints, tupleModel!);
}
public override DeclarationModel VisitTypeAlias(MeowParser.TypeAliasContext context)
{
var name = context.name.Text;
var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List<string>();
var type = new TypeReferenceVisitor().Visit(context.typeReference());
return new TypeAliasModel(context.GetSpan(), name, typeParameters, type);
}
}
public class AttributeVisitor : MeowBaseVisitor<AttributeModel>
{
public override AttributeModel VisitAttribute(MeowParser.AttributeContext context)
{
var name = context.name.Text;
var values = context.attributeValue().Select(x => new AttributeValueVisitor().Visit(x)).ToList();
return new AttributeModel(context.GetSpan(), name, values);
}
}
public class AttributeValueVisitor : MeowBaseVisitor<AttributeValueModel>
{
public override AttributeValueModel VisitAttributeValue(MeowParser.AttributeValueContext context)
{
if (context.id != null)
{
return new IdentifierAttributeValueModel(context.GetSpan(), context.id.Text);
}
var literal = new LiteralVisitor().Visit(context.literal());
return new LiteralAttributeValueModel(context.GetSpan(), literal);
}
}
public class FunctionParameterVisitor : MeowBaseVisitor<FunctionParameterModel>
{
public override FunctionParameterModel VisitFunctionParameter(MeowParser.FunctionParameterContext context)
{
var type = new TypeReferenceVisitor().Visit(context.typeReference());
var name = context.name.Text;
return new FunctionParameterModel(context.GetSpan(), type, name);
}
}
public class TypeReferenceVisitor : MeowBaseVisitor<TypeReferenceModel>
{
public override TypeReferenceModel VisitTypeReference(MeowParser.TypeReferenceContext context)
{
var type = Visit(context.nonPointerTypeReference());
if (context.pointer != null)
{
return new PointerTypeReferenceModel(context.GetSpan(), type);
}
return type;
}
public override TypeReferenceModel VisitTypeName(MeowParser.TypeNameContext context)
{
var import = context.importName?.Text;
var nestedName = context._name.Select(x => x.Text).ToList();
var typeParameters = context._genericType.Select(Visit).ToList();
return new TypeNameModel(context.GetSpan(), import, nestedName[0], typeParameters, nestedName.Skip(1).ToList());
}
public override TypeReferenceModel VisitArrayType(MeowParser.ArrayTypeContext context)
{
var type = Visit(context.typeReference());
if (context.length == null)
{
return new SliceTypeModel(context.GetSpan(), type);
}
return new ArrayTypeModel(context.GetSpan(), type, context.length.Text);
}
public override TypeReferenceModel VisitTupleType(MeowParser.TupleTypeContext context)
{
var types = context.typeReference().Select(Visit).ToList();
return new TupleTypeModel(context.GetSpan(), types);
}
public override TypeReferenceModel VisitStructType(MeowParser.StructTypeContext context)
{
var members = context.structMember().Select(x => new StructMemberVisitor().Visit(x)).ToList();
return new StructTypeModel(context.GetSpan(), members);
}
public override TypeReferenceModel VisitEnumType(MeowParser.EnumTypeContext context)
{
var members = context.enumMember().Select(x => new EnumMemberVisitor().Visit(x)).ToList();
return new EnumTypeModel(context.GetSpan(), members);
}
}
public class StructMemberVisitor : MeowBaseVisitor<StructMemberModel>
{
public override StructMemberModel VisitStructMember(MeowParser.StructMemberContext context)
{
var type = new TypeReferenceVisitor().Visit(context.typeReference());
var name = context.name.Text;
return new StructMemberModel(context.GetSpan(), type, name);
}
}
public class EnumMemberVisitor : MeowBaseVisitor<EnumMemberModel>
{
public override EnumMemberModel VisitEnumMember(MeowParser.EnumMemberContext context)
{
var name = context.name.Text;
TypeReferenceModel? type = null;
var typeRef = context.typeReference();
if (typeRef != null)
{
type = new TypeReferenceVisitor().Visit(typeRef);
}
return new EnumMemberModel(context.GetSpan(), name, type);
}
}
public class FunctionConstraintVisitor : MeowBaseVisitor<ConstraintModel>
{
public override ConstraintModel VisitConstraint(MeowParser.ConstraintContext context)
{
var name = context.name.Text;
var typeNames = context._typenames.Select(x => x.Text).ToList();
return new ConstraintModel(context.GetSpan(), name, typeNames);
}
}
public class LiteralVisitor : MeowBaseVisitor<LiteralModel>
{
public override LiteralModel VisitStringLiteral(MeowParser.StringLiteralContext context)
{
var value = context.val.Text[1..^1].Unescape();
return new StringLiteralModel(context.GetSpan(), value);
}
public override LiteralModel VisitBoolLiteral(MeowParser.BoolLiteralContext context)
{
var text = context.val.Text;
var value = text == "true";
return new BoolLiteralModel(context.GetSpan(), value);
}
public override LiteralModel VisitNumericLiteral(MeowParser.NumericLiteralContext context)
{
return new NumericLiteralModel(context.GetSpan(), context.val.Text);
}
public override LiteralModel VisitCharacterLiteral(MeowParser.CharacterLiteralContext context)
{
var value = context.val.Text[1..^1].Unescape();
return new CharacterLiteralModel(context.GetSpan(), value);
}
}
public class ConstraintRuleVisitor : MeowBaseVisitor<ConstraintRuleModel>
{
public override ConstraintRuleModel VisitEmbedConstraintRule(MeowParser.EmbedConstraintRuleContext context)
{
var name = context.name.Text;
var types = context._types.Select(x => new TypeReferenceVisitor().Visit(x)).ToList();
return new EmbedConstraintRuleModel(context.GetSpan(), name, types);
}
public override ConstraintRuleModel VisitFunctionConstraintRule(MeowParser.FunctionConstraintRuleContext context)
{
var name = context.name.Text;
var parameters = context.constraintFunctionParameters().typeReference()
.Select(x => new TypeReferenceVisitor().Visit(x)).ToList();
var returns =
context.functionReturn()?.typeReference().Select(x => new TypeReferenceVisitor().Visit(x)).ToList() ??
new List<TypeReferenceModel>();
return new FunctionConstraintRuleModel(context.GetSpan(), name, parameters, returns);
}
}
public record Model(Span span, List<ImportModel> Imports, List<DeclarationModel> Declarations) : ModelBase(span);
public record ImportModel(Span span, string? Project, string Path, string? Alias) : ModelBase(span);
public abstract record DeclarationModel(Span span) : ModelBase(span);
public record FunctionModel(Span span, List<AttributeModel> Attributes, bool Pub, string Name,
List<TypeParameterModel> TypeParameters, List<FunctionParameterModel> Parameters, List<TypeReferenceModel> Returns,
List<ConstraintModel> Constraints, FunctionBodyModel Body) : DeclarationModel(span);
public record AttributeModel(Span span, string Name, List<AttributeValueModel> Values) : ModelBase(span);
public abstract record AttributeValueModel(Span span) : ModelBase(span);
public record IdentifierAttributeValueModel(Span span, string Name) : AttributeValueModel(span);
public record LiteralAttributeValueModel(Span span, LiteralModel Literal) : AttributeValueModel(span);
public record TypeParameterModel(Span span, string Name) : ModelBase(span);
public record FunctionParameterModel(Span span, TypeReferenceModel Type, string Name) : ModelBase(span);
public abstract record TypeReferenceModel(Span span) : ModelBase(span);
public record PointerTypeReferenceModel(Span span, TypeReferenceModel Type) : TypeReferenceModel(span);
public record TypeNameModel(Span span, string? ImportName, string Name, List<TypeReferenceModel> TypeParameters,
List<string> Nested) : TypeReferenceModel(span);
public record ArrayTypeModel(Span span, TypeReferenceModel Type, string Length) : TypeReferenceModel(span);
public record SliceTypeModel(Span span, TypeReferenceModel Type) : TypeReferenceModel(span);
public record TupleTypeModel(Span span, List<TypeReferenceModel> Types) : TypeReferenceModel(span);
public record StructTypeModel(Span span, List<StructMemberModel> Members) : TypeReferenceModel(span);
public record StructMemberModel(Span span, TypeReferenceModel Type, string Name) : ModelBase(span);
public record EnumTypeModel(Span span, List<EnumMemberModel> Members) : TypeReferenceModel(span);
public record EnumMemberModel(Span span, string Name, TypeReferenceModel? Type) : ModelBase(span);
public record ConstraintModel(Span span, string Name, List<string> TypeNames) : ModelBase(span);
public record FunctionBodyModel(Span span) : ModelBase(span);
public abstract record LiteralModel(Span span) : ModelBase(span);
public record StringLiteralModel(Span span, string Value) : LiteralModel(span);
public record CharacterLiteralModel(Span span, string Value) : LiteralModel(span);
public record NumericLiteralModel(Span span, string StringValue) : LiteralModel(span);
public record BoolLiteralModel(Span span, bool Value) : LiteralModel(span);
public record ConstraintDeclarationModel
(Span span, string Name, List<string> TypeNames, List<ConstraintRuleModel> Rules) : DeclarationModel(span);
public abstract record ConstraintRuleModel(Span span) : ModelBase(span);
public record EmbedConstraintRuleModel
(Span span, string Name, List<TypeReferenceModel> Types) : ConstraintRuleModel(span);
public record FunctionConstraintRuleModel(Span span, string Name, List<TypeReferenceModel> Parameters,
List<TypeReferenceModel> Returns) : ConstraintRuleModel(span);
public record StructDeclarationModel(Span span, string Name, List<string> TypeParameters,
List<ConstraintModel> Constraints, StructTypeModel Struct) : DeclarationModel(span);
public record EnumDeclarationModel(Span span, string Name, List<string> TypeParameters,
List<ConstraintModel> Constraints, EnumTypeModel Enum) : DeclarationModel(span);
public record TupleDeclarationModel(Span span, string Name, List<string> TypeParameters,
List<ConstraintModel> Constraints, TupleTypeModel Tuple) : DeclarationModel(span);
public record TypeAliasModel
(Span span, string Name, List<string> TypeParameters, TypeReferenceModel Type) : DeclarationModel(span);