Guest User

Untitled

a guest
Jun 6th, 2026
224
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 35.36 KB | None | 0 0
  1. The official LAC language standard.
  2. Last edited: 2026-06-04.
  3.  
  4. PART 00 - Metadocumentation
  5. 00 Introduction
  6. The present document, which defines the LAC programming language, shall be organized into three levels of
  7. subdivision: PARTs, SECTIONs and CLAUSEs, following a common structure.
  8.  
  9. Current PARTs include:
  10. 00 - Metadocumentation
  11. 01 - Rationale
  12. 02 - Program structure
  13. 03 - The LAC preprocessor (LPP)
  14. 04 - Types
  15. 05 - Expressions
  16. 06 - Functions
  17. 07 - Statements
  18. 08 - Variables
  19. 09 - The LAC standard library
  20. 10 - Naming conventions
  21. 11 - The LAC transpiler (LACT)
  22.  
  23. 01 Format rules
  24. Text between backticks (\`), except when escaped or matching any of the following rules, shall refer
  25. literally to LAC tokens or identifiers, or substrings thereof.
  26.  
  27. Text inside braces (\{\}), except when escaped, shall define a semantic block.
  28. Text inside brackets (\[\]), except when escaped, shall hold a placeholder and define a semantic block.
  29.  
  30. Semantic blocks followed by a question mark (\?) shall declare it optional (may be present once).
  31.  
  32. 02 Keyword table
  33. The following table shall associate all LAC keywords with their respective section within the standard.
  34.  
  35. KEYWORD RELEVANT SECTIONS KIND
  36. ==========================================================================================================
  37. align (PART 04, SECTION 02) and (PART 08, SECTION 01) Type specifier
  38. alignof (PART 05, SECTION 00) Constant operator
  39. atomic (PART 08, SECTION 01) Type specifier
  40. break (PART 07, SECTION 02) Control flow
  41. case (PART 07, SECTION 03) Control flow
  42. cond (PART 07, SECTION 04) Control flow
  43. const (PART 08, SECTION 01) Type qualifier
  44. continue (PART 07, SECTION 05) Control flow
  45. countof (PART 05, SECTION 00) Constant operator
  46. default (PART 07, SECTION 06) Control flow
  47. defer (PART 07, SECTION 07) Control flow
  48. do (PART 07, SECTION 08) Control flow
  49. else (PART 07, SECTION 09) Control flow
  50. enum (PART 04, SECTION 02) Type declarator
  51. fallthrough (PART 07, SECTION 10) Control flow
  52. fn (PART 06, SECTION 01) Function type
  53. for (PART 07, SECTION 11) Control flow
  54. goto (PART 07, SECTION 12) Control flow
  55. if (PART 07, SECTION 13) Control flow
  56. null (PART 04, SECTION 00) Constant value
  57. offsetof (PART 05, SECTION 00) Constant operator
  58. parcel (PART 04, SECTION 02) Type declarator
  59. remanent (PART 08, SECTION 01) Type specifier
  60. restrict (PART 08, SECTION 01) Type qualifier
  61. return (PART 07, SECTION 14) Control flow
  62. sizeof (PART 05, SECTION 00) Constant operator
  63. struct (PART 04, SECTION 02) Type declarator
  64. switch (PART 07, SECTION 15) Control flow
  65. threadlocal (PART 08, SECTION 01) Type specifier
  66. union (PART 04, SECTION 02) Type declarator
  67. volatile (PART 08, SECTION 01) Type qualifier
  68. while (PART 07, SECTION 16) Control flow
  69.  
  70. [OPERATORS] (PART 05, SECTION 00) Expression
  71. [TYPES] (PART 04) Type qualifier
  72.  
  73. as (Subdirective; see others) LPP directive
  74. #assert (PART 03, SECTION 04) LPP directive
  75. #c (PART 03, SECTION 02) LPP directive
  76. #error (PART 03, SECTION 04) LPP directive
  77. #eval (PART 03, SECTION 03) Expression
  78. #gen (PART 03, SECTION 05) LPP directive
  79. #import (PART 03, SECTION 01) LPP directive
  80. #label (PART 07, SECTION 12) LPP directive
  81. #unpack (PART 03, SECTION 01) LPP directive
  82.  
  83. PART 01 - Rationale
  84. 00 Goal
  85. The goal of the LAC programming language is to provide an ergonomic, more elegant alternative to the C
  86. programming language, which is shackled by its backwards-compatibility requirements, without meaning to
  87. replace it outright.
  88.  
  89. 01 Philosophy
  90. In essence, LAC serves as a translation layer between the user and C: it aims to reduce undefined or
  91. implementation-defined behavior while providing a cleaner standard library, without foregoing C's extensive
  92. tooling suites. As such, all C code produced by the LAC transpiler (LACT) should be human-readable and
  93. easily correlated with LAC source code while debugging or profiling.
  94.  
  95. 02 Limits
  96. The LAC programming language does not aspire to be widely adopted or to become a new standard. Its primary
  97. goal is to serve as main language for me (lzg), and as such may change (breaking backwards-compatibility) if
  98. it is deemed important enough.
  99.  
  100. PART 02 - Program structure
  101. 00 Overview
  102. A LAC program is comprised of one or more translation strands (TS), which are pairs of LAC source files
  103. (.lacs) and LAC external files (.lace).
  104.  
  105. LAC source and external files shall only allow ASCII characters (0-127), except inside string or character
  106. literals (see PART 05, SECTION 02).
  107.  
  108. Furthermore, identifiers shall only be composed of alphanumeric characters (a-z, A-Z, 0-9) in addition to
  109. the underscore (`_`) and at ('@') characters, and may not begin with a digit (0-9).
  110.  
  111. Note: if an identifier begins with a double underscore (`__`), it is reserved.
  112.  
  113. 01 .lace files
  114. The role of the lace is to provide external linkage with other strands, not unlike C's header files.
  115.  
  116. As such, the lace may choose to expose to other strands:
  117. - LPP linking directives (see PART 03, SECTION 01)
  118. - Public type declarations (see PART 04, SECTION 02)
  119. - Public global variable prototypes (see PART 08, SECTION 00)
  120. - Public function prototypes (see PART 06, SECTION 00)
  121. Note: while not enforced, it is recommended to follow the above order when writing lace files.
  122.  
  123. 02 .lacs files
  124. The role of the LAC source file is to provide both lace directives (which will be private to this strand),
  125. and implementation/initialization for the declared functions/variables.
  126.  
  127. A LAC source file may contain the following toplevel statements:
  128. - LPP directives (see PART 03)
  129. - Public global variable declarations (see PART 08, SECTION 01)
  130. - Private type declarations (see PART 04, SECTION 02)
  131. - Private global variable declarations (see PART 08, SECTION 01)
  132. - Public function declarations (see PART 06, SECTION 01)
  133. - Private function declarations (see PART 06, SECTION 01)
  134. Note: while not enforced, it is recommended to follow the above order when writing source files.
  135.  
  136. Global variable declarations not initialized using the assignment operator are cleared (set to zero).
  137. Unlike C, private ("helper") functions do not require a prototype before declaration.
  138.  
  139. 03 Strand scoping
  140. Linking with another strand (see PART 03, SECTION 01) brings its strand descriptor (SD) in scope.
  141. An SD represents the other strand's lace, and may be accessed as if a `struct` (using the `.` operator).
  142.  
  143. SDs may contain other SDs, in which case chained access (still using the `.` operator) is required, except
  144. if the lace `unpack`s the nested SDs.
  145.  
  146. 04 Program entry point
  147. As in C, a program's entry point is a function named `main`, which can have the following types:
  148. - i32(void)
  149. - i32(u64, **u8)
  150.  
  151. The number of arguments is passed in the `u64` while the arguments themselves are passed as null-terminated
  152. strings in an array of the given size.
  153.  
  154. The return value is an `i32` to conform to C-style program execution expectations.
  155.  
  156. PART 03 - The LAC preprocessor (LPP)
  157. 00 LPP overview
  158. Unlike the C preprocessor (CPP), which uses special syntax to provide metaprogramming capabilities (through
  159. textual replacement), the LPP offers only a few essential directives and lets the programmer use the LAC
  160. language itself to preprocess code.
  161.  
  162. As in C, the LPP is invoked using the hash (`#`) character, though this is only a convention, as any
  163. identifier may include it, although frivolous usage of special characters is discouraged.
  164.  
  165. 01 Linking
  166. The LPP directives `import`, `as` and `unpack` shall provide facilities for one strand to interface with
  167. others through their lace (see PART 02, SECTION 03).
  168.  
  169. To access external functionality, the LPP shall provide the `import` directive, which brings a strand
  170. descriptor into scope, optionally aliasing it when using the `as` keyword.
  171.  
  172. The linking syntax shall be of the form:
  173. - `#import [STRAND REFERENCE] {as [ALIAS]}?;`
  174.  
  175. Where [STRAND REFERENCE] is a string literal corresponding to the lace file name.
  176. The LACT shall search for the given lace in the following directories, in the given order:
  177. - /usr/lace/
  178. - /usr/local/lace/
  179. - ./
  180. - Importation paths as specified to the LACT (see PART 11, section [TODO])
  181.  
  182. And [ALIAS] is an alternate handle for referencing the same SD.
  183.  
  184. To avoid unnecessary verbosity when accessing strand descriptors, the LPP shall provide the `unpack`
  185. directive to bring strand descriptors' contents to toplevel. The full SD path can still be used.
  186.  
  187. The unpacking syntax shall be of the form:
  188. - `#unpack [STRAND COMPONENT LIST]`
  189.  
  190. Where [STRAND COMPONENT LIST] is a comma-separated list of declarations or SD handles to be
  191. brought to toplevel. For a complete list of SD declarations, see PART 02, SECTION 01.
  192.  
  193. 02 C interoperability
  194. The LPP shall provide facilities to interact with the C language through the use of the `#c` directive,
  195. which shall use the following syntax:
  196. - `#c([C TOKENS]);`
  197.  
  198. Where [C TOKENS] is literal C code to be inserted in place of the `#c` directive. The CPP may also be
  199. accessed using this directive.
  200.  
  201. For example:
  202. - `#c(#define _POSIX_C_SOURCE 200809L);`
  203. - `#c(#ifndef _WIN32);` ... `#c(#endif);`
  204. - `#c(#include "string.h");` ... `#c(strdup)(lacString);`
  205.  
  206. C errors are not detected by the LACT and may depend on the underlying C compiler (especially when
  207. using external C libraries). The LACT shall print CC output on compilation failure.
  208.  
  209. Interacting with LAC from C is also possible, as all lact functions and global variables are `.o` symbol
  210. references. Their handles are formed by concatening together the LAC prefix, the strand name and the symbol
  211. handle itself using the following syntax:
  212. - `[LAC PREFIX][STRAND]_[HANDLE]`
  213.  
  214. Where [LAC PREFIX] is `LaC__`
  215. And [STRAND] is the strand name without its extension
  216. And [HANDLE] is the symbol name.
  217.  
  218. For example, in file `prgmstate.lacs`:
  219. - `[256]u8 chrbuf;` -> `LaC__prgmstate_chrbuf`
  220. - `fn i32 isalnum(u8 char);` -> `LaC__prgmstate_isalnum`
  221.  
  222. 03 Translation-time code evaluation
  223. To facilitate integration of non-trivial but constant computation in programs, the LPP shall provide the
  224. `#eval` directive, using the following syntax:
  225. - `#eval([EXPRESSION])`
  226.  
  227. Where [EXPRESSION] is any LAC expression returning a scalar value.
  228.  
  229. The expression is executed in a virtual instance of the program, so pointers will be invalid and
  230. modified state is discarded.
  231.  
  232. Other side effects which modify external state, such as file modification, however, are retained,
  233. although using such tricks is not encouraged.
  234.  
  235. 04 Translation-time code verification
  236. The LPP shall provide facilities for translation-time code verification through the `#assert` and `#error`
  237. directives, which shall use the following syntax:
  238. - `#assert([EXPRESSION], [ERROR STRING]);`
  239. - `#error([ERROR STRING]);`
  240.  
  241. Where [EXPRESSION] is any expression, to be `#eval`uated at translation-time (see PART 03, SECTION 04)
  242. And [ERROR STRING] is a string literal (see PART 05, SECTION 02) to be printed on error or misassertion.
  243.  
  244. 05 Translation-time code generation
  245. The most versatile part of the LPP lies in its ability to generate and process arbitrary instructions prior
  246. to compilation, using the `#gen` directive, which shall use the following syntax:
  247. - `#gen([EXPRESSION])`
  248.  
  249. Where [EXPRESSION] is any expression which returns a null-terminated ASCII string (`*u8`).
  250.  
  251. In practice, the [EXPRESSION] is almost always a function returning the string to be literally inserted
  252. in the program. Because this function can read files, which includes program files, the `#gen` directive
  253. may be used to generate arbitrarily complex programs from within LAC.
  254.  
  255. PART 04 - Types
  256. 00 Primitive types
  257. LAC primitives shall be part of one of the following categories:
  258. - Floating-point numbers (f) (IEEE-754)
  259. - Unsigned integers (u)
  260. - Bitwise numbers (n)
  261. - Signed integers (i)
  262.  
  263. Primitives are named using the following syntax:
  264. - `[FAMILY][BITWIDTH]`
  265.  
  266. Where [FAMILY] is one of the previously-declared categories, and [BITWIDTH] is the type size in bits.
  267.  
  268. The LAC language shall define the following [FAMILY][BITWIDTH] pairs to refer to primitive types:
  269. - f16, f32, f64, f128
  270. - u8, u16, u32, u64, u128
  271. - n8, n16, n32, n64, n128
  272. - i8, i16, i32, i64, i128
  273. - void (decays to u8 when pointed to; otherwise is a placeholder)
  274.  
  275. Furthermore, the keyword `null` shall be defined as zero, which is a reserved value guaranteed not to point
  276. to accessible memory.
  277.  
  278. 01 Type casting
  279. To convert values between types, the LAC language shall make use of type-casting, which may change the
  280. bitwise representation of the number depending on the types being reassigned.
  281.  
  282. The unary cast operator shall be of the syntax:
  283. - `([TYPE]) [EXPR]`
  284.  
  285. Where [TYPE] is either a primitive or compound type
  286. And [EXPR] is a LAC expression (see PART 05)
  287.  
  288. The LAC language shall disallow the use of differing types within a single expression without an explicit
  289. cast (see PART 05, SECTION 00), except when casting to a bitwise type of equal or greater width.
  290.  
  291. Implicit cast of types with different specifiers (e.g. `u64` to `atomic u64`) is likewise disallowed.
  292. Implicit cast of types with different qualifiers (e.g. `u8` to `const u8`) is allowed when adding qualifiers.
  293. Implicit cast of arrays to pointers and vice-versa is allowed.
  294.  
  295. The following table shall list all type-casts which modify the bitwise representation of the number.
  296. All unspecified pairs shall not change this bitwise representation.
  297.  
  298. Casts to an equivalent or wider type
  299. - f <-> u IEEE-754 <-> unsigned binary number Truncates, snaps to nearest
  300. - f <-> i IEEE-754 <-> signed two's complement number Truncates, snaps to nearest
  301. - u <-> i unsigned binary number <-> signed two's complement number Sign-extends
  302.  
  303. Casts to a narrower type
  304. - f <-> u IEEE-754 <-> unsigned binary number Truncates, snaps to nearest
  305. - f <-> i IEEE-754 <-> signed two's complement number Truncates, snaps to nearest
  306. - u <-> i unsigned binary number <-> signed two's complement number Modulo capacity
  307.  
  308. 02 Type declaration
  309. The LAC language shall allow for the creation of user-defined types through the following keywords:
  310. - `struct` (Equivalent to C `struct`s)
  311. - `parcel` (Equivalent to packed `struct`s)
  312. - `union` (Equivalent to C unions)
  313. - `enum` (Can be used with any underlying types, provided constant initializers)
  314.  
  315. `struct`s, `parcel`s, `union`s and `enum`s shall be declared with the following syntax:
  316. - `struct [IDENTIFIER] align([ALIGNMENT])? { [MEMBER LIST] };`
  317. - `parcel [IDENTIFIER] align([ALIGNMENT])? { [MEMBER LIST] };`
  318. - `union [IDENTIFIER] align([ALIGNMENT])? { [MEMBER LIST] };`
  319. - `enum([ENUM TYPE]) align([ALIGNMENT])? [IDENTIFIER] { [VALUE LIST] };`
  320.  
  321. Where [ALIGNMENT] is a valid type alignment (see PART 08, SECTION 01)
  322. And [IDENTIFIER] is a name unique to this strand's namespace
  323. And [MEMBER LIST] is a semicolon-separated list of LAC variable prototypes (see PART 08, SECTION 00)
  324. And [ENUM TYPE] is the underlying enumeration type
  325. And [VALUE LIST] is a comma-separated list of constant [ENUM TYPE] variable initializers.
  326.  
  327. Once declared, the provided [IDENTIFIER] shall be used to refer to the type itself, and can be used where
  328. any LAC primitive would otherwise be.
  329.  
  330. As in C, the `.` operator shall be used to access `struct`, `parcel` and `union` members,
  331. and the `->` operator shall be used to dereference and access these types.
  332.  
  333. Unlike C, `enum` values cannot be reference without specifying the `enum` identifier followed by a `.` first.
  334.  
  335. 03 Compound types
  336. Types may be combined to form more precise compound types, which mix and match function prototypes, array
  337. syntax and pointer notation.
  338.  
  339. LAC compound types act as a single, cohesive unit; they may accept type modifiers (see [TODO])
  340. and be used where primitive types would be.
  341.  
  342. Furthermore, unlike C, LAC compound types are spatially contiguous; that is, any compound type is
  343. representable by a single, unbroken string.
  344.  
  345. Compound types end with a type, preceded by an agglomeration of the following components:
  346. - `*`
  347. - `\[[ARRAY LENGTH]\]`
  348. - `fn [FUNCTION RETURN TYPE]([FUNCTION PARAMETER LIST])`
  349.  
  350. Where [ARRAY LENGTH] is a constant positive integer
  351. And [FUNCTION PARAMETER LIST] is a comma-separated list of function parameters (see PART 06, SECTION 02)
  352.  
  353. Parameter lists take in everything preceding them as a return type, while other components compound in
  354. the same order they are accessed with (see PART 05, SECTION 00).
  355.  
  356. For example:
  357. - `*i32` -> pointer to an `i32`
  358. - `[3]f32` -> array of 3 `f32`
  359. - `*[16][2]u64` -> pointer to an array of 16 array of 2 u64
  360. - `*fn void(*u8, *u64)` -> pointer to function returning void taking (pointer to u8, pointer to u64)
  361.  
  362. PART 05 - Expressions
  363. 00 Operators
  364. The following (exhaustive) table shall list all LAC operators from highest to lowest precedence:
  365.  
  366. PRECEDENCE 0
  367. - `++`, `--`
  368. Suffix increment/decrement.
  369.  
  370. - `()`
  371. Function call.
  372.  
  373. Builtin function-like keywords also benefit from function call syntax, such as:
  374. - `alignof()` Query alignment in bytes of argument.
  375. - `countof()` Query member count of argument (array).
  376. - `offsetof()` Query offset in bytes of argument (struct member).
  377. - `sizeof()` Query size in bytes of argument.
  378.  
  379. - `[]`, `*`
  380. Array access/dereference.
  381.  
  382. - `.`, `->`
  383. `struct`, `parcel`, `union` or `enum` access.
  384.  
  385. PRECEDENCE 1
  386. - `++`, `--`
  387. Prefix increment/decrement.
  388.  
  389. - `-`
  390. Unary minus (two's complement conversion).
  391.  
  392. - `!`, `~`
  393. Logical/bitwise NOT.
  394.  
  395. - `([TYPE])`
  396. Type cast (see PART 04, SECTION 01).
  397.  
  398. - `&`
  399. Address reference.
  400.  
  401. PRECEDENCE 2
  402. - `*`, `/`, `%`
  403. Multiplication, division, remainder.
  404.  
  405. - `<<`, `>>`
  406. Bitwise left and right shift.
  407.  
  408. Note: right shift is arithmetic when operating on signed types.
  409.  
  410. PRECEDENCE 3
  411. - `+`, `-`
  412. Addition, subtraction.
  413.  
  414. Note: pointer/array arithmetic implicitly multiplies by type size (in bytes).
  415. For example, if `u64 p*;`, then `p++;` will add 8 (bytes) to p.
  416.  
  417. PRECEDENCE 4
  418. - `<`, `<=`, `>`, `>=`
  419. Relational smaller-than/greater-than operators.
  420.  
  421. PRECEDENCE 5
  422. - `==`, `!=`
  423. Relational equality operators.
  424.  
  425. PRECEDENCE 6
  426. - `&`
  427. Bitwise AND.
  428.  
  429. PRECEDENCE 7
  430. - `^`
  431. Bitwise XOR.
  432.  
  433. PRECEDENCE 8
  434. - `|`
  435. Bitwise OR.
  436.  
  437. PRECEDENCE 9
  438. - `&&`
  439. Logical AND (short-circuiting).
  440.  
  441. PRECEDENCE 10
  442. - `||`
  443. Logical OR (short-circuiting).
  444.  
  445. PRECEDENCE 11
  446. - `[COND]?[TRUE]:[FALSE]`
  447. Ternary operator.
  448.  
  449. PRECEDENCE 12
  450. - `=` Simple assignment (rvalue is after assignment).
  451. - `+=, `-=`, `*=`, `/=`, `%=`, `<<= `>>=`, `&=`, `^=`, `|=`, '~=`, Combined simple assignment.
  452.  
  453. PRECEDENCE 13
  454. - `,`
  455. Comma operator.
  456.  
  457. An expression within parentheses is parsed with precedence level 0, although parentheses are not themselves
  458. expressions; an empty standalone `()` is illegal.
  459.  
  460. 01 Expression syntax
  461. A LAC expression shall be one of the following:
  462. - A literal (see PART 05, SECTION 02).
  463. - A global or local variable.
  464. - An operator acting on one or more LAC expressions (see PART 05, SECTION 00).
  465.  
  466. Only LAC expressions which yield an lvalue (that is, an address in memory) can be assigned to, but all LAC
  467. expressions can be assigned from.
  468.  
  469. For example, consider:
  470. - `[16]u64 arr;` Array declaration (see PART 08, SECTION 01).
  471. - `arr[4] = 64;` Legal; `arr[4]` is shorthand for `(arr+4)`, which has a memory address.
  472. - `arr[1]++ = 12` Illegal; `arr[1]++` is of type `u64`, not `*u64` and cannot be assigned to.
  473.  
  474. 02 Literals
  475. LAC literals may be either number literals, character literals or string literals. To explicitate memory
  476. usage, there are no compound literals for user-defined types or arrays, and these must be initialized
  477. (preferably with `remanent` storage) beforehand.
  478.  
  479. Number literals are declared using the following syntax:
  480. - `[BASE]?[NUMBER]{.[FRACTIONAL PART]}?[PRIMITIVE TYPE]`
  481.  
  482. Where [BASE] is one of the following:
  483. - `[NONE]` Decimal.
  484. - `0b` Binary.
  485. - `0o` Octal.
  486. - `0x` Hexadecimal.
  487.  
  488. And both [NUMBER] and [FRACTIONAL PART] are sequences of digits in their respective bases
  489. And [PRIMITIVE TYPE] is one of the types outlined in PART 04, SECTION 00.
  490.  
  491. Note: hexadecimal digits must be uppercase (A-F).
  492. Note: underscores (`_`) are ignored within number literals.
  493.  
  494. Character literals shall be declared using the following syntax:
  495. - `'[CHAR]'`
  496.  
  497. Where [CHAR] is a possibly escaped character mapping to one or more byte. In effect, a character literal
  498. acts as if a number literal with the same value.
  499.  
  500. The following list shall map all character escape sequences to their actual value:
  501. - `\[OCT]` Character with octal value [OCT].
  502. - `\x[HX]` Character with hex value [HX].
  503. - `\a` 0x07; Alert (BEL) character.
  504. - `\b` 0x08; Backspace (BS) character.
  505. - `\e` 0x1B; Escape (ESC) character.
  506. - `\n` 0x0A; Newline (LF) character.
  507. - `\r` 0x0D; Carriage return (CR) character.
  508. - `\t` 0x09; Horizontal tab (HT) character.
  509. - `\v` 0x0B; Vertical tab (VT) character.
  510. - `\\` 0x5C; Backslash (\\) character.
  511. - `\'` 0x27; Apostrophe (') character.
  512. - `\"` 0x22; Double-quotes (") character.
  513. - `\U+[UNI]` Unicode codepoint with hex value [UNI] (4 to 6 digits).
  514.  
  515. String literals shall be declared using the following syntax:
  516. - `"[STRING]"`
  517.  
  518. Where [STRING] is a sequence character literals, without the apostrophes (`'`).
  519. Strings literals are implicitly null-terminated, and cannot be modified (as if `const`).
  520.  
  521. PART 06 - Functions
  522. 00 Function prototypes
  523. LAC function prototypes are a kind of toplevel lace statement used to link with a public function.
  524.  
  525. They follow the same syntax as a function declaration (see PART 06, SECTION 01), but without a body.
  526. Prototype parameters must be named and match the declaration signature (see PART 06, SECTION 02).
  527.  
  528. 01 Function declaration
  529. LAC functions shall be declared using the following syntax:
  530. - `fn [RETURN TYPE] [IDENTIFIER][PARAMETER LIST] \{ [BODY] \}`
  531.  
  532. Where [RETURN TYPE] is the function return type
  533. And [IDENTIFIER] is a name unique to this stand's namespace
  534. And [PARAMETER LIST] is the function parameter list (see PART 06, SECTION 02)
  535. And [BODY] is the function body (see below).
  536.  
  537. Function bodies shall group statements (see PART 07) to be executed in control flow order, terminating
  538. when reaching a `return` statement (see PART 07, SECTION 14) or end of scope. Only functions with
  539. return type `void` may omit `return` this way.
  540.  
  541. Functions may be declared within functions; this has the effect of restricting the inner function's linkage
  542. to only the scope within which it was declared.
  543.  
  544. Identifiers prefixed with the dollar (`$`) character used inside nested functions refer to its outside scope
  545. and are implicitly passed as arguments.
  546.  
  547. 02 Function parameters
  548. Function calls, prototypes and declarations all interface through the parameter list, which identify the
  549. function to the outside world.
  550.  
  551. Parameter lists are comma-separated lists of function parameters, each of which must be named with an
  552. identifier unique to the function's namespace, and typed as if it were a local variable declaration. (see
  553. PART 08, SECTION 01). In effect, parameters are a special kind of local variable which are initialized with
  554. the callee's passed values on function call.
  555.  
  556. PART 07 - Statements
  557. 00 Scopes
  558. Statements are semicolon-terminated instructions affecting the program state whilst evaluating expressions
  559. (see PART 05). Some expressions, such as assignment, may themselves be statements.
  560.  
  561. Statements typically affect only the next statement (or expression); as such, it is common to create scopes
  562. to group code together. Scopes are declared by enclosing statements within curly braces (`\{` and `\}`).
  563. Stack-allocated memory is automatically free'd on scope exit.
  564.  
  565. 01 Expression statements
  566. LAC expression statements shall be one of the following:
  567. - Function calls
  568. - Assignment/modification operators
  569.  
  570. 02 Break
  571. A `break` statement shall be declared using the following syntax:
  572. - `break [DEPTH]?;`
  573.  
  574. Where [DEPTH] is a positive nonzero integer indicating the number of nested scopes to break out of.
  575. If [DEPTH] is omitted, it is implicitly `1`.
  576.  
  577. The `break` keyword may only be used within `for` or `while` loops.
  578.  
  579. 03 Case
  580. A `case` statement shall be declared using the following syntax:
  581. - `case ([TEST]) [STATEMENT]`
  582.  
  583. Where [TEST] is either a literal corresponding to the `switch` argument type, or an expression (`cond`)
  584. And [STATEMENT] is the statement the control flow will jump to.
  585.  
  586. The `case` keyword may only be used within `switch` or `cond` statements.
  587.  
  588. 04 Cond
  589. A `cond` statement shall be declared using the following syntax:
  590. - `cond { [CASES] }`
  591.  
  592. Where [CASES] are a number of `case` statements whose expressions are evaluated in order until one is
  593. true (nonzero), at which point control flow jumps to it.
  594.  
  595. Effectively, `cond` statements are equivalent to `else if` chains with syntactic sugar on top.
  596.  
  597. 05 Continue
  598. A `continue` statement shall be declared using the following syntax:
  599. - `continue [DEPTH]?;`
  600.  
  601. Where [DEPTH] is a positive nonzero integer indicating the number of nested loops to jump out of prior
  602. to `continue`ing. If [DEPTH] is omitted, it is implicitly `1`.
  603.  
  604. 06 Default
  605. A `default` statement shall be declared using the following syntax:
  606. - `default [STATEMENT]`
  607.  
  608. Where [STATEMENT] is the statement the control flow will jump to if all other `switch` or `cond`
  609. `case`s fail.
  610.  
  611. The `default` keyword may only be used within `switch` or `cond` statements.
  612.  
  613. 07 Defer
  614. A `defer` statement shall be declared using the following syntax:
  615. - `defer [STATEMENT]`
  616.  
  617. Where [STATEMENT] is the statement to be deferred to the end of the current scope. If multiple `defer`
  618. statements are used, they are pushed to a stack which will execute in reverse insertion order.
  619.  
  620. It is possible to nest `defer` statements, which will push to the `defer` stack when reaching end of
  621. scope, although since the stack is emptied before exiting, this effectively "depriorizes" redeferred
  622. statements.
  623.  
  624. 08 Do
  625. A `do` statement shall be declared using the following syntax:
  626. - `do [STATEMENT] while ([CONDITION]);`
  627.  
  628. Where [STATEMENT] is the statement to be executed then repeated while the expression [CONDITION] is
  629. true (nonzero).
  630.  
  631. The `do` keyword may only be used in conjunction with the `while` keyword. This is called a "do-while loop".
  632.  
  633. 09 Else
  634. An `else` statement shall be declared using the following syntax:
  635. - `[FALLIBLE STATEMENT] else [FALSE STATEMENT]`
  636.  
  637. Where [FALSE STATEMENT] is the statement the control flow will jump to if [FALLIBLE STATEMENT] fails
  638. And [FALLIBLE STATEMENT] is one of:
  639. - A `for` statement; will fail if the loop fails to run at least once.
  640. - A `while` statement; will fail if the loop fails to run at least once.
  641. - An `if` statement; will fail if the condition is false (zero).
  642.  
  643. The `else` keyword may only be used in conjunction with a fallible statement.
  644.  
  645. 10 Fallthrough
  646. A `fallthrough` statement shall be declared using the following syntax:
  647. - `fallthrough;`
  648.  
  649. A `fallthrough` statement causes control flow to jump to the next `case` statement.
  650.  
  651. The `fallthrough` keyword may only be used within a `switch` or `cond` statement.
  652.  
  653. 11 For
  654. A `for` statement shall be declared using the following syntax:
  655. - `for ([BEFORE EXPR]; [WHILE EXPR]; [AFTER EXPR]) [STATEMENT]`
  656.  
  657. Where [BEFORE EXPR] is either an expression to be evaluated before looping, or a single variable
  658. declaration (see PART 08, SECTION 01) local to [WHILE EXPR], [AFTER EXPR] and [STATEMENT]
  659.  
  660. And [WHILE EXPR] is an expression to be evaluated each loop, breaking the loop if false (zero)
  661. And [STATEMENT] is the statement the control flow will jump to if [WHILE EXPR] is true (nonzero).
  662.  
  663. 12 Goto
  664. A `goto` statement shall be declared using the following syntax:
  665. - `goto [LABEL];`
  666.  
  667. Where [LABEL] is a label in the current function body.
  668.  
  669. A label shall be declared using the following syntax:
  670. - `#label [IDENTIFIER];`
  671.  
  672. Where [IDENTIFIER] is a name unique to this strand's namespace.
  673.  
  674. Control flow will jump to the specified label.
  675.  
  676. 13 If
  677. An `if` statement shall be declared using the following syntax:
  678. - `if ([CONDITION]) [STATEMENT]`
  679.  
  680. Where [STATEMENT] is the statement to be executed if the expression [CONDITION] is true (nonzero).
  681.  
  682. 14 Return
  683. A `return` statement shall be declared using the following syntax:
  684. - `return [EXPRESSION]?`
  685.  
  686. Where [EXPRESSION] is an expression whose value is the return value of the current function. It may be
  687. omitted only if the function type is `void`.
  688.  
  689. 15 Switch
  690. A `switch` statement shall be declared using the following syntax:
  691. - `switch ([EXPRESSION]) { [CASES] }`
  692.  
  693. Where [EXPRESSION] is an expression whose value must be an integral value (of families `u`, `n` or `i`)
  694.  
  695. And [CASES] are a number of `case` statements whose expressions are compared against this value until
  696. one is true (nonzero), at which point control flow jumps to it.
  697.  
  698. The LAC `switch` statement uses similar semantics to C's `switch` statement.
  699.  
  700. 16 While
  701. A `while` statement shall be declared using the following syntax:
  702. - `while ([CONDITION]) [STATEMENT]`
  703.  
  704. Where [STATEMENT] is the statement to be repeatedly executed while the expression [CONDITION] is true.
  705.  
  706. PART 08 - Variables
  707. 00 Variable prototypes
  708. LAC variable prototypes are a kind of toplevel lace statement used to link with a public global variable.
  709.  
  710. They follow the same syntax as a variable declaration (see PART 08, SECTION 01) without initialization (see
  711. PART 08, SECTION 02). In essence, they are defined in every scope which can reference them, as if the scope
  712. declared them with their prototypes.
  713.  
  714. 01 Variable declaration
  715. LAC variables shall be declared using the following syntax:
  716. - `[TYPE] [IDENTIFIER] {= [INITIALIZER]}?;`
  717.  
  718. Where [TYPE] is a LAC compound type (see PART 04, SECTION 03), where each component can be affected by
  719. type specifiers or type qualifiers (see below)
  720.  
  721. And [IDENTIFIER] is a name unique to this strand's namespace
  722. And [INITIALIZER] is a LAC initializer (see PART 08, SECTION 02).
  723.  
  724. Type specifiers are special keywords controlling certain aspects of a variable's representation in memory.
  725. They do not affect the type itself, but rather how it is expressed at the hardware level.
  726.  
  727. The following type specifiers shall be defined by the LAC standard:
  728. - `align([ALIGNMENT])` Specify a memory alignment, in bytes, for this type (must be a power of two).
  729. - `atomic` Enable atomic operations on the variable (may change size).
  730. - `remanent` Reserve remanent (static) storage for this variable. Cannot apply to globals.
  731. - `threadlocal` Use thread-local storage for the variable (must be global or remanent).
  732.  
  733. Type qualifiers are special keywords controlling how a variable is perceived, or accessed, by the program.
  734. They modify the type itself, and as such a `const u8` is not the same type as a `u8`.
  735.  
  736. The following type qualifiers shall be defined by the LAC standard:
  737. - `const` Enforce read-only actions on this variable.
  738. - `restrict` Guarantee variable as being a unique pointer (cannot apply to non-pointers).
  739. - `volatile` Indicate that variable value can change at any time and must not be optimized.
  740.  
  741. 02 Variable initialization
  742. Array or non-primitive variables may be assigned to using a LAC initializer, which shall provide a simple
  743. and curt syntax to assign to many different fields at once. Incomplete initializers shall implicitly use
  744. zero for unspecified values.
  745.  
  746. Initializers shall be declared using the following syntax:
  747. - ` = { [DEREFERENCED TYPE INITIALIZER LIST] };`
  748.  
  749. Where [DEREFERENCED TYPE INITIALIZER LIST] is a comma-separated list of initializers corresponding to
  750. the type of the variable once dereferenced. These may be either aggregate or designated initializers, but
  751. never both in the same initializer scope.
  752.  
  753. Note: initializers may be themselves be further [DEREFERENCED TYPE INITIALIZER LIST]s.
  754.  
  755. Aggregate initializers shall be declared using the following syntax:
  756. - `[DEREFERENCED TYPE VALUE]`
  757.  
  758. Where [DEREFERENCED TYPE VALUE] is a constant value matching the dereferenced type.
  759.  
  760. Aggregate initializers assign values in ascending order for arrays, and in declaration order for
  761. user-defined types.
  762.  
  763. Designated initializers shall be declared using the following syntax:
  764. - `[DEREFERENCING OPERATOR] = [DEREFERENCED TYPE VALUE]`
  765.  
  766. Where [DEREFERENCING OPERATOR] is a token sequence to be tacked on to the type to yield its
  767. dereferenced type.
  768.  
  769. For example:
  770. - `[16]u64 arr;` -> `arr = { [0] = 1, [1] = 2, [2] = 4, [3] = 8, [4] = 16 };`
  771. - `[2][2]i32 arr;` -> `arr = { {[0] = 1, [1] = 2}, {[0] = 3, [1] = 4} };
  772. - `[2]timespan ts;` -> `ts = { {.s = 5, .ns = 0}, {.s = 0, .ns = 1_000_000 };`
  773.  
  774. Note: `union` initializers may only assign to one member.
  775.  
  776. PART 09 - The LAC standard library
  777.  
  778. PART 10 - Naming conventions
  779. 00 Files
  780. Strand handles live in a common flat namespace, which may incur collisions. As such, it is recommended to
  781. prefix file names with an identifier unique to the project (i.e. `libstd_string.lacs`), and provide one
  782. grab-bag lace (e.g. `std.lace`) which `import`s and `unpack`s all provided functionality.
  783.  
  784. 01 Types
  785. User-defined types are by convention in PascalCase (similar to Java's class naming convention), while library
  786. and standard types should be in curt lowercase (e.g. `std.mutex`).
  787.  
  788. 02 Functions
  789. In the spirit of C, function names should be simple and explicit, preferring lowercase when possible. In
  790. cases where clear separation is required, snake_case should be used.
  791.  
  792. If the function is internal, it should be prefixed with the underscore (`_`) character.
  793.  
  794. 03 Local variables
  795. In the spirit of C, variable names should be simple and explicit, preferring lowercase when possible. In
  796. cases where clear separation is required, camelCase should be used.
  797.  
  798. 04 Global variables
  799. To avoid confusion, global variables should be suffixed with the underscore (`_`) character, and otherwise
  800. follow the same conventions as local variables.
  801.  
  802. When used as constants, or rarely-changing values, they should instead be written in MACRO_CASE, still with
  803. the trailing underscore (e.g. `GAME_FPS_`, `MAX_STRBUF_SZ_`).
  804.  
  805. 05 LPP expressions and utilities
  806. Code used exclusively by the LPP, such as helper functions evaluated at transpile-time, should be prefixed
  807. with `LPP_` (e.g. `LPP_calculate_boundingbox`).
  808.  
  809. If used, C macros and definitions follow the standard C MACRO_CASE rules.
  810.  
  811. PART 11 - The LAC transpiler (LACT)
  812. [TODO]
Advertisement
Add Comment
Please, Sign In to add comment