Architecture
The initial concept when designing U was to create a compiler so straightforward that it could potentially be implemented in silicon and hardware (FPGA). With this requirement in mind, we continually ensure that the design remains simple and efficient.
Lexer¶
The U grammar is designed with the following principles:
- Implemented with a specific parser generator: This ensures that no errors are introduced and that the parser is easily understandable and maintainable.
- Valid (sound): The grammar is so simple that we can verify all inpel combinations at every state.
- Context-free
- Relies on only one inpel (input element) lookahead: This means that at any point in the compilation process, U only needs one inpel to determine your intent, highlighting the power of apertures.
Here is a snippet of the DSL that generate the parser:
:Append_alnum t {
=Read_append_while $t
;Alnum_end
}
Parser¶
When evaluating your program, U parser creates Values backward:
U lexer will match: Symbol('a'), Bind(':'), Identifier('f'), Identifier('x'), Comma, Identifier('y').
Then U parser will execute the following steps:
- create y, x
- create sequence (x,y)
- call f with sequence (x,y)
- bind the result of 'f(x,y)' to 'a'
Memory models¶
Memory management is one of the most challenging aspects of programming languages. It can either enhance your application's performance or cause it to crash, depending on its implementation. Automatic memory management alleviates the burden of manual memory allocation and deallocation. Several paradigms exist for automatic memory management:
- Immutability: functional programming languages like Ocaml,
- Borrow checker: Rust,
- Automatic counting reference: Swift
- Runtime VM: Java, Erlang, Go,
- Garbage collectors: Java, Ocaml, Erlang, ...
It's predictable that memory chips will continue to evolve. With the mainstream adoption of hierarchical memory structures, there are increasingly more levels between the slowest and fastest memory technologies, spanning from CPU cache to hard drives. This creates a continuum of memory types characterized by varying technologies and physical locations.
These advancements have significantly influenced programming languages and their memory models. To ensure future-proofing, the U memory model is not hardcoded into the core language but implemented as a user-defined function. This approach enables developers to choose their preferred allocator (such as malloc, jemalloc, tcmalloc) and implement the best strategies for creating and freeing values. This flexibility allows for efficient adaptation to evolving memory technologies and programming needs.