The Cute Programming Language

main page: zagura.one

A multipurpose language aimed at simplicity (work very in progress)

Table of Contents

Intro to Syntax

In Cute, instead of snake_case, kebab-case is used. Also, while the syntax is meant to make it look that way, Cute is NOT whitespace-sensitive

List of Reserved Keywords

my, our, has, impl, and, or, not, use, if, elif, else, match, is, mut, const, for, in, extern
Also there's yes & no, but they're values & not just tokens

Comments

Comments can't be just written anywhere, they must be put either before a field/function/type... declaration, to document it, or before an expression to form a commented expression, to explain the code

Operators

Binary Operators

+   -   *   /   %  and  or

+ also concatenates strings or arrays, and also combines arrays with items and & or are logical operators (they short-cirquit)

Unary Operators

-  not

Comparison Operators

>  <  >=  <=  =  /=

Operator precedence

The operators that can be overloaded are:

+   -   *   /   %   =   not

If the = is overloaded, /= can be used to get the inverse result

Literals

By default, integers are written in base 10 (56, 42), but can be written in any base less than 36, by prepending them by the base number & a colon, like so: 16:00ff88, 8:1244, 2:010111010

Floats are written exactly like ints, but with a point somewhere in the number. Int literals are automatically converted into floats if a float is needed instead

Booleans are written as either yes or no

Strings are written using single quotes (') with some typical character escapes: \\, \', \n, \t, \0, and unicode character escapes: \u1234
Example: 'Hello World!\n'

Arrays are written as [a, b, c, d, e]

Ranges are written as [a..b]

For Loops

Cute has a for-loop construct, but it's actually just a sugared-up version of map and filter from other languages (so it's actually an expression, not a statement). This is what multiplying every element in the list by 2 would look like:

for x in my-list:
    x * 2

And this is what getting a list of all the prime numbers from another list would look like:

for x in my-list if x >- is-prime: x

Lambdas

To write a lambda, prefix an expression with a comma-separated list of param names, between pipes: |x, y| x + y * 2

Function Invocations

Functions are invoked like in most languages: my-function(a, b, c), but there's also a pipe-first syntax for chaining function calls: a >- my-function(b, c). To put any value after the >-, use parentheses, like so: a >- (|x| x * 2)

Definitions

You can define constants, functions, types & typeclasses. Any definition starts with either my (for private) or our (for public)

constant:
our some-name: SomeType = 69
function:
our some-name(p0: Int, p1: Fpt): SomeType = 69
type:
our :Maybe T = Yes(T) No
typeclass:
our :: Ord T = has cmp(a: T, b: T): Ordering

The types of constants can be omitted thanks to type inference

Types

These are the builtin types:

signed:
Int, Int32, Int16, Int8
unsigned:
Nat, Nat32, Nat16, Nat8
float:
Fpt, Fpt32
boolean:
Bool
string:
Str
closure:
|Int| Int
|Int, Int| Int
|x: Int, y: Int| Int
array:
[Int]
tuple:
(Int, Int)
(x: Int, y: Int)
()
params:
Maybe Int
Map[Str, Int]
List Maybe (Str, Int)

Typeclasses

Typeclasses can be used in function definitions to require certain functions for the given types to be present when the defined function is invoked.

This is really good for writing generic functions, for example to operate on any types that constitute a map, this would be the typeclass:

our :: Map K, V, M =
    has get(self: M, key: K): Maybe V
    has set(self: M, key: K, value: V): ()

And this would be a generic function using the typeclass (Map[M, K, V]):

our get-or[K, V, M](
    self: M,
    key: K,
    default: || V,
): V :: Map[M, K, V] = self >- get(key) >- or-else(default)