meowlang/README.md

317 lines
5.5 KiB
Markdown
Raw Normal View History

2022-02-12 02:29:25 +01:00
# 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}
```