Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- The official LAC language standard.
- Last edited: 2026-06-04.
- PART 00 - Metadocumentation
- 00 Introduction
- The present document, which defines the LAC programming language, shall be organized into three levels of
- subdivision: PARTs, SECTIONs and CLAUSEs, following a common structure.
- Current PARTs include:
- 00 - Metadocumentation
- 01 - Rationale
- 02 - Program structure
- 03 - The LAC preprocessor (LPP)
- 04 - Types
- 05 - Expressions
- 06 - Functions
- 07 - Statements
- 08 - Variables
- 09 - The LAC standard library
- 10 - Naming conventions
- 11 - The LAC transpiler (LACT)
- 01 Format rules
- Text between backticks (\`), except when escaped or matching any of the following rules, shall refer
- literally to LAC tokens or identifiers, or substrings thereof.
- Text inside braces (\{\}), except when escaped, shall define a semantic block.
- Text inside brackets (\[\]), except when escaped, shall hold a placeholder and define a semantic block.
- Semantic blocks followed by a question mark (\?) shall declare it optional (may be present once).
- 02 Keyword table
- The following table shall associate all LAC keywords with their respective section within the standard.
- KEYWORD RELEVANT SECTIONS KIND
- ==========================================================================================================
- align (PART 04, SECTION 02) and (PART 08, SECTION 01) Type specifier
- alignof (PART 05, SECTION 00) Constant operator
- atomic (PART 08, SECTION 01) Type specifier
- break (PART 07, SECTION 02) Control flow
- case (PART 07, SECTION 03) Control flow
- cond (PART 07, SECTION 04) Control flow
- const (PART 08, SECTION 01) Type qualifier
- continue (PART 07, SECTION 05) Control flow
- countof (PART 05, SECTION 00) Constant operator
- default (PART 07, SECTION 06) Control flow
- defer (PART 07, SECTION 07) Control flow
- do (PART 07, SECTION 08) Control flow
- else (PART 07, SECTION 09) Control flow
- enum (PART 04, SECTION 02) Type declarator
- fallthrough (PART 07, SECTION 10) Control flow
- fn (PART 06, SECTION 01) Function type
- for (PART 07, SECTION 11) Control flow
- goto (PART 07, SECTION 12) Control flow
- if (PART 07, SECTION 13) Control flow
- null (PART 04, SECTION 00) Constant value
- offsetof (PART 05, SECTION 00) Constant operator
- parcel (PART 04, SECTION 02) Type declarator
- remanent (PART 08, SECTION 01) Type specifier
- restrict (PART 08, SECTION 01) Type qualifier
- return (PART 07, SECTION 14) Control flow
- sizeof (PART 05, SECTION 00) Constant operator
- struct (PART 04, SECTION 02) Type declarator
- switch (PART 07, SECTION 15) Control flow
- threadlocal (PART 08, SECTION 01) Type specifier
- union (PART 04, SECTION 02) Type declarator
- volatile (PART 08, SECTION 01) Type qualifier
- while (PART 07, SECTION 16) Control flow
- [OPERATORS] (PART 05, SECTION 00) Expression
- [TYPES] (PART 04) Type qualifier
- as (Subdirective; see others) LPP directive
- #assert (PART 03, SECTION 04) LPP directive
- #c (PART 03, SECTION 02) LPP directive
- #error (PART 03, SECTION 04) LPP directive
- #eval (PART 03, SECTION 03) Expression
- #gen (PART 03, SECTION 05) LPP directive
- #import (PART 03, SECTION 01) LPP directive
- #label (PART 07, SECTION 12) LPP directive
- #unpack (PART 03, SECTION 01) LPP directive
- PART 01 - Rationale
- 00 Goal
- The goal of the LAC programming language is to provide an ergonomic, more elegant alternative to the C
- programming language, which is shackled by its backwards-compatibility requirements, without meaning to
- replace it outright.
- 01 Philosophy
- In essence, LAC serves as a translation layer between the user and C: it aims to reduce undefined or
- implementation-defined behavior while providing a cleaner standard library, without foregoing C's extensive
- tooling suites. As such, all C code produced by the LAC transpiler (LACT) should be human-readable and
- easily correlated with LAC source code while debugging or profiling.
- 02 Limits
- The LAC programming language does not aspire to be widely adopted or to become a new standard. Its primary
- goal is to serve as main language for me (lzg), and as such may change (breaking backwards-compatibility) if
- it is deemed important enough.
- PART 02 - Program structure
- 00 Overview
- A LAC program is comprised of one or more translation strands (TS), which are pairs of LAC source files
- (.lacs) and LAC external files (.lace).
- LAC source and external files shall only allow ASCII characters (0-127), except inside string or character
- literals (see PART 05, SECTION 02).
- Furthermore, identifiers shall only be composed of alphanumeric characters (a-z, A-Z, 0-9) in addition to
- the underscore (`_`) and at ('@') characters, and may not begin with a digit (0-9).
- Note: if an identifier begins with a double underscore (`__`), it is reserved.
- 01 .lace files
- The role of the lace is to provide external linkage with other strands, not unlike C's header files.
- As such, the lace may choose to expose to other strands:
- - LPP linking directives (see PART 03, SECTION 01)
- - Public type declarations (see PART 04, SECTION 02)
- - Public global variable prototypes (see PART 08, SECTION 00)
- - Public function prototypes (see PART 06, SECTION 00)
- Note: while not enforced, it is recommended to follow the above order when writing lace files.
- 02 .lacs files
- The role of the LAC source file is to provide both lace directives (which will be private to this strand),
- and implementation/initialization for the declared functions/variables.
- A LAC source file may contain the following toplevel statements:
- - LPP directives (see PART 03)
- - Public global variable declarations (see PART 08, SECTION 01)
- - Private type declarations (see PART 04, SECTION 02)
- - Private global variable declarations (see PART 08, SECTION 01)
- - Public function declarations (see PART 06, SECTION 01)
- - Private function declarations (see PART 06, SECTION 01)
- Note: while not enforced, it is recommended to follow the above order when writing source files.
- Global variable declarations not initialized using the assignment operator are cleared (set to zero).
- Unlike C, private ("helper") functions do not require a prototype before declaration.
- 03 Strand scoping
- Linking with another strand (see PART 03, SECTION 01) brings its strand descriptor (SD) in scope.
- An SD represents the other strand's lace, and may be accessed as if a `struct` (using the `.` operator).
- SDs may contain other SDs, in which case chained access (still using the `.` operator) is required, except
- if the lace `unpack`s the nested SDs.
- 04 Program entry point
- As in C, a program's entry point is a function named `main`, which can have the following types:
- - i32(void)
- - i32(u64, **u8)
- The number of arguments is passed in the `u64` while the arguments themselves are passed as null-terminated
- strings in an array of the given size.
- The return value is an `i32` to conform to C-style program execution expectations.
- PART 03 - The LAC preprocessor (LPP)
- 00 LPP overview
- Unlike the C preprocessor (CPP), which uses special syntax to provide metaprogramming capabilities (through
- textual replacement), the LPP offers only a few essential directives and lets the programmer use the LAC
- language itself to preprocess code.
- As in C, the LPP is invoked using the hash (`#`) character, though this is only a convention, as any
- identifier may include it, although frivolous usage of special characters is discouraged.
- 01 Linking
- The LPP directives `import`, `as` and `unpack` shall provide facilities for one strand to interface with
- others through their lace (see PART 02, SECTION 03).
- To access external functionality, the LPP shall provide the `import` directive, which brings a strand
- descriptor into scope, optionally aliasing it when using the `as` keyword.
- The linking syntax shall be of the form:
- - `#import [STRAND REFERENCE] {as [ALIAS]}?;`
- Where [STRAND REFERENCE] is a string literal corresponding to the lace file name.
- The LACT shall search for the given lace in the following directories, in the given order:
- - /usr/lace/
- - /usr/local/lace/
- - ./
- - Importation paths as specified to the LACT (see PART 11, section [TODO])
- And [ALIAS] is an alternate handle for referencing the same SD.
- To avoid unnecessary verbosity when accessing strand descriptors, the LPP shall provide the `unpack`
- directive to bring strand descriptors' contents to toplevel. The full SD path can still be used.
- The unpacking syntax shall be of the form:
- - `#unpack [STRAND COMPONENT LIST]`
- Where [STRAND COMPONENT LIST] is a comma-separated list of declarations or SD handles to be
- brought to toplevel. For a complete list of SD declarations, see PART 02, SECTION 01.
- 02 C interoperability
- The LPP shall provide facilities to interact with the C language through the use of the `#c` directive,
- which shall use the following syntax:
- - `#c([C TOKENS]);`
- Where [C TOKENS] is literal C code to be inserted in place of the `#c` directive. The CPP may also be
- accessed using this directive.
- For example:
- - `#c(#define _POSIX_C_SOURCE 200809L);`
- - `#c(#ifndef _WIN32);` ... `#c(#endif);`
- - `#c(#include "string.h");` ... `#c(strdup)(lacString);`
- C errors are not detected by the LACT and may depend on the underlying C compiler (especially when
- using external C libraries). The LACT shall print CC output on compilation failure.
- Interacting with LAC from C is also possible, as all lact functions and global variables are `.o` symbol
- references. Their handles are formed by concatening together the LAC prefix, the strand name and the symbol
- handle itself using the following syntax:
- - `[LAC PREFIX][STRAND]_[HANDLE]`
- Where [LAC PREFIX] is `LaC__`
- And [STRAND] is the strand name without its extension
- And [HANDLE] is the symbol name.
- For example, in file `prgmstate.lacs`:
- - `[256]u8 chrbuf;` -> `LaC__prgmstate_chrbuf`
- - `fn i32 isalnum(u8 char);` -> `LaC__prgmstate_isalnum`
- 03 Translation-time code evaluation
- To facilitate integration of non-trivial but constant computation in programs, the LPP shall provide the
- `#eval` directive, using the following syntax:
- - `#eval([EXPRESSION])`
- Where [EXPRESSION] is any LAC expression returning a scalar value.
- The expression is executed in a virtual instance of the program, so pointers will be invalid and
- modified state is discarded.
- Other side effects which modify external state, such as file modification, however, are retained,
- although using such tricks is not encouraged.
- 04 Translation-time code verification
- The LPP shall provide facilities for translation-time code verification through the `#assert` and `#error`
- directives, which shall use the following syntax:
- - `#assert([EXPRESSION], [ERROR STRING]);`
- - `#error([ERROR STRING]);`
- Where [EXPRESSION] is any expression, to be `#eval`uated at translation-time (see PART 03, SECTION 04)
- And [ERROR STRING] is a string literal (see PART 05, SECTION 02) to be printed on error or misassertion.
- 05 Translation-time code generation
- The most versatile part of the LPP lies in its ability to generate and process arbitrary instructions prior
- to compilation, using the `#gen` directive, which shall use the following syntax:
- - `#gen([EXPRESSION])`
- Where [EXPRESSION] is any expression which returns a null-terminated ASCII string (`*u8`).
- In practice, the [EXPRESSION] is almost always a function returning the string to be literally inserted
- in the program. Because this function can read files, which includes program files, the `#gen` directive
- may be used to generate arbitrarily complex programs from within LAC.
- PART 04 - Types
- 00 Primitive types
- LAC primitives shall be part of one of the following categories:
- - Floating-point numbers (f) (IEEE-754)
- - Unsigned integers (u)
- - Bitwise numbers (n)
- - Signed integers (i)
- Primitives are named using the following syntax:
- - `[FAMILY][BITWIDTH]`
- Where [FAMILY] is one of the previously-declared categories, and [BITWIDTH] is the type size in bits.
- The LAC language shall define the following [FAMILY][BITWIDTH] pairs to refer to primitive types:
- - f16, f32, f64, f128
- - u8, u16, u32, u64, u128
- - n8, n16, n32, n64, n128
- - i8, i16, i32, i64, i128
- - void (decays to u8 when pointed to; otherwise is a placeholder)
- Furthermore, the keyword `null` shall be defined as zero, which is a reserved value guaranteed not to point
- to accessible memory.
- 01 Type casting
- To convert values between types, the LAC language shall make use of type-casting, which may change the
- bitwise representation of the number depending on the types being reassigned.
- The unary cast operator shall be of the syntax:
- - `([TYPE]) [EXPR]`
- Where [TYPE] is either a primitive or compound type
- And [EXPR] is a LAC expression (see PART 05)
- The LAC language shall disallow the use of differing types within a single expression without an explicit
- cast (see PART 05, SECTION 00), except when casting to a bitwise type of equal or greater width.
- Implicit cast of types with different specifiers (e.g. `u64` to `atomic u64`) is likewise disallowed.
- Implicit cast of types with different qualifiers (e.g. `u8` to `const u8`) is allowed when adding qualifiers.
- Implicit cast of arrays to pointers and vice-versa is allowed.
- The following table shall list all type-casts which modify the bitwise representation of the number.
- All unspecified pairs shall not change this bitwise representation.
- Casts to an equivalent or wider type
- - f <-> u IEEE-754 <-> unsigned binary number Truncates, snaps to nearest
- - f <-> i IEEE-754 <-> signed two's complement number Truncates, snaps to nearest
- - u <-> i unsigned binary number <-> signed two's complement number Sign-extends
- Casts to a narrower type
- - f <-> u IEEE-754 <-> unsigned binary number Truncates, snaps to nearest
- - f <-> i IEEE-754 <-> signed two's complement number Truncates, snaps to nearest
- - u <-> i unsigned binary number <-> signed two's complement number Modulo capacity
- 02 Type declaration
- The LAC language shall allow for the creation of user-defined types through the following keywords:
- - `struct` (Equivalent to C `struct`s)
- - `parcel` (Equivalent to packed `struct`s)
- - `union` (Equivalent to C unions)
- - `enum` (Can be used with any underlying types, provided constant initializers)
- `struct`s, `parcel`s, `union`s and `enum`s shall be declared with the following syntax:
- - `struct [IDENTIFIER] align([ALIGNMENT])? { [MEMBER LIST] };`
- - `parcel [IDENTIFIER] align([ALIGNMENT])? { [MEMBER LIST] };`
- - `union [IDENTIFIER] align([ALIGNMENT])? { [MEMBER LIST] };`
- - `enum([ENUM TYPE]) align([ALIGNMENT])? [IDENTIFIER] { [VALUE LIST] };`
- Where [ALIGNMENT] is a valid type alignment (see PART 08, SECTION 01)
- And [IDENTIFIER] is a name unique to this strand's namespace
- And [MEMBER LIST] is a semicolon-separated list of LAC variable prototypes (see PART 08, SECTION 00)
- And [ENUM TYPE] is the underlying enumeration type
- And [VALUE LIST] is a comma-separated list of constant [ENUM TYPE] variable initializers.
- Once declared, the provided [IDENTIFIER] shall be used to refer to the type itself, and can be used where
- any LAC primitive would otherwise be.
- As in C, the `.` operator shall be used to access `struct`, `parcel` and `union` members,
- and the `->` operator shall be used to dereference and access these types.
- Unlike C, `enum` values cannot be reference without specifying the `enum` identifier followed by a `.` first.
- 03 Compound types
- Types may be combined to form more precise compound types, which mix and match function prototypes, array
- syntax and pointer notation.
- LAC compound types act as a single, cohesive unit; they may accept type modifiers (see [TODO])
- and be used where primitive types would be.
- Furthermore, unlike C, LAC compound types are spatially contiguous; that is, any compound type is
- representable by a single, unbroken string.
- Compound types end with a type, preceded by an agglomeration of the following components:
- - `*`
- - `\[[ARRAY LENGTH]\]`
- - `fn [FUNCTION RETURN TYPE]([FUNCTION PARAMETER LIST])`
- Where [ARRAY LENGTH] is a constant positive integer
- And [FUNCTION PARAMETER LIST] is a comma-separated list of function parameters (see PART 06, SECTION 02)
- Parameter lists take in everything preceding them as a return type, while other components compound in
- the same order they are accessed with (see PART 05, SECTION 00).
- For example:
- - `*i32` -> pointer to an `i32`
- - `[3]f32` -> array of 3 `f32`
- - `*[16][2]u64` -> pointer to an array of 16 array of 2 u64
- - `*fn void(*u8, *u64)` -> pointer to function returning void taking (pointer to u8, pointer to u64)
- PART 05 - Expressions
- 00 Operators
- The following (exhaustive) table shall list all LAC operators from highest to lowest precedence:
- PRECEDENCE 0
- - `++`, `--`
- Suffix increment/decrement.
- - `()`
- Function call.
- Builtin function-like keywords also benefit from function call syntax, such as:
- - `alignof()` Query alignment in bytes of argument.
- - `countof()` Query member count of argument (array).
- - `offsetof()` Query offset in bytes of argument (struct member).
- - `sizeof()` Query size in bytes of argument.
- - `[]`, `*`
- Array access/dereference.
- - `.`, `->`
- `struct`, `parcel`, `union` or `enum` access.
- PRECEDENCE 1
- - `++`, `--`
- Prefix increment/decrement.
- - `-`
- Unary minus (two's complement conversion).
- - `!`, `~`
- Logical/bitwise NOT.
- - `([TYPE])`
- Type cast (see PART 04, SECTION 01).
- - `&`
- Address reference.
- PRECEDENCE 2
- - `*`, `/`, `%`
- Multiplication, division, remainder.
- - `<<`, `>>`
- Bitwise left and right shift.
- Note: right shift is arithmetic when operating on signed types.
- PRECEDENCE 3
- - `+`, `-`
- Addition, subtraction.
- Note: pointer/array arithmetic implicitly multiplies by type size (in bytes).
- For example, if `u64 p*;`, then `p++;` will add 8 (bytes) to p.
- PRECEDENCE 4
- - `<`, `<=`, `>`, `>=`
- Relational smaller-than/greater-than operators.
- PRECEDENCE 5
- - `==`, `!=`
- Relational equality operators.
- PRECEDENCE 6
- - `&`
- Bitwise AND.
- PRECEDENCE 7
- - `^`
- Bitwise XOR.
- PRECEDENCE 8
- - `|`
- Bitwise OR.
- PRECEDENCE 9
- - `&&`
- Logical AND (short-circuiting).
- PRECEDENCE 10
- - `||`
- Logical OR (short-circuiting).
- PRECEDENCE 11
- - `[COND]?[TRUE]:[FALSE]`
- Ternary operator.
- PRECEDENCE 12
- - `=` Simple assignment (rvalue is after assignment).
- - `+=, `-=`, `*=`, `/=`, `%=`, `<<= `>>=`, `&=`, `^=`, `|=`, '~=`, Combined simple assignment.
- PRECEDENCE 13
- - `,`
- Comma operator.
- An expression within parentheses is parsed with precedence level 0, although parentheses are not themselves
- expressions; an empty standalone `()` is illegal.
- 01 Expression syntax
- A LAC expression shall be one of the following:
- - A literal (see PART 05, SECTION 02).
- - A global or local variable.
- - An operator acting on one or more LAC expressions (see PART 05, SECTION 00).
- Only LAC expressions which yield an lvalue (that is, an address in memory) can be assigned to, but all LAC
- expressions can be assigned from.
- For example, consider:
- - `[16]u64 arr;` Array declaration (see PART 08, SECTION 01).
- - `arr[4] = 64;` Legal; `arr[4]` is shorthand for `(arr+4)`, which has a memory address.
- - `arr[1]++ = 12` Illegal; `arr[1]++` is of type `u64`, not `*u64` and cannot be assigned to.
- 02 Literals
- LAC literals may be either number literals, character literals or string literals. To explicitate memory
- usage, there are no compound literals for user-defined types or arrays, and these must be initialized
- (preferably with `remanent` storage) beforehand.
- Number literals are declared using the following syntax:
- - `[BASE]?[NUMBER]{.[FRACTIONAL PART]}?[PRIMITIVE TYPE]`
- Where [BASE] is one of the following:
- - `[NONE]` Decimal.
- - `0b` Binary.
- - `0o` Octal.
- - `0x` Hexadecimal.
- And both [NUMBER] and [FRACTIONAL PART] are sequences of digits in their respective bases
- And [PRIMITIVE TYPE] is one of the types outlined in PART 04, SECTION 00.
- Note: hexadecimal digits must be uppercase (A-F).
- Note: underscores (`_`) are ignored within number literals.
- Character literals shall be declared using the following syntax:
- - `'[CHAR]'`
- Where [CHAR] is a possibly escaped character mapping to one or more byte. In effect, a character literal
- acts as if a number literal with the same value.
- The following list shall map all character escape sequences to their actual value:
- - `\[OCT]` Character with octal value [OCT].
- - `\x[HX]` Character with hex value [HX].
- - `\a` 0x07; Alert (BEL) character.
- - `\b` 0x08; Backspace (BS) character.
- - `\e` 0x1B; Escape (ESC) character.
- - `\n` 0x0A; Newline (LF) character.
- - `\r` 0x0D; Carriage return (CR) character.
- - `\t` 0x09; Horizontal tab (HT) character.
- - `\v` 0x0B; Vertical tab (VT) character.
- - `\\` 0x5C; Backslash (\\) character.
- - `\'` 0x27; Apostrophe (') character.
- - `\"` 0x22; Double-quotes (") character.
- - `\U+[UNI]` Unicode codepoint with hex value [UNI] (4 to 6 digits).
- String literals shall be declared using the following syntax:
- - `"[STRING]"`
- Where [STRING] is a sequence character literals, without the apostrophes (`'`).
- Strings literals are implicitly null-terminated, and cannot be modified (as if `const`).
- PART 06 - Functions
- 00 Function prototypes
- LAC function prototypes are a kind of toplevel lace statement used to link with a public function.
- They follow the same syntax as a function declaration (see PART 06, SECTION 01), but without a body.
- Prototype parameters must be named and match the declaration signature (see PART 06, SECTION 02).
- 01 Function declaration
- LAC functions shall be declared using the following syntax:
- - `fn [RETURN TYPE] [IDENTIFIER][PARAMETER LIST] \{ [BODY] \}`
- Where [RETURN TYPE] is the function return type
- And [IDENTIFIER] is a name unique to this stand's namespace
- And [PARAMETER LIST] is the function parameter list (see PART 06, SECTION 02)
- And [BODY] is the function body (see below).
- Function bodies shall group statements (see PART 07) to be executed in control flow order, terminating
- when reaching a `return` statement (see PART 07, SECTION 14) or end of scope. Only functions with
- return type `void` may omit `return` this way.
- Functions may be declared within functions; this has the effect of restricting the inner function's linkage
- to only the scope within which it was declared.
- Identifiers prefixed with the dollar (`$`) character used inside nested functions refer to its outside scope
- and are implicitly passed as arguments.
- 02 Function parameters
- Function calls, prototypes and declarations all interface through the parameter list, which identify the
- function to the outside world.
- Parameter lists are comma-separated lists of function parameters, each of which must be named with an
- identifier unique to the function's namespace, and typed as if it were a local variable declaration. (see
- PART 08, SECTION 01). In effect, parameters are a special kind of local variable which are initialized with
- the callee's passed values on function call.
- PART 07 - Statements
- 00 Scopes
- Statements are semicolon-terminated instructions affecting the program state whilst evaluating expressions
- (see PART 05). Some expressions, such as assignment, may themselves be statements.
- Statements typically affect only the next statement (or expression); as such, it is common to create scopes
- to group code together. Scopes are declared by enclosing statements within curly braces (`\{` and `\}`).
- Stack-allocated memory is automatically free'd on scope exit.
- 01 Expression statements
- LAC expression statements shall be one of the following:
- - Function calls
- - Assignment/modification operators
- 02 Break
- A `break` statement shall be declared using the following syntax:
- - `break [DEPTH]?;`
- Where [DEPTH] is a positive nonzero integer indicating the number of nested scopes to break out of.
- If [DEPTH] is omitted, it is implicitly `1`.
- The `break` keyword may only be used within `for` or `while` loops.
- 03 Case
- A `case` statement shall be declared using the following syntax:
- - `case ([TEST]) [STATEMENT]`
- Where [TEST] is either a literal corresponding to the `switch` argument type, or an expression (`cond`)
- And [STATEMENT] is the statement the control flow will jump to.
- The `case` keyword may only be used within `switch` or `cond` statements.
- 04 Cond
- A `cond` statement shall be declared using the following syntax:
- - `cond { [CASES] }`
- Where [CASES] are a number of `case` statements whose expressions are evaluated in order until one is
- true (nonzero), at which point control flow jumps to it.
- Effectively, `cond` statements are equivalent to `else if` chains with syntactic sugar on top.
- 05 Continue
- A `continue` statement shall be declared using the following syntax:
- - `continue [DEPTH]?;`
- Where [DEPTH] is a positive nonzero integer indicating the number of nested loops to jump out of prior
- to `continue`ing. If [DEPTH] is omitted, it is implicitly `1`.
- 06 Default
- A `default` statement shall be declared using the following syntax:
- - `default [STATEMENT]`
- Where [STATEMENT] is the statement the control flow will jump to if all other `switch` or `cond`
- `case`s fail.
- The `default` keyword may only be used within `switch` or `cond` statements.
- 07 Defer
- A `defer` statement shall be declared using the following syntax:
- - `defer [STATEMENT]`
- Where [STATEMENT] is the statement to be deferred to the end of the current scope. If multiple `defer`
- statements are used, they are pushed to a stack which will execute in reverse insertion order.
- It is possible to nest `defer` statements, which will push to the `defer` stack when reaching end of
- scope, although since the stack is emptied before exiting, this effectively "depriorizes" redeferred
- statements.
- 08 Do
- A `do` statement shall be declared using the following syntax:
- - `do [STATEMENT] while ([CONDITION]);`
- Where [STATEMENT] is the statement to be executed then repeated while the expression [CONDITION] is
- true (nonzero).
- The `do` keyword may only be used in conjunction with the `while` keyword. This is called a "do-while loop".
- 09 Else
- An `else` statement shall be declared using the following syntax:
- - `[FALLIBLE STATEMENT] else [FALSE STATEMENT]`
- Where [FALSE STATEMENT] is the statement the control flow will jump to if [FALLIBLE STATEMENT] fails
- And [FALLIBLE STATEMENT] is one of:
- - A `for` statement; will fail if the loop fails to run at least once.
- - A `while` statement; will fail if the loop fails to run at least once.
- - An `if` statement; will fail if the condition is false (zero).
- The `else` keyword may only be used in conjunction with a fallible statement.
- 10 Fallthrough
- A `fallthrough` statement shall be declared using the following syntax:
- - `fallthrough;`
- A `fallthrough` statement causes control flow to jump to the next `case` statement.
- The `fallthrough` keyword may only be used within a `switch` or `cond` statement.
- 11 For
- A `for` statement shall be declared using the following syntax:
- - `for ([BEFORE EXPR]; [WHILE EXPR]; [AFTER EXPR]) [STATEMENT]`
- Where [BEFORE EXPR] is either an expression to be evaluated before looping, or a single variable
- declaration (see PART 08, SECTION 01) local to [WHILE EXPR], [AFTER EXPR] and [STATEMENT]
- And [WHILE EXPR] is an expression to be evaluated each loop, breaking the loop if false (zero)
- And [STATEMENT] is the statement the control flow will jump to if [WHILE EXPR] is true (nonzero).
- 12 Goto
- A `goto` statement shall be declared using the following syntax:
- - `goto [LABEL];`
- Where [LABEL] is a label in the current function body.
- A label shall be declared using the following syntax:
- - `#label [IDENTIFIER];`
- Where [IDENTIFIER] is a name unique to this strand's namespace.
- Control flow will jump to the specified label.
- 13 If
- An `if` statement shall be declared using the following syntax:
- - `if ([CONDITION]) [STATEMENT]`
- Where [STATEMENT] is the statement to be executed if the expression [CONDITION] is true (nonzero).
- 14 Return
- A `return` statement shall be declared using the following syntax:
- - `return [EXPRESSION]?`
- Where [EXPRESSION] is an expression whose value is the return value of the current function. It may be
- omitted only if the function type is `void`.
- 15 Switch
- A `switch` statement shall be declared using the following syntax:
- - `switch ([EXPRESSION]) { [CASES] }`
- Where [EXPRESSION] is an expression whose value must be an integral value (of families `u`, `n` or `i`)
- And [CASES] are a number of `case` statements whose expressions are compared against this value until
- one is true (nonzero), at which point control flow jumps to it.
- The LAC `switch` statement uses similar semantics to C's `switch` statement.
- 16 While
- A `while` statement shall be declared using the following syntax:
- - `while ([CONDITION]) [STATEMENT]`
- Where [STATEMENT] is the statement to be repeatedly executed while the expression [CONDITION] is true.
- PART 08 - Variables
- 00 Variable prototypes
- LAC variable prototypes are a kind of toplevel lace statement used to link with a public global variable.
- They follow the same syntax as a variable declaration (see PART 08, SECTION 01) without initialization (see
- PART 08, SECTION 02). In essence, they are defined in every scope which can reference them, as if the scope
- declared them with their prototypes.
- 01 Variable declaration
- LAC variables shall be declared using the following syntax:
- - `[TYPE] [IDENTIFIER] {= [INITIALIZER]}?;`
- Where [TYPE] is a LAC compound type (see PART 04, SECTION 03), where each component can be affected by
- type specifiers or type qualifiers (see below)
- And [IDENTIFIER] is a name unique to this strand's namespace
- And [INITIALIZER] is a LAC initializer (see PART 08, SECTION 02).
- Type specifiers are special keywords controlling certain aspects of a variable's representation in memory.
- They do not affect the type itself, but rather how it is expressed at the hardware level.
- The following type specifiers shall be defined by the LAC standard:
- - `align([ALIGNMENT])` Specify a memory alignment, in bytes, for this type (must be a power of two).
- - `atomic` Enable atomic operations on the variable (may change size).
- - `remanent` Reserve remanent (static) storage for this variable. Cannot apply to globals.
- - `threadlocal` Use thread-local storage for the variable (must be global or remanent).
- Type qualifiers are special keywords controlling how a variable is perceived, or accessed, by the program.
- They modify the type itself, and as such a `const u8` is not the same type as a `u8`.
- The following type qualifiers shall be defined by the LAC standard:
- - `const` Enforce read-only actions on this variable.
- - `restrict` Guarantee variable as being a unique pointer (cannot apply to non-pointers).
- - `volatile` Indicate that variable value can change at any time and must not be optimized.
- 02 Variable initialization
- Array or non-primitive variables may be assigned to using a LAC initializer, which shall provide a simple
- and curt syntax to assign to many different fields at once. Incomplete initializers shall implicitly use
- zero for unspecified values.
- Initializers shall be declared using the following syntax:
- - ` = { [DEREFERENCED TYPE INITIALIZER LIST] };`
- Where [DEREFERENCED TYPE INITIALIZER LIST] is a comma-separated list of initializers corresponding to
- the type of the variable once dereferenced. These may be either aggregate or designated initializers, but
- never both in the same initializer scope.
- Note: initializers may be themselves be further [DEREFERENCED TYPE INITIALIZER LIST]s.
- Aggregate initializers shall be declared using the following syntax:
- - `[DEREFERENCED TYPE VALUE]`
- Where [DEREFERENCED TYPE VALUE] is a constant value matching the dereferenced type.
- Aggregate initializers assign values in ascending order for arrays, and in declaration order for
- user-defined types.
- Designated initializers shall be declared using the following syntax:
- - `[DEREFERENCING OPERATOR] = [DEREFERENCED TYPE VALUE]`
- Where [DEREFERENCING OPERATOR] is a token sequence to be tacked on to the type to yield its
- dereferenced type.
- For example:
- - `[16]u64 arr;` -> `arr = { [0] = 1, [1] = 2, [2] = 4, [3] = 8, [4] = 16 };`
- - `[2][2]i32 arr;` -> `arr = { {[0] = 1, [1] = 2}, {[0] = 3, [1] = 4} };
- - `[2]timespan ts;` -> `ts = { {.s = 5, .ns = 0}, {.s = 0, .ns = 1_000_000 };`
- Note: `union` initializers may only assign to one member.
- PART 09 - The LAC standard library
- PART 10 - Naming conventions
- 00 Files
- Strand handles live in a common flat namespace, which may incur collisions. As such, it is recommended to
- prefix file names with an identifier unique to the project (i.e. `libstd_string.lacs`), and provide one
- grab-bag lace (e.g. `std.lace`) which `import`s and `unpack`s all provided functionality.
- 01 Types
- User-defined types are by convention in PascalCase (similar to Java's class naming convention), while library
- and standard types should be in curt lowercase (e.g. `std.mutex`).
- 02 Functions
- In the spirit of C, function names should be simple and explicit, preferring lowercase when possible. In
- cases where clear separation is required, snake_case should be used.
- If the function is internal, it should be prefixed with the underscore (`_`) character.
- 03 Local variables
- In the spirit of C, variable names should be simple and explicit, preferring lowercase when possible. In
- cases where clear separation is required, camelCase should be used.
- 04 Global variables
- To avoid confusion, global variables should be suffixed with the underscore (`_`) character, and otherwise
- follow the same conventions as local variables.
- When used as constants, or rarely-changing values, they should instead be written in MACRO_CASE, still with
- the trailing underscore (e.g. `GAME_FPS_`, `MAX_STRBUF_SZ_`).
- 05 LPP expressions and utilities
- Code used exclusively by the LPP, such as helper functions evaluated at transpile-time, should be prefixed
- with `LPP_` (e.g. `LPP_calculate_boundingbox`).
- If used, C macros and definitions follow the standard C MACRO_CASE rules.
- PART 11 - The LAC transpiler (LACT)
- [TODO]
Advertisement
Add Comment
Please, Sign In to add comment