You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Gwendolyn 18d35a5f1e make exceptions cooler and fix example code 1 year ago
compiler make exceptions cooler and fix example code 1 year ago
parser make exceptions cooler and fix example code 1 year ago
typechecker loooots of stuff 1 year ago
visitorgenerator make exceptions cooler and fix example code 1 year ago
.gitignore first commit wtf am I doing 1 year ago
MeowLang.sln loooots of stuff 1 year ago loooots of stuff 1 year ago


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?




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;



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(a: int, b: Foo, c: Bar): int {


[c_export("renamed_foo2")] pub fn foo2(a: int, b: Foo, c: Bar): int, int {


Functions can be overloaded on parameter and return types

fn a(): s32 {
    return -1;
fn a(): u32 {
    return 1;

fn a(x: i32, y: i32): (i32, i32) {
    return y, x;

fn a(x: u32): u32 {
    return x + 1;


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;



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).


The character literal is a single unicode character enclosed in single quotes, its value is the character's unicode code point.


true and false


String literals are enclosed in double quotes (e.g. "hello world"). Their type is an u8 array with length of the string in bytes.


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
// array
[u8; 10]
// slice

let a: [u8] = "foo";
let b: u8 = a[1]; 
let d: [s32; 4] = []{1,2,3,4};
let e = [u8]{1,2,3,4};

let f = d[1:3]; // f has type [s32] (slice) now

type Arr = [u8];
let g = Arr[]{1,2,3};

struct Point {
    x: s32;
    y: s32;
    z: s32;
type Point = struct {
    x: s32;
    y: s32;
    z: s32;

type Options = struct {
    api: struct {
        int foo;
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 A {

type A = enum {

type B = enum {
    Y(enum { // this is terrible but you can do it if you want for consistency reasons

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
type X = (s8, s8);
tuple X(s8, s8);
type Y = (struct {int a; int b}, enum {A, B}); // why would you do this aaaaa
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 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} 

operator precedence

. (struct member access), [] array subscripting
 unaries: + - ! ~, pointer dereference *, pointer reference &, 
 binary operators:
 * / %
 + -
 << >>
 > >= < <=
 == !=
 lowest precedence, assignment: