first commit wtf am I doing

This commit is contained in:
Gwendolyn 2022-02-12 02:29:25 +01:00
commit 78fe931f97
13 changed files with 1345 additions and 0 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/
.idea
gen/

22
MeowLang.sln Normal file
View file

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "compiler", "compiler\compiler.csproj", "{1ABDD383-ABC6-4B3F-80FC-348879BF8AFE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "parser", "parser\parser.csproj", "{240E1F81-DB04-46CE-AB7B-60616B6D868C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1ABDD383-ABC6-4B3F-80FC-348879BF8AFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1ABDD383-ABC6-4B3F-80FC-348879BF8AFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1ABDD383-ABC6-4B3F-80FC-348879BF8AFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1ABDD383-ABC6-4B3F-80FC-348879BF8AFE}.Release|Any CPU.Build.0 = Release|Any CPU
{240E1F81-DB04-46CE-AB7B-60616B6D868C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{240E1F81-DB04-46CE-AB7B-60616B6D868C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{240E1F81-DB04-46CE-AB7B-60616B6D868C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{240E1F81-DB04-46CE-AB7B-60616B6D868C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

316
README.md Normal file
View file

@ -0,0 +1,316 @@
# meow
most awesome language, mainly because it's not object-oriented and it's called meow.
Multiple dispatch!
Weird syntax!
Implicit interfaces, except we call them constraints! whyyyy did I do this?
```
<imports>
<declarations>
```
### imports
```
import "std:strings" as str // standard library
import "std:strings/ext" as strext // nested
import "foo:bar" as fb // file bar from project foo
import ":foo/bar" // relative to project root
import "foo" // relative to current file
import "./foo" as whatever // relative to current file
import "../foobar" // relative to current file
```
access public thingies from imports with `:`
```
import foo;
foo:somefunction();
foo:SomeType
foo:SomeConstraint
```
### functions
Functions are by default private to the current file, functions with `pub` are accessible from other files/projects.
```
fn x() {}
pub fn y() {}
```
Functions can take the `[c_export]` attribute to make them callable when compiled as a static library, and to generate C headers for them.
```
[c_export] pub fn foo(int a, Foo b, Bar c) -> int {
}
[c_export("renamed_foo2")] pub fn foo2(int a, Foo b, Bar c) -> int, int {
}
```
Functions can be overloaded on parameter and return types
```
fn a() -> s32 {
return -1;
}
fn a() -> u32 {
return 1;
}
fn a(i32 x, i32 y) -> (i32, i32) {
return y, x;
}
fn a(u32 x) -> u32 {
return x + 1;
}
```
### constraints
constraints are kind of weird because they
- can have multiple types, like, a constraint can constrain multiple types together
- can be used both as a constraint on generic types and as a type themselves
- but only can be used as a type when they constrain only one type, and then they're kinda like an interface?
- fuck this is weird
```
// this one can be used only as a constraint for generic type parameters
constraint Foo on A B {
some_func(A, B);
some_other_func(A) -> B;
}
// this one can be used both as a constraint for generic type parameters or as an interface type
constraint Bar on A {
f1(A) -> A;
f2(A) -> i32;
}
```
```
// usage as type parameter constraints
fn foo<T1, T2>(T1 x)
where Foo T1 T2
{
T2 y = some_other_func(x);
some_func(x, y);
}
fn bar<T>(T a) -> i32
where Bar T
{
T b = f1(a);
return f2(b);
}
// usage as interface types
Bar x = getSomeTypeThatIsBar();
Bar y = f1(x);
```
constraints can be embedded in other constraints like this:
```
constraint Arithmetic on A {
operator+ (A, A) -> A;
operator- (A, A) -> A;
operator* (A, A) -> A;
operator/ (A, A) -> A;
}
constraint Foo on A {
Arithmetic A;
some_func(A) -> A;
}
```
```
int a = 1;
mut int b = 2;
let a = 1;
mut let b = 2;
```
### literals
#### numeric
Numeric literals are untyped but literals with a decimal point can not be used as integers.
They can contain underscores between digits which are ignored, e.g. `1_000` or `1_0_0_0`.
Unprefixed numeric literals are decimal, prefixes exist for hexadecimal (`0x`), octal (`0o`) and binary (`0b`).
#### character
The character literal is a single unicode character enclosed in single quotes, its value is the character's unicode code point.
#### bool
`true` and `false`
#### string
String literals are enclosed in double quotes (e.g. `"hello world"`).
Their type is an `u8` array with length of the string in bytes.
### types
#### basic types
- bool: `bool`
- signed integer types: `s8`, `s16`, `s32`, `s64`, `s128`
- unsigned integer types: `u8`, `u16`, `u32`, `u64`, `u128`
- floating point types: `f32`, `f64` (possibly more?)
- decimal type? `decimal`
- complex types? `c64`, `c128` (does this refer to the total size or the size of each component?)
#### compound types
##### array & slice
###### declaration
```
// array
[u8; 10]
// slice
[u8]
```
###### use
```
let a: [u8] = "foo";
let b: u8 = a[1];
let d: [s32; 4] = {1,2,3,4};
let e = [u8]{1,2,3,4};
```
##### struct
###### declaration
```
struct Point {
s32 x;
s32 y;
s32 z;
}
type Point = struct {
s32 x;
s32 y;
s32 z;
}
type Options = struct {
struct {
int foo;
} api;
}
```
##### use
```
let p1 = Point{
x: 1,
y: 2,
z: 3,
};
let p2: Point = {
x: 2,
y: 3,
z: 4,
};
let x = p1.x;
p1.x = 2;
let opt = Options{
api: {
foo: 1
}
};
let a: Options@api = opt.api; // yeah this is weird, try to avoid it
```
##### enum
###### declaration
```
enum A {
Foo,
Bar(u8)
}
type A = enum {
Foo,
Bar(u8)
}
type B = enum {
X,
Y(enum { // this is terrible but you can do it if you want for consistency reasons
A,
B
})
}
```
###### use
```
let x = A'Foo;
let y = A'Bar(10);
let z = B'Y(B@Y'A); // don't do this why would you do this
```
##### tuple
###### declaration
```
type X = (s8, s8);
tuple X(s8, s8);
type Y = (struct {int a; int b}, enum {A, B}); // why would you do this aaaaa
```
###### use
```
let a: X = (1,2);
let b = a.0;
let c = a.1;
let d = Y({a: 1, b: 2}, Y@1'A); // oh no
let e: Y@1 = d.1;
```
#### pointers
Pointers are taken with the `&` operator and dereferenced with the `*` operator. They are mostly similar to C I think.
Pointer types have a `*` appended to the type they point to.
```
let a: int = 1;
let b: int* = &a;
let c = *b;
```
A special `void*` type exists???? does it really? maybe? kinda yes? aaaaaaa
Pointer arithmetic works the same as in C, except that arithmetic on void pointers is allowed?
```
let a: [u8; 2] = {0,1};
let b: u8* = &a[0];
let c: u8* = b + 1;
let d: u8 = *b; // 0
let e: u8 = *c; // 1
*(&a[0]+1) = 2; // a is now {0,2}
```

14
compiler/Compiler.cs Normal file
View file

@ -0,0 +1,14 @@
using System;
using meowlang.parser;
namespace meowlang.compiler;
static class Compiler
{
private static void Main(string[] args)
{
var path = "example.mew";
var model = Parser.Parse(path);
Console.WriteLine(model.AutoToString());
}
}

26
compiler/compiler.csproj Normal file
View file

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>meow</AssemblyName>
<LangVersion>10</LangVersion>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<Company />
<Product>meow compiler</Product>
<RootNamespace>meowlang.compiler</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\parser\parser.csproj" />
</ItemGroup>
<ItemGroup>
<None Remove="example.mew" />
<Content Include="example.mew">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

91
compiler/example.mew Normal file
View file

@ -0,0 +1,91 @@
import "std:strings";
import "foo" as bar;
import "./foobar";
/*
fn foo() {}
pub fn bar(int x) -> int {}
pub fn multiret() -> int, int {}
[c_export] pub fn add(int a, int b) -> int {}
[c_export("add_floats")] pub fn add(float a, float b) -> float {}
fn sub<T>(T a, T b) -> T
where SUBTRACT T
{
// do something
}
fn ret_arr() -> [int; 10] {}
fn ret_slice() -> [int] {}
fn ret_multislice() -> [[int]] {}
fn ret_ptr() -> int* {}
fn ret_ptrslice() -> [int*] {}
fn ret_arrayptr() -> [int; 5]* {}
fn ret_tuple() -> (int, int) {}
fn ret_imported() -> strings:StringBuilder {}
fn ret_nested() -> foo@bar {}
fn ret_imported_nested() -> foo:bar@some@nested@shit {}
constraint Foo A {
whatever(A);
}
constraint Bar B {
constraint Foo B*;
constraint Foo [B];
constraint Foo (int, B);
constraint Foo SomeType<B>;
}
*/
struct Foo {
int something;
struct {
int foo;
} bar;
}
Foo f;
f.something
enum X {
A,
B,
C
}
enum X<T1, T2, T3> {
A(T1),
B(T2),
C(T3),
}
enum X<T1, T2, T3> where Constraint T1 T2 where Constraint T2 T3 {
A(T1),
B(T2),
C(T3),
}
struct X<T> {
T a;
}
tuple Point(int,int,int)
tuple Point<T> where Arithmetic T (T,T,T)
type A = Foo;
type F<X> = Foo<Bar<X>>;

277
parser/Meow.g4 Normal file
View file

@ -0,0 +1,277 @@
grammar Meow;
file
: importStatement* declaration* EOF
;
importStatement
: ImportKeyword importpath=StringLiteral (AsKeyword importname=Identifier)? ';'
;
declaration
: function ';'?
| constraintDeclaration ';'?
| structDeclaration ';'?
| enumDeclaration ';'?
| tupleDeclaration ';'?
| typeAlias ';'?
;
structDeclaration
: StructKeyword name=Identifier (genericParameters constraint*)? structType
;
enumDeclaration
: EnumKeyword name=Identifier (genericParameters constraint*)? enumType
;
tupleDeclaration
: TupleKeyword name=Identifier (genericParameters constraint*)? tupleType
;
typeAlias
: TypeKeyword name=Identifier genericParameters? '=' typeReference
;
constraintDeclaration
: ConstraintKeyword name=Identifier types+=Identifier+ '{' constraintRule* '}'
;
constraintRule
: embedConstraintRule
| functionConstraintRule
;
embedConstraintRule
: ConstraintKeyword name=Identifier types+=typeReference+ ';'
;
functionConstraintRule
: name=Identifier constraintFunctionParameters functionReturn? ';'
;
constraintFunctionParameters
: '(' (typeReference (',' typeReference)*)? ')'
;
function
: attribute* pub=PubKeyword? FnKeyword name=Identifier functionParameters functionReturn? functionBody
| attribute* pub=PubKeyword? FnKeyword name=Identifier genericParameters functionParameters functionReturn? constraint* functionBody
;
attribute
: '[' name=Identifier ('(' (attributeValue (',' attributeValue)*)? ')')? ']'
;
attributeValue
: literal
| id=Identifier
;
literal
: stringLiteral
| numericLiteral
| boolLiteral
| characterLiteral
;
stringLiteral: val=StringLiteral;
numericLiteral: val=NumericLiteral;
boolLiteral: val=BoolLiteral;
characterLiteral: val=CharacterLiteral;
genericParameters
: '<' (name+=Identifier (',' name+=Identifier)*) '>'
;
functionParameters
: '(' (functionParameter (',' functionParameter)*)? ')'
;
functionParameter
: typeReference name=Identifier
;
functionReturn
: '->' (typeReference (',' typeReference)*)
;
constraint
: WhereKeyword name=Identifier typenames+=Identifier+
;
functionBody
: '{' statement* expression? '}'
;
typeReference
: nonPointerTypeReference pointer='*'?
;
nonPointerTypeReference
: typeName
| arrayType
| tupleType
| StructKeyword structType
| EnumKeyword enumType
;
typeName
: (importName=Identifier ':')? name+=Identifier ('<' genericType+=typeName (',' genericType+=typeName)* '>')? ('@' name+=Identifier)*
;
arrayType
: '[' typeReference (';' length=NumericLiteral)? ']'
;
tupleType
: '(' typeReference (',' typeReference)* ')'
;
structType
: '{' structMember* '}'
;
structMember
: typeReference name=Identifier ';'
;
enumType
: '{' enumMember (',' enumMember)* ','? '}'
;
enumMember
: name=Identifier ('(' typeReference ')')?
;
statement
: breakStatement
| continueStatement
| returnStatement
| loopStatement
| expressionStatement
;
breakStatement
: BreakKeyword label=Identifier? ';'
;
continueStatement
: ContinueKeyword label=Identifier? ';'
;
returnStatement
: ReturnKeyword expression? ';'
;
loopStatement
: LoopKeyword '{' statement* '}'
| LoopKeyword condition=expression '{' statement* '}'
| LoopKeyword init=expression? ';' condition=expression? ';' increment=expression? '{' statement* '}'
;
expressionStatement
: expression ';'
;
/*
todo: use C operator precedence: https://en.cppreference.com/w/c/language/operator_precedence
binary operators:
== != > >= < <=
||
&&
+ -
* / %
&
|
^
<<
>>
unary operators:
+
-
~
!
assignment:
=
+=
-=
/=
*=
%=
&=
|=
^=
<<=
>>=
*/
expression
: addExpression
;
addExpression
: multExpression ((op='+'|op='-') multExpression)*
;
multExpression
: terminalExpression ((op='*'|op='/'|op='%') terminalExpression)*
;
terminalExpression
: literal
| structConstructor
| arrayConstructor
| enumConstructor
| functionCall
| ifExpression
| switchExpression
| blockExpression
| parenthesisExpression
;
///////////////////////////
ImportKeyword: 'import';
AsKeyword: 'as';
PubKeyword: 'pub';
FnKeyword: 'fn';
WhereKeyword: 'where';
ConstraintKeyword: 'constraint';
StructKeyword: 'struct';
EnumKeyword: 'enum';
TupleKeyword: 'tuple';
TypeKeyword: 'type';
BreakKeyword: 'break';
ContinueKeyword: 'continue';
ReturnKeyword: 'return';
LoopKeyword: 'loop';
// start with letters (upper or lower case) followed by any alphanumeric symbol
Identifier: [a-zA-Z_][a-zA-Z_0-9]*;
NumericLiteral: DecimalNumberLiteral /*| HexadecimalNumberLiteral | OctalNumberLiteral | BinaryNumberLiteral*/;
fragment DecimalNumberLiteral: DecimalNumberPart ('.' DecimalNumberPart)? | '.' DecimalNumberPart;
fragment DecimalNumberPart: [0-9] [0-9_]*;
BoolLiteral: 'true' | 'false' ;
CharacterLiteral: '\'' (CharacterEscape | ~['\\]) '\'';
fragment CharacterEscape: '\\\'' | '\\\\';
StringLiteral: '"' (StringEscape | ~[\\"])*? '"';
fragment StringEscape: '\\"' | '\\\\';
// comments and white space -> ignored
BLOCK_COMMENT: '/*' .*? '*/' -> channel(HIDDEN);
LINE_COMMENT: '//' ~[\n]* -> channel(HIDDEN);
WS: [ \t\r\n\f]+ -> channel(HIDDEN);

3
parser/ModelBase.cs Normal file
View file

@ -0,0 +1,3 @@
namespace meowlang.parser;
public record ModelBase([property:Ignore] Span span);

20
parser/Parser.cs Normal file
View file

@ -0,0 +1,20 @@
using Antlr4.Runtime;
using meowlang.parser.antlr;
namespace meowlang.parser;
public class Parser
{
public static Model? Parse(string path)
{
var lexer = new MeowLexer(new AntlrFileStream(path));
var parser = new MeowParser(new CommonTokenStream(lexer));
var visitor = new Visitor();
var file = parser.file();
if (parser.NumberOfSyntaxErrors > 0)
{
return null;
}
return visitor.Visit(file);
}
}

3
parser/Span.cs Normal file
View file

@ -0,0 +1,3 @@
namespace meowlang.parser;
public record Span(string Filename, int From, int To);

139
parser/Utils.cs Normal file
View file

@ -0,0 +1,139 @@
using System.Collections;
using System.Reflection;
using System.Text;
using Antlr4.Runtime;
using Newtonsoft.Json;
namespace meowlang.parser;
[AttributeUsage(AttributeTargets.Property)]
public class IgnoreAttribute : Attribute
{
}
public static class ObjectExtensions
{
public static string AutoToString(this object? o, bool prettyPrint = true, bool encapsulate = true)
{
if (o == null) return "null";
var type = o.GetType();
if (o is string s)
{
var escaped = s.Replace("\\", "\\\\").Replace("\"", "\\\"");
return $"\"{escaped}\"";
}
if (o is bool b)
{
return b ? "true" : "false";
}
if (type.IsPrimitive)
{
return o.ToString()!;
}
if (type.IsEnum)
{
var val = Enum.GetName(type, o);
return $"\"{val}\"";
}
string json;
if (type.IsAssignableTo(typeof(IEnumerable)))
{
var enumerable = (o as IEnumerable)!.Cast<object>();
var sb = new StringBuilder();
sb.Append('[');
sb.AppendJoin(", ", enumerable.Select(x => x.AutoToString(false)));
sb.Append(']');
json = sb.ToString();
}
else
{
var properties = type.GetProperties();
var sb = new StringBuilder();
sb.Append('{');
sb.Append($"\"@type\": \"{type.Name}\"");
for (var index = 0; index < properties.Length; index++)
{
var propertyInfo = properties[index];
if (propertyInfo.GetCustomAttribute<IgnoreAttribute>() != null) continue;
sb.Append(',');
sb.Append($"\"{propertyInfo.Name}\": ");
var propertyValue = propertyInfo.GetValue(o);
sb.Append(propertyValue.AutoToString());
}
sb.Append('}');
json = sb.ToString();
}
if (prettyPrint)
{
var temp = JsonConvert.DeserializeObject(json);
json = JsonConvert.SerializeObject(temp, Formatting.Indented);
}
return json;
}
}
internal static class ParserRuleContextExtensions
{
public static Span GetSpan(this ParserRuleContext context)
{
return new Span(context.Start.TokenSource.SourceName, context.Start.StartIndex, context.Stop.StopIndex);
}
}
internal static class TokenExtensions
{
public static Span GetSpan(this IToken token)
{
return new Span(token.TokenSource.SourceName, token.StartIndex, token.StopIndex);
}
}
internal static class StringExtensions
{
public static string Unescape(this string str)
{
StringBuilder builder = new();
var startPos = 0;
int backslashPos;
while ((backslashPos = str.IndexOf('\\', startPos)) > -1)
{
builder.Append(str[startPos..backslashPos]);
int length;
string ch;
switch (str[backslashPos + 1])
{
case '\\':
ch = "\\";
length = 1;
break;
case '\'':
ch = "'";
length = 1;
break;
case '"':
ch = "\"";
length = 1;
break;
default:
throw new InvalidEscapeSequenceException($"\\{str[backslashPos + 1]}");
}
builder.Append(ch);
startPos = backslashPos + length + 1;
}
builder.Append(str[startPos..]);
return builder.ToString();
}
}

412
parser/Visitor.cs Normal file
View file

@ -0,0 +1,412 @@
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);

15
parser/parser.csproj Normal file
View file

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>meowlang.parser</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Antlr4.Runtime.Standard" Version="4.9.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>