Syntax
type Vector3
def with_y self (y : f32) = Vector3 self.x y self.z
The self parameter prevents the y field from being shadowed by the y parameter.
let enabled_extension_names = ["VK_EXT_debug_report"
"VK_EXT_debug_utils"
"VK_KHR_surface"
"VK_KHR_xcb_surface"
"VK_KHR_xlib_surface"]
Commas are not required if each array element is located on a separate line or lines.
let thickness = (left = border.left
right = border.right
up = border.up
down = border.down)
let size = Atom<(u32, u32) width height> (0, 0)
Tuple fields can be named on creation, or when a tuple type is specified. Names have no impact on compatibility.
val identity = Matrix3 1
m22 = 1
m33 = 1
f@ struct@zero
Field values can be set positionally, by name or with a filler. Type of a filler must either match the type of the entity being created, or be a tuple with named fields. Works for object creation, initialization of a structure, type inheritance and function invocation.
let vector = Vector3@ref 1 3 8
Structure is initialized on the heap if @ref suffix is added to the type name. Binding vector is of type mut ref Vector3, which can also be written as MutRef<Vector3>. References of this kind in essence are pointers without arithmetics.
text
|> lines
|> filter { line -> line.starts_with "layout" }
|> map { remove_comment _ }
Closures are enclosed in curly braces. Each use of underscore returns the next parameter.
filter and map are methods of the List type.
object Obs =
def map<T, U> (list : List<T>) (f : T -> U) : List<U> = ...
let squares = numbers |> Obs.map { x -> x * x }
numbers is passed to Obs.map as the first argument.
type Array<T> @byval =
val size : u32
let ptr @param = kedr/alloc<T> size
The @param attribute allows a replacement value to be passed as a named argument, can be used in functions as well.
let up_right = Vector3 left.as<f32> 0 border_z
let adjusted_size = size as f32 * 1.5 |> as<u32>
Type cast can be written without parentheses.
let list @owner = List@mrc.new
Modifier @mrc stands for manual reference counting. The @owner attribute guarantees that memory is freed before the containing function returns, is also available for object fields.
The new keyword is used only for types without constructor parameters.
import num/vector_f32/Vector3
Vector4
vector_i32/Vector2i
control.set_width width
set_height control.measure_height
arrange
Methods set_width, set_height and arrange are called on the same control binding.
type Entry =
path : String
created : DateTime
| File size : u32
| Directory entries : Slice<Entry>
| Local
| Remote url : String
Entry and Directory are sum types. Structures File, Local and Remote inherit the path and created fields. Local and Remote also contain the entries.
type CString ptr
fun get (i : u32) = ptr[i]
The only item of a tuple is bound to the ptr.
Special functions are defined with fun, fun get is an indexer getter.
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>
The ptr field has different types for Slice and mut Slice.
type Object =
var room : Room @late
The room binding is not a constructor parameter, will throw an error if accessed before assigned.
# Single-line comment
/* Multiline comment */
Closing part of a multiline lexeme is optional.
Visibility and mutability
val defines a binding, var — mutable binding, def — a function, let — binding or function, private to a file.
var align_h @mut = AlignH/Stretch
val items @mut = List<Control>.new
The List type has a mutable version mut List. Readonly type cannot be casted back to mutable.
When the file ends, var bindings become readonly and val bindings of mutable types get readonly version of the type. The @mut attribute serves to prevent this.
var size : u32 @[mut internal] = 0
The @mut attribute argument specifies the mutability scope.
type Grid @mut =
var count : u32 = 0
var distance : u32 = 0
Fields become mutable everywhere by default because of the @mut attribute at the type level.
begin@ editor
type Editor =
var count : u64 = 0
local mut should_separate = false
let rectangle = Rectangle.new
end@ editor
editor is a logical file. Outside of editor the count binding becomes readonly, while should_separate is no longer visible. rectangle becomes inaccessible when either editor or the physical file ends.
internal@
var array = Array<T> 0
Apart from the let and local keywords, visibility is also restricted using directives: private@ — private in file, local@ — private in logical file, protected@ — private in hierarchy, internal@ — private in crate.
Generic declaration
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
Specializations of the Kd.hash function are defined separately for each combination of argument types.
Attached functions
type Control =
var width : u32 = 0
var min_width : u32 = 0
var max_width = u32.max
coerce@ width { _.clamp min_width max_width }
The value of width will always be between min_width and max_width.
observe@ width { _ w ->
let event = SizeEvent/Width w
push event }
The closure is invoked after each write to the field.
Dependency injection
type Selector =
let add_popup : Control -> Unit @auto
let remove_popup : Control -> Unit @auto
let main () =
let selector = Selector.new
let add_popup @publish = app.display.add_popup
let remove_popup @publish = app.display.remove_popup
main
Values of the published add_popup and remove_popup bindings will be passed to the corresponding fields of the Selector object. Both name and type need to match.
Object tree
let stack = Stack
align_h = AlignH/Left
items <- margin, text_block
run@ set_fixed_width 200
Expression creates a new Stack object, assigns AlignH/Left to the align_h field, adds margin and text_block to the items list, invokes the set_fixed_width method.
stack
align_v = AlignV/Center
is_horizontal = true
The type name is replaced with the binding name, so a stack is returned instead of a new object.
let border = Border.new
let stack = Stack.new
border
thickness = 5
stack
Button
text = "save"
on_press <- { save_current_file }
Button
text = "load"
on_press <- { show_load_dialog }
stack is assigned to border.content and buttons are added to stack.items. The content and items fields have the @dst attribute.