Синтаксис

type Vector3
    def with_y self (y : f32) = Vector3 self.x y self.z

Параметр self предотвращает затенение поля y одноимённым параметром.

let enabled_extension_names = ["VK_EXT_debug_report"
                               "VK_EXT_debug_utils"
                               "VK_KHR_surface"
                               "VK_KHR_xcb_surface"
                               "VK_KHR_xlib_surface"]

Запятые между элементами массива не нужны, если каждый находится на отдельной строке или строках.

let thickness = (left = border.left
                 right = border.right
                 up = border.up
                 down = border.down)

let size = Atom<(u32, u32) width height> (0, 0)

Имена полей кортежа не влияют на совместимость типов.

val identity = Matrix3 1
                       m22 = 1
                       m33 = 1                    
                       f@ struct@zero

Задавать значения полей можно позиционно, по имени и с помощью заполнителя. Применимо для создания объектов, инициализации структур, наследования типов и вызова функций. Тип заполнителя должен либо совпадать с типом создаваемой сущности, либо быть кортежем с именованными полями.

let vector = Vector3@ref 1 3 8

Структура инициализируется в куче из-за суффикса @ref. Привязка vector имеет тип mut ref Vector3, что также можно записать как MutRef<Vector3>. Ссылки такого рода по сути являются указателями, которые вместо традиционных для указателей операций дают доступ к полям и методам типа.

text
|> lines
|> filter { line -> line.starts_with "layout" }
|> map { remove_comment _ }

Замыкания создаются с помощью фигурных скобок. Каждое использование подчёркивания возвращает следующий параметр.

filter и map это методы типа List.

object Obs =
    def map<T, U> (list : List<T>) (f : T -> U) : List<U> = ...
        
let squares = numbers |> Obs.map { x -> x * x }        

Значение numbers передаётся в функцию Obs.map в качестве первого аргумента.

type Array<T> @byval =
    val size : u32
    let ptr @param = kedr/alloc<T> size

Атрибут @param делает привязку необязательным именованным параметром конструктора, может также использоваться в функциях.

let up_right = Vector3 left.as<f32> 0 border_z
let adjusted_size = size as f32 * 1.5 |> as<u32>

Преобразование типа можно записать без скобок.

let list @owner = List@mrc.new

Модификатор @mrc, расшифровывается как manual reference counting, даёт доступ к версии типа без автоматического подсчета ссылок. Атрибут @owner гарантирует освобождение памяти перед выходом из содержащей привязку функции, также доступен для полей объектов.

Ключевое слово new используется для типов без параметров конструктора.

import num/vector_f32/Vector3
                      Vector4
           vector_i32/Vector2i

control.set_width width
        set_height control.measure_height
        arrange

Методы set_width, set_height и arrange вызываются на одной и той же привязке control.

type Entry =
    path : String
    created : DateTime

    | File size : u32
    | Directory entries : Slice<Entry>
                | Local
                | Remote url : String

Entry и Directory это типы-суммы. Структуры File, Local и Remote наследуют поля path и created. Local и Remote также содержат entries.

type CString ptr
    fun get (i : u32) = ptr[i]

Значение единственного элемента кортежа привязывается к ptr.

Особые функции определяются через ключевое слово fun, fun get это индексатор.

type Slice<T> @byval =
    val ptr : Ptr<T>
    val size : u32

type MutSlice<T> @byval @[mut_of Slice] =
    val ptr : MutPtr<T> @impl

    inherit Slice<T>

Поле ptr имеет разные типы для Slice и mut Slice.

type Object =
    var room : Room @late

Привязка room не является параметром конструктора, вернёт ошибку при попытке чтения до присвоения значения.

# Однострочный комментарий

/* Многострочный комментарий */

Закрывающая часть многострочной лексемы не обязательна.

Видимость и изменяемость

val определяет привязку, var — изменяемую привязку, def — функцию, let — привязку или функцию, доступную только в текущем файле.

var align_h @mut = AlignH/Stretch
val items @mut = List<Control>.new

У типа List есть изменяемая версия mut List. Тип только для чтения нельзя снова преобразовать в изменяемый.

Без атрибута @mut по окончании файла привязка align_h превратится в только для чтения, а items получит тип List<Control> вместо mut List<Control>.

var size : u32 @[mut internal] = 0

Аргумент атрибута @mut уточняет область изменяемости привязки.

type Grid @mut =
    var count : u32 = 0
    var distance : u32 = 0

Поля становятся изменяемыми повсеместно по-умолчанию благодаря атрибуту @mut на уровне типа.

begin@ editor

type Editor =
    var count : u64 = 0
    local mut should_separate = false
    let rectangle = Rectangle.new

end@ editor

editor это логический файл. За пределами editor привязка count становится только для чтения, а should_separate не видна. rectangle становится недоступной, когда заканчивается либо editor, либо физический файл.

internal@

var array = Array<T> 0

Помимо ключевых слов let и local, видимость элементов также ограничивается с помощью директив: private@ — внутри файла, local@ — внутри логического файла, internal@ — внутри ящика, protected@ — внутри иерархии.

Примесь

type Control @abstract =
    def measure (w : u32) (h : u32)
    def arrange

type SingleChildLayout @mixin =
    require Control

    def Control.measure w h =
        measure_single_child self w h

    def Control.arrange =
        arrange_single_child self

type Button =
    inherit Control
    include SingleChildLayout

Control объявляет абстрактные методы measure и arrange.

Примесь SingleChildLayout может быть включена только в тип, наследующий Control.

Button получает содержимое SingleChildLayout, но связь наследования между типами не создаётся.

Обобщённое объявление

object Kd =
    def hash<T> @decl (x : T) (state : HashState)

def Kd.hash @impl (x : bool) state =
    let i = if x then 1 else 0
    Kd.hash<i32> i state

Специализации функции Kd.hash задаются отдельно для каждой комбинации типов аргументов.

Прикреплённые функции

type Control =
    var width : u32 = 0
    var min_width : u32 = 0
    var max_width = u32.max

    coerce@ width { _.clamp min_width max_width }

Значение поля width всегда будет находиться в диапазоне между min_width и max_width.

observe@ width { _ w ->
    let event = SizeEvent/Width w
    push event }

Замыкание вызывается после каждой записи в поле.

Внедрение зависимостей

type Selector =
    let overlay : Overlay @auto

let overlay @publish = display.overlay

let selector = Selector.new

Привязки с атрибутом @auto получают значения из опубликованных привязок при соответствии имён и типов.

Дерево объектов

let stack = Stack
    align_h = AlignH/Left
    items <- margin, text_block
    run@ set_fixed_width 200

Выражение создаёт новый объект Stack, присваивает AlignH/Left его полю align_h, добавляет margin и text_block в список items, вызывает метод set_fixed_width.

stack
    align_v = AlignV/Center
    is_horizontal = true

Мы заменили имя типа именем привязки, поэтому вместо нового объекта возвращается stack.

let border = Border.new
let stack = Stack.new

border
    stack
        Button
            text = "save"
            on_press <- { save_current_file }
        Button
            text = "load"
            on_press <- { show_load_dialog }

Объект stack присваивается полю border.content, кнопки добавляются в список stack.items. Поля content и items обозначены атрибутом @dst.