HTLL is not an academic exercise; it is a practical tool for creating hyper-efficient software. Its simplicity translates directly to size and performance.
- A standard
Hello, World!program in HTLL compiles to a 440-byte x86-64 assembly (.s) file. When assembled, the final statically linked binary x86-64 file is only 255 bytes. - A more complex program, like a full Bubble Sort algorithm, produces a final statically linked executable x86-64 of just 1.1 kilobytes.
This is the result of rejecting unnecessary layers of abstraction.
- Rules
- The 'Types Are a Lie' Doctrine
- The
mainEntry Point: Rules of Execution - Variables: 64-bit Integers
- Arrays: The Universal Byte Buffer
- Terminal I/O: Printing and Input
- Control Flow: Loops
- Control Flow: Conditionals
- Control Flow: Goto
- Functions: Scope, Parameters, and Variables
- The Array Parameter Solution: The Buffer Pattern
- File System Operations
- System Commands & Features
- Syntax Reference & Flexibility
- Comprehensive All-In-One Example
- HTLL Quirks & Gotchas: A Mandatory Review
- Integers (
int/nint):- 64-bit signed integers.
intandnintare functionally identical.- Global Scope Rule: All variables defined anywhere (except function params) are global and initialized only once.
- Arrays (
arr):- Universal dynamic byte buffers.
- Can hold ASCII text, integers, or raw data.
- NOT passable as function parameters.
- The
raxRegister:- This is the volatile "working memory" of the compiler.
- Behavior: It is overwritten by almost every operation (
.size,.index, math, etc.). - Rule: Use the value in
raximmediately or store it. Do not expect it to persist.
- Operator Spacing: You must put a space around every single binary operator.
- Correct:
int x := 0 - Incorrect:
int x:=0 - Correct:
x += 10 - Incorrect:
x+=10
- Correct:
- Control Flow Spacing: You must put a space between the keyword and the opening parenthesis/brace.
- Correct:
if (x = 1) { - Incorrect:
if(x=1){
- Correct:
- Unary Exception:
++and--are the only operators that stick to the variable.- Correct:
x++
- Correct:
- Comments: Require a preceding space if on the same line (e.g.,
code ; comment).
- Rule: Expressions do not exist. You cannot perform math and assignment in the same step unless it is a compound assignment.
- Illegal:
z := x + y - Illegal:
if (x + 1 > 5)
- Illegal:
- The "Line-by-Line" Workflow: To add two numbers into a third variable, you must do it in steps:
z := x z += y - Allowed Math Operations:
+=(Add to variable)-=(Subtract from variable)*=(Multiply variable)++(Increment)--(Decrement)
- Assignment:
:=
- The 9-Level Limit: You can only nest blocks (Loops/Ifs) up to 9 levels deep.
- This is a hard limit of the parser stack.
- Loops:
- Syntax:
Loop, <count> {orLoop, rax { - Termination:
} - Iterator:
A_Index(Always refers to the innermost active loop). continue: Skips the rest of the current iteration and jumps to the next.break: Immediately terminates the loop.
- Syntax:
- Conditionals:
- Syntax:
if (<operand1> <operator> <operand2>) { - Termination:
} - Operators:
=,!=,>,<,>=,<=(Spaces required!). - Logic: NO
else. NOand. NOor. You must usegotoor nestedifblocks to simulate this.
- Syntax:
- Jumps:
togo <label>: Defines a jump target.goto <label>: Unconditional jump.
arradd <arr> <text>:- Appends text to the array.
- NO QUOTES ALLOWED. (e.g.,
arradd mybuf Hello World). - TRIMS SPACES: Trailing spaces are automatically removed.
.add <value>: Appends a raw 64-bit value or an ASCII code (e.g.,.add 32for a space)..pop: Removes the last element from the array..clear: Resets the array size to 0..size: Calculates the size and puts it intorax..index <i_val>: Retrieves value at indexi_valand puts it intorax..set <idx>, <val>: Overwrites the value at a specific index..copy <src_arr>: Copies contents of source array to destination array.
- Definition:
func <name>(param1, param2) { - Termination:
} - Parameters: These are the ONLY local variables in the entire language. They are pushed to the stack.
- No Nesting: You cannot define a function inside another function.
- The Anti-Pattern: Do not define variables (
int x := 0) inside a function. They will be global and only initialize once. - The Buffer Pattern: Since you cannot pass arrays as parameters, you must agree on a global
arrto use as a shared data buffer between the caller and the function.
print(<value>): Prints integer value of a variable or register.print("text"): Prints a double-quoted string literal.print(""): Prints a newline (ASCII 10).print_rax_as_char: Interprets the value inraxas an ASCII code and prints the corresponding character.input <dest_arr>, <prompt_arr>: Displays the text inprompt_arr, then reads from standard input intodest_arr.
- Read:
fileread <dest_arr>, "file.txt"(Literal filename)fileread_arr <dest_arr>, <filename_arr>(Filename in an array)
- Append:
fileappend "file.txt", <source_arr>fileappend_arr <filename_arr>, <source_arr>
- Delete:
filedelete "file.txt"filedelete_arr <filename_arr>
mainLabel:- Mandatory if functions are used (must be placed after definitions).
- Optional if writing a simple top-down script.
args_array:- A special global array automatically populated at startup.
- Contains command-line arguments.
- Separator: Each argument is separated by a newline character (ASCII 10) inside the array.
Sleep, <ms>: Pauses execution via a kernel sleep syscall.
- No Booleans: True/False must be handled via integers (1/0).
- Manual ASCII: To add a space to a string builder, you must use
.add 32.arraddwill strip it. - Stack Management: The parser manages the stack for you, but you must respect the 9-level nesting limit.
- No Expressions: Never try to do math inside an
ifstatement or an assignment. One operation per line.
In low-level computing, distinct data types like "string" or "boolean" don't truly exist. There are only bytes of data. A "type" is simply how you decide to interpret those bytes. HTLL is built on this truth.
The arr type is a raw buffer of bytes. It can function as a "string" if you fill it with ASCII values and print them as characters. It can function as a list of "integers" if you fill it with numbers and perform arithmetic. You, the programmer, are in complete control of data representation.
Example 1: Dual-purpose buffer
arr buffer
arradd buffer Some text ; Use as a "string"
buffer.clear
buffer.add 1991 ; Now use as a list of numbersExample 2: Populating with character literals You can also build up text using single-quoted character literals.
arr greeting
greeting.add 'H'
greeting.add 'e'
greeting.add 'l'
greeting.add 'l'
greeting.add 'o'
; The array now holds the ASCII values [72, 101, 108, 108, 111]The main label tells the compiler where your program's execution begins. Its usage has specific rules:
- If you have no
funcdefinitions: Themainlabel is optional. The compiler will execute from the top of the file. You can still add it for clarity if you wish. - If you have
funcdefinitions: Themainlabel is mandatory. You must place it after all your global variable and function definitions to mark the start of execution.
HTLL supports 64-bit integers. Following the global scope rule, they should be defined at the top of your file for clarity.
Types: int and nint (functionally identical).
Syntax: No spaces are allowed between a variable name and the ++ or -- operators.
; --- Declaration and Initialization ---
int counter := 0
int value := 50
; --- Operations ---
value += 10 ; value is now 60
value -= 5 ; value is now 55
value *= 2 ; value is now 110
value++ ; value is now 111
value-- ; value is now 110
counter := value ; AssignmentArrays are the core data structure in HTLL. They are dynamically-sized buffers that hold 64-bit values.
Handling Spaces with arradd
The arradd command is designed for efficiency and trims any trailing spaces from its input. This means you cannot add a space at the end of a line with it. To add a space or other specific characters, you must use the .add method with the character's ASCII value. The value for a space is 32.
Example: Creating a spaced prompt
arr prompt
; Correct way to create "Name: "
arradd prompt Name:
prompt.add 32 ; This adds the trailing spaceprint(<value>): Prints the numeric value of a variable or number.print("text"): Prints a double-quoted string literal.print(""): This is the standard method for printing a newline character.print_rax_as_char: Interprets the numeric value inraxas an ASCII code and prints the corresponding character.input <dest_arr>, <prompt_arr>: Displays the text inprompt_arr, then reads from standard input intodest_arr.
Loops are zero-indexed and can be nested up to 9 levels.
Syntax: Loop, <count>
Example 1: Basic zero-indexed loop
; This will print 0, 1, 2, 3, 4
Loop, 5 {
print(A_Index)
}Example 2: Iterating over an array
arr data_arr
data_arr.add 11
data_arr.add 22
data_arr.add 33
data_arr.size ; Place size (3) into rax
Loop, rax {
data_arr.index A_Index
print(rax)
}Example 3: Nested Loops and A_Index
Loop, 2 { ; Outer loop from 0 to 1
print("Outer:")
print(A_Index) ; This A_Index belongs to the outer loop
Loop, 3 { ; Inner loop from 0 to 2
print(" Inner:")
print(A_Index) ; This A_Index belongs to the inner loop
}
}Conditional logic requires parentheses.
Operators: =, !=, >, <, >=, <=
Example 1: Simple check
int val := 10
if (val = 10) {
print("Value is 10.")
}Example 2: Simulating an else block
HTLL does not have an else keyword. You achieve this with goto.
int access_level := 5
if (access_level > 8) {
print("Admin access granted.")
goto end_check
}
print("Standard access.")
togo end_checkgoto provides raw control over the execution path by jumping to a defined label.
togo <label_name>: Defines a jump target.goto <label_name>: Jumps execution to the label.
Example: A goto-based loop
int counter := 0
togo loop_start
counter++
print(counter)
if (counter < 3) {
goto loop_start
}
print("Loop finished.")Function parameters are the only local variables in HTLL. They are pushed onto the stack when the function is called and exist only for the duration of that function's execution.
Shadowing: HTLL supports parameter shadowing. If you define a function parameter with the same name as a global variable, the compiler automatically isolates the parameter. Inside the function, that name refers to the local stack value. Outside, it refers to the global variable.
Example: Safe Shadowing
int x := 10 ; Global variable
func my_func(x) { ; This 'x' is a local parameter, shadowing the global 'x'
x += 5 ; This modifies the local 'x' on the stack (20 + 5)
print(x) ; Prints 25
}
main
my_func(20) ; We pass 20 to the function.
print(x) ; Prints 10. The global 'x' was never touched.Do not define variables inside functions (int i := 0). While the syntax is allowed, it does not behave as you might expect from other languages. Due to HTLL's global nature, the variable is created globally and initialized only once when the compiler first sees it. It will not be reset on subsequent function calls.
The Wrong Way (Bugged Logic):
func counter_broken() {
int i := 0 ; This line only truly runs once during compilation!
i++
print(i)
}
main
counter_broken() ; Prints 1
counter_broken() ; Prints 2, because 'i' was not reset to 0
counter_broken() ; Prints 3The Correct Way (Declare Globally, Reset Locally):
int i := 0 ; 1. Declare the variable in the global scope.
func counter_correct() {
i := 0 ; 2. Reset the variable to its starting value inside the function.
i++
print(i)
}
main
counter_correct() ; Prints 1
counter_correct() ; Prints 1
counter_correct() ; Prints 1CRITICAL RULE REVISITED: You cannot pass an array as a parameter to a function.
This is a core design choice. The correct way to have a function process array data is to use the "Global Buffer Pattern." You and the function agree on a global array to use as a shared workspace. The caller places data into the buffer, and the function reads from it.
Example: Correctly processing array data
arr my_data
arr shared_buffer ; This is the agreed-upon global buffer
; This function is designed to work ONLY with 'shared_buffer'
func process_data_in_buffer() {
print("Processing data...")
shared_buffer.size
Loop, rax {
shared_buffer.index A_Index
rax++ ; Increment the value
print(rax)
}
}
main
; 1. Load your primary data
my_data.add 100
my_data.add 200
; 2. Copy the data to the shared buffer before calling
shared_buffer.copy my_data
; 3. Call the function, which now operates on the buffer
process_data_in_buffer()HTLL provides direct syscalls for file I/O. For each operation, there are two versions: one that takes a double-quoted string literal for the filename, and a more flexible _arr version that takes an array containing the filename.
fileread <dest_arr>, "file.txt"/fileread_arr <dest_arr>, <filename_arr>fileappend "file.txt", <source_arr>/fileappend_arr <filename_arr>, <source_arr>filedelete "file.txt"/filedelete_arr <filename_arr>
Example: Reading, Writing, and Deleting a file
arr content_buffer
arr filename_buffer
main
arradd filename_buffer temp_file.txt
arradd content_buffer This is a test.
content_buffer.add 10 ; Add a newline
; Write the content to the file
print("Writing to file...")
fileappend_arr filename_buffer, content_buffer
; Clear the buffer and read the file back
content_buffer.clear
print("Reading from file...")
fileread_arr content_buffer, filename_buffer
; Print the contents
content_buffer.size
Loop, rax {
content_buffer.index A_Index
print_rax_as_char
}
; Clean up
print("Deleting file...")
filedelete_arr filename_bufferHTLL automatically populates the special global array args_array at startup with any command-line arguments you provide. Do not declare this array yourself.
Internally, HTLL loops through the arguments provided by the operating system, unpacks them, and appends them to the args_array one by one, adding a newline character (ASCII 10) after each argument to act as a separator.
Example: Displaying arguments
; To run from terminal: ./my_program arg1 "second arg" third
main
print("--- Arguments Received ---")
args_array.size
if (rax = 0) {
print("None.")
goto args_done
}
Loop, rax {
args_array.index A_Index
if (rax = 10) {
print("") ; A newline separates each argument
continue
}
print_rax_as_char
}
togo args_doneThe Sleep, <ms> command pauses execution via a kernel syscall for the specified number of milliseconds.
Example: Timed execution
print("Step 1")
Sleep, 1000 ; Pause for 1 second (1000 ms)
print("Step 2")This single program demonstrates the correct usage of globals, functions, the buffer pattern, I/O, loops, and conditionals to perform a series of tasks.
;#######################################################
;# HTLL All-In-One Demonstration
;#######################################################
; --- Global Data & Buffers ---
arr log_content_buffer ; Shared buffer for logging functions
arr filename_buffer ; Holds the filename for I/O operations
arr number_list ; Primary data array for sorting
arr user_input ; Buffer for stdin
arr prompt ; Buffer for user prompt text
int swapped := 0
int i := 0
int n := 0
int item1 := 0
int item2 := 0
; --- Function to sort the global 'number_list' via Bubble Sort ---
func sort_number_list() {
print("--- Sorting List ---")
togo sort_start_label
swapped := 0
number_list.size
n := rax
n-- ; Adjust for zero-based index
Loop, n {
i := A_Index
number_list.index i
item1 := rax
i++
number_list.index i
item2 := rax
if (item1 > item2) {
number_list.set A_Index, item2
number_list.set i, item1
swapped := 1
}
}
if (swapped = 1) {
goto sort_start_label
}
print("Sort complete.")
}
; --- Function to append the contents of 'log_content_buffer' to disk ---
func append_to_log() {
; This function uses the agreed-upon global buffers
fileappend_arr filename_buffer, log_content_buffer
; Also append a newline for readability
log_content_buffer.clear
log_content_buffer.add 10
fileappend_arr filename_buffer, log_content_buffer
}
;#######################################################
;# MAIN EXECUTION BLOCK
;#######################################################
main
; --- 1. Setup ---
arradd filename_buffer demo_output.log
filedelete_arr filename_buffer ; Start with a clean file
; --- 2. Populate and Sort Data ---
number_list.add 42
number_list.add 8
number_list.add 1991
number_list.add 100
sort_number_list()
; --- 3. Log the Sorted Data ---
log_content_buffer.clear
arradd log_content_buffer Sorted list written to disk.
append_to_log()
print("Log updated.")
; --- 4. Get User Input and Log It ---
print("--- User Input ---")
arradd prompt Enter a message:
prompt.add 32 ; Add trailing space for prompt
input user_input, prompt
log_content_buffer.clear
log_content_buffer.copy user_input
append_to_log()
print("User message logged.")
; --- 5. Read and Display the Final Log File ---
print("--- Final Log Contents ---")
log_content_buffer.clear ; Reuse buffer for reading
fileread_arr log_content_buffer, filename_buffer
log_content_buffer.size
Loop, rax {
log_content_buffer.index A_Index
print_rax_as_char
}
print("--- DEMO COMPLETE ---")This is a summary of the most important, non-obvious rules of HTLL. Internalize them.
arraddUSES NO QUOTES: The most common mistake.arradd my_arr Some textis correct.arradd my_arr "Some text"is wrong. To add a space at the end of text, you must append it manually with.add 32.- ALL DECLARED VARIABLES ARE GLOBAL: There is no local variable declaration.
int x := 0inside a function creates a globalxthat is initialized only once. The only local scope is for function parameters. Doing so will cause big problems, so just DO NOT declare variables inside a function body. - ARRAYS ARE NOT PARAMETERS: You cannot pass an array to a function like
my_func(my_array). This is forbidden. You must use the Global Buffer Pattern described in section 10. args_arrayIS RESERVED: Do not declarearr args_array. The system provides it.- NO
else,and,or: These constructs do not exist. You must build equivalent logic usinggotoand nestedifstatements. This is intentional. print("")IS FOR NEWLINES: This is the specific syntax trick to print a newline character.- SPACE BEFORE END-OF-LINE COMMENTS: A comment at the end of a line needs a space.
x++ ; commentis correct.x++;commentis wrong. - NESTING IS FINITE: You have 9 levels. If you need more, your code is too complex and must be refactored into smaller functions.
In conclusion: C is bloated.
You have been told your whole life that C is the pinnacle of minimalism. This is a lie. The dependency on libc and the complexity of its toolchains introduce unnecessary bloat.
HTLL is an experiment in true minimalism. The trade-off is its specificity: it only targets only a few architectures (x86-64 and AArch64) and one operating system (Linux). But within that domain, it offers unparalleled control and efficiency.