first commit wtf am I doing
This commit is contained in:
commit
78fe931f97
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
/packages/
|
||||||
|
riderModule.iml
|
||||||
|
/_ReSharper.Caches/
|
||||||
|
.idea
|
||||||
|
gen/
|
22
MeowLang.sln
Normal file
22
MeowLang.sln
Normal 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
316
README.md
Normal 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
14
compiler/Compiler.cs
Normal 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
26
compiler/compiler.csproj
Normal 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
91
compiler/example.mew
Normal 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
277
parser/Meow.g4
Normal 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
3
parser/ModelBase.cs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
namespace meowlang.parser;
|
||||||
|
|
||||||
|
public record ModelBase([property:Ignore] Span span);
|
20
parser/Parser.cs
Normal file
20
parser/Parser.cs
Normal 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
3
parser/Span.cs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
namespace meowlang.parser;
|
||||||
|
|
||||||
|
public record Span(string Filename, int From, int To);
|
139
parser/Utils.cs
Normal file
139
parser/Utils.cs
Normal 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
412
parser/Visitor.cs
Normal 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
15
parser/parser.csproj
Normal 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>
|
Loading…
Reference in a new issue