standardized the system of stack effect comments and updated/corrected the existing comments in stdlib and added some that were lacking

This commit is contained in:
IgorCielniak
2026-02-05 21:36:03 +01:00
parent 2d06358e24
commit 5fb36ac9bc
11 changed files with 128 additions and 110 deletions

View File

@@ -21,6 +21,13 @@ This document reflects the implementation that ships in this repository today (`
- **Lists** `[` begins a list literal, `]` ends it. The compiler captures the intervening stack segment into a freshly `mmap`'d buffer that stores `(len followed by qword items)`, drops the captured values, and pushes the buffer address. Users must `munmap` the buffer when done. - **Lists** `[` begins a list literal, `]` ends it. The compiler captures the intervening stack segment into a freshly `mmap`'d buffer that stores `(len followed by qword items)`, drops the captured values, and pushes the buffer address. Users must `munmap` the buffer when done.
- **Token customization** Immediate words can call `add-token` or `add-token-chars` to teach the reader about new multi-character tokens. `fn.sl` uses this in combination with token hooks to recognize `foo(1, 2)` syntax. - **Token customization** Immediate words can call `add-token` or `add-token-chars` to teach the reader about new multi-character tokens. `fn.sl` uses this in combination with token hooks to recognize `foo(1, 2)` syntax.
### Stack-effect comments
- **Location and prefix** Public words in `stdlib/` (and most user code should) document its stack effect with a line comment directly above the definition: `#word_name …`.
- **Before/after form** Use `[before] -> [after]`, where each side is a comma-separated list. Items sitting to the left of `|` are deeper in the stack; the segment to the right of `|` runs all the way to the current top-of-stack. Omit the `|` only when a side is empty (`[*]`).
- **Tail sentinel** `*` represents the untouched rest of the stack. By convention it is always the first entry on each side so readers can quickly see which values are consumed/produced.
- **Alternatives** Separate multiple outcomes with `||`. Each branch repeats the `[before] -> [after]` structure (e.g., `#read_file [*, path | len] -> [*, addr | len] || [*, tag | neg_errno]`).
- **Examples** `#dup [* | x] -> [*, x | x]` means a word consumes the top value `x` and returns two copies with the newest copy at TOS; `#arr_pop [* | arr] -> [*, arr | x]` states that the array pointer remains just below the popped element. This notation keeps stack order resonably easy to read and grep.
## 4. Runtime Model ## 4. Runtime Model
- **Stacks** `r12` holds the data stack pointer, `r13` the return stack pointer. Both live in `.bss` buffers sized by `DSTK_BYTES`/`RSTK_BYTES` (default 64 KiB each). `stdlib/core.sl` implements all standard stack shuffles, arithmetic, comparisons, boolean ops, `@`/`!`, `c@`/`c!`, and return-stack transfers (`>r`, `r>`, `rdrop`, `rpick`). - **Stacks** `r12` holds the data stack pointer, `r13` the return stack pointer. Both live in `.bss` buffers sized by `DSTK_BYTES`/`RSTK_BYTES` (default 64 KiB each). `stdlib/core.sl` implements all standard stack shuffles, arithmetic, comparisons, boolean ops, `@`/`!`, `c@`/`c!`, and return-stack transfers (`>r`, `r>`, `rdrop`, `rpick`).
- **Calling convention** Words call each other using the System V ABI. `extern` words marshal arguments into registers before `call symbol`, then push results back onto the data stack. Integer results come from `rax`; floating results come from `xmm0` and are copied into a qword slot. - **Calling convention** Words call each other using the System V ABI. `extern` words marshal arguments into registers before `call symbol`, then push results back onto the data stack. Integer results come from `rax`; floating results come from `xmm0` and are copied into a qword slot.

3
fn.sl
View File

@@ -1,4 +1,5 @@
word call-syntax-rewrite # ( fnameToken -- handled ) #call-syntax-rewrite [* | fnameToken] -> [* | handled]
word call-syntax-rewrite
dup token-lexeme identifier? 0 == if drop 0 exit end dup token-lexeme identifier? 0 == if drop 0 exit end
peek-token dup nil? if drop drop 0 exit end peek-token dup nil? if drop drop 0 exit end
dup token-lexeme "(" string= 0 == if drop drop 0 exit end dup token-lexeme "(" string= 0 == if drop drop 0 exit end

2
nob.sl
View File

@@ -2,7 +2,7 @@ import stdlib/stdlib.sl
import stdlib/linux.sl import stdlib/linux.sl
import stdlib/mem.sl import stdlib/mem.sl
# sh ( cmd_addr cmd_len -- exit_code | neg_errno ) # sh [*, cmd_addr | cmd_len ] -> [* | exit_code ]
word sh word sh
swap swap
>r # save cmd_addr >r # save cmd_addr

View File

@@ -11,7 +11,7 @@
import mem.sl import mem.sl
# : arr_new ( cap -- arr ) #arr_new [* | cap] -> [* | arr]
# Create a new array with given initial capacity (minimum 1) # Create a new array with given initial capacity (minimum 1)
word arr_new word arr_new
dup 1 < if drop 1 end dup 1 < if drop 1 end
@@ -22,21 +22,21 @@ word arr_new
nip nip
end end
# : arr_len ( arr -- len ) #arr_len [* | arr] -> [* | len]
word arr_len @ end word arr_len @ end
# : arr_cap ( arr -- cap ) #arr_cap [* | arr] -> [* | cap]
word arr_cap 8 + @ end word arr_cap 8 + @ end
# : arr_data ( arr -- ptr ) #arr_data [* | arr] -> [* | ptr]
word arr_data 16 + @ end word arr_data 16 + @ end
# : arr_free ( arr -- ) #arr_free [* | arr] -> [*]
word arr_free word arr_free
dup arr_cap 8 * 24 + free dup arr_cap 8 * 24 + free
end end
# Helper: copy n qwords from src to dst (dst src n --) # Helper: copy n qwords from src to dst [*, dst, src | n] -> [*]
word arr_copy_elements word arr_copy_elements
while dup 0 > do while dup 0 > do
over @ 3 pick swap ! # dst = *src over @ 3 pick swap ! # dst = *src
@@ -47,7 +47,7 @@ word arr_copy_elements
drop 2drop drop 2drop
end end
# : arr_reserve ( cap arr -- arr ) #arr_reserve [*, cap | arr] -> [* | arr]
# Ensures capacity >= cap; returns (possibly moved) arr pointer. # Ensures capacity >= cap; returns (possibly moved) arr pointer.
word arr_reserve word arr_reserve
swap dup 1 < if drop 1 end swap # reqcap arr swap dup 1 < if drop 1 end swap # reqcap arr
@@ -77,7 +77,7 @@ word arr_reserve
end end
end end
# : arr_push ( x arr -- arr ) #arr_push [*, x | arr] -> [* | arr]
# Push element onto array, growing if needed # Push element onto array, growing if needed
word arr_push word arr_push
dup arr_len over arr_cap >= if dup arr_len over arr_cap >= if
@@ -94,27 +94,26 @@ word arr_push
dup @ 1 + over swap ! dup @ 1 + over swap !
end end
# : arr_pop ( arr -- x arr ) #arr_pop [* | arr] -> [*, arr | x]
# Pop element from array (returns 0 if empty) # Pop element from array (returns 0 if empty)
word arr_pop word arr_pop
dup arr_len 0 == if dup arr_len 0 == if
0 swap 0
else else
# Decrement len # Decrement len
dup @ 1 - over swap ! dup @ 1 - over swap !
# Get element at new len position # Get element at new len position
dup arr_data over arr_len 8 * + @ dup arr_data over arr_len 8 * + @
swap
end end
end end
# : arr_get ( i arr -- x ) #arr_get [*, i | arr] -> [* | x]
# Get element at index i # Get element at index i
word arr_get word arr_get
arr_data swap 8 * + @ arr_data swap 8 * + @
end end
# : arr_set ( x i arr -- ) #arr_set [*, x, i | arr] -> [*]
# Set element at index i to x # Set element at index i to x
word arr_set word arr_set
arr_data swap 8 * + swap ! arr_data swap 8 * + swap !

View File

@@ -9,7 +9,7 @@
# Allocation: mmap; free: munmap. # Allocation: mmap; free: munmap.
# Growth: allocate new block, copy elements, munmap old block. # Growth: allocate new block, copy elements, munmap old block.
# : arr_new ( cap -- arr ) #arr_new [* | cap] -> [* | arr]
:asm arr_new { :asm arr_new {
mov r14, [r12] ; requested cap mov r14, [r12] ; requested cap
cmp r14, 1 cmp r14, 1
@@ -42,7 +42,7 @@
} }
; ;
# : arr_len ( arr -- len ) #arr_len [* | arr] -> [* | len]
:asm arr_len { :asm arr_len {
mov rax, [r12] mov rax, [r12]
mov rax, [rax] mov rax, [rax]
@@ -51,7 +51,7 @@
} }
; ;
# : arr_cap ( arr -- cap ) #arr_cap [* | arr] -> [* | cap]
:asm arr_cap { :asm arr_cap {
mov rax, [r12] mov rax, [r12]
mov rax, [rax + 8] mov rax, [rax + 8]
@@ -60,7 +60,7 @@
} }
; ;
# : arr_data ( arr -- ptr ) #arr_data [* | arr] -> [* | ptr]
:asm arr_data { :asm arr_data {
mov rax, [r12] mov rax, [r12]
mov rax, [rax + 16] mov rax, [rax + 16]
@@ -69,7 +69,7 @@
} }
; ;
# : arr_free ( arr -- ) #arr_free [* | arr] -> [*]
:asm arr_free { :asm arr_free {
mov rbx, [r12] ; base mov rbx, [r12] ; base
mov rcx, [rbx + 8] ; cap mov rcx, [rbx + 8] ; cap
@@ -84,7 +84,7 @@
} }
; ;
# : arr_reserve ( cap arr -- arr ) #arr_reserve [*, cap | arr] -> [* | arr]
# Ensures capacity >= cap; returns (possibly moved) arr pointer. # Ensures capacity >= cap; returns (possibly moved) arr pointer.
:asm arr_reserve { :asm arr_reserve {
mov rbx, [r12] ; arr mov rbx, [r12] ; arr
@@ -151,7 +151,7 @@
} }
; ;
# : arr_push ( x arr -- arr ) #arr_push [*, x | arr] -> [* | arr]
:asm arr_push { :asm arr_push {
mov rbx, [r12] ; arr mov rbx, [r12] ; arr
mov rcx, [rbx] ; len mov rcx, [rbx] ; len
@@ -227,7 +227,7 @@
} }
; ;
# : arr_pop ( arr -- x arr ) #arr_pop [* | arr] -> [*, arr | x]
:asm arr_pop { :asm arr_pop {
mov rbx, [r12] ; arr mov rbx, [r12] ; arr
mov rcx, [rbx] ; len mov rcx, [rbx] ; len

View File

@@ -2,6 +2,7 @@
# persistent: resb 64 # persistent: resb 64
# push the addr of it # push the addr of it
#mem [*] -> [* | ptr]
:asm mem { :asm mem {
lea rax, [rel persistent] lea rax, [rel persistent]
sub r12, 8 sub r12, 8
@@ -9,7 +10,7 @@
} }
; ;
# : argc ( -- n ) #argc [*] -> [* | n]
:asm argc { :asm argc {
extern sys_argc extern sys_argc
mov rax, [rel sys_argc] mov rax, [rel sys_argc]
@@ -19,7 +20,7 @@
} }
; ;
# : argv ( -- ptr ) #argv [*] -> [* | ptr]
:asm argv { :asm argv {
extern sys_argv extern sys_argv
mov rax, [rel sys_argv] mov rax, [rel sys_argv]
@@ -29,7 +30,7 @@
} }
; ;
# : argv@ ( n -- ptr ) #argv@ [* | n] -> [* | ptr]
:asm argv@ { :asm argv@ {
extern sys_argv extern sys_argv
mov rbx, [r12] ; n mov rbx, [r12] ; n
@@ -40,7 +41,7 @@
} }
; ;
# : c@ ( addr -- byte ) #c@ [* | addr] -> [* | byte]
:asm c@ { :asm c@ {
mov rax, [r12] ; get address from stack mov rax, [r12] ; get address from stack
movzx rax, byte [rax] ; load byte at address, zero-extend to rax movzx rax, byte [rax] ; load byte at address, zero-extend to rax
@@ -49,7 +50,7 @@
} }
; ;
# : c! ( byte addr -- ) #c! [*, byte | addr] -> [*]
:asm c! { :asm c! {
mov rax, [r12] ; get address from stack mov rax, [r12] ; get address from stack
add r12, 8 ; pop address add r12, 8 ; pop address
@@ -60,7 +61,7 @@
} }
; ;
# : r@ ( -- x ) #r@ [*] -> [* | x]
:asm r@ { :asm r@ {
mov rax, [r13] ; get value from return stack mov rax, [r13] ; get value from return stack
sub r12, 8 ; make room on data stack sub r12, 8 ; make room on data stack
@@ -69,7 +70,7 @@
} }
; ;
# : dup ( x -- x x ) #dup [* | x] -> [*, x | x]
:asm dup { :asm dup {
mov rax, [r12] ; get top of stack mov rax, [r12] ; get top of stack
sub r12, 8 ; make room sub r12, 8 ; make room
@@ -77,13 +78,13 @@
} }
; ;
# : drop ( x -- ) #drop [* | x] -> [*]
:asm drop { :asm drop {
add r12, 8 ; remove top of stack add r12, 8 ; remove top of stack
} }
; ;
# : over ( x1 x2 -- x1 x2 x1 ) #over [*, x1 | x2] -> [*, x1, x2 | x1]
:asm over { :asm over {
mov rax, [r12 + 8] ; get second item mov rax, [r12 + 8] ; get second item
sub r12, 8 ; make room sub r12, 8 ; make room
@@ -91,7 +92,7 @@
} }
; ;
# : swap ( x1 x2 -- x2 x1 ) #swap [*, x1 | x2] -> [*, x2 | x1]
:asm swap { :asm swap {
mov rax, [r12] ; get top mov rax, [r12] ; get top
mov rbx, [r12 + 8] ; get second mov rbx, [r12 + 8] ; get second
@@ -100,7 +101,7 @@
} }
; ;
# : rot ( x1 x2 x3 -- x2 x3 x1 ) #rot [*, x1, x2 | x3] -> [*, x2, x3 | x1]
:asm rot { :asm rot {
mov rax, [r12] ; x3 (top) mov rax, [r12] ; x3 (top)
mov rbx, [r12 + 8] ; x2 mov rbx, [r12 + 8] ; x2
@@ -111,7 +112,7 @@
} }
; ;
# : -rot ( x1 x2 x3 -- x3 x1 x2 ) #-rot [*, x1, x2 | x3] -> [*, x3, x1 | x2]
:asm -rot { :asm -rot {
mov rax, [r12] ; x3 (top) mov rax, [r12] ; x3 (top)
mov rbx, [r12 + 8] ; x2 mov rbx, [r12 + 8] ; x2
@@ -122,7 +123,7 @@
} }
; ;
# : nip ( x1 x2 -- x2 ) #nip [*, x1 | x2] -> [* | x2]
:asm nip { :asm nip {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; drop lower add r12, 8 ; drop lower
@@ -130,7 +131,7 @@
} }
; ;
# : tuck ( x1 x2 -- x2 x1 x2 ) #tuck [*, x1 | x2] -> [*, x2, x1 | x2]
:asm tuck { :asm tuck {
mov rax, [r12] ; x2 (top) mov rax, [r12] ; x2 (top)
mov rbx, [r12 + 8] ; x1 mov rbx, [r12 + 8] ; x1
@@ -141,7 +142,7 @@
} }
; ;
# : 2dup ( x1 x2 -- x1 x2 x1 x2 ) #2dup [*, x1 | x2] -> [*, x1, x2, x1 | x2]
:asm 2dup { :asm 2dup {
mov rax, [r12] ; b (top) mov rax, [r12] ; b (top)
mov rbx, [r12 + 8] ; a mov rbx, [r12 + 8] ; a
@@ -152,13 +153,13 @@
} }
; ;
# : 2drop ( x1 x2 -- ) #2drop [*, x1 | x2] -> [*]
:asm 2drop { :asm 2drop {
add r12, 16 ; remove two items add r12, 16 ; remove two items
} }
; ;
# : 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 ) #2swap [*, x1, x2, x3 | x4] -> [*, x3, x4, x1 | x2]
:asm 2swap { :asm 2swap {
mov rax, [r12] ; d (top) mov rax, [r12] ; d (top)
mov rbx, [r12 + 8] ; c mov rbx, [r12 + 8] ; c
@@ -171,7 +172,7 @@
} }
; ;
# : 2over ( x1 x2 x3 x4 -- x3 x4 x1 x2 x3 x4 ) #2over [*, x1, x2, x3 | x4] -> [*, x3, x4, x1, x2, x3 | x4]
:asm 2over { :asm 2over {
mov rax, [r12 + 16] ; b mov rax, [r12 + 16] ; b
mov rbx, [r12 + 24] ; a mov rbx, [r12 + 24] ; a
@@ -182,7 +183,7 @@
} }
; ;
# : + ( x1 x2 -- x3 ) #+ [*, x1 | x2] -> [* | x3]
:asm + { :asm + {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -190,7 +191,7 @@
} }
; ;
# : - ( x1 x2 -- x3 ) #- [*, x1 | x2] -> [* | x3]
:asm - { :asm - {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -198,7 +199,7 @@
} }
; ;
# : * ( x1 x2 -- x3 ) #* [*, x1 | x2] -> [* | x3]
:asm * { :asm * {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -207,7 +208,7 @@
} }
; ;
# : / ( x1 x2 -- x3 ) #/ [*, x1 | x2] -> [* | x3]
:asm / { :asm / {
mov rbx, [r12] ; divisor mov rbx, [r12] ; divisor
add r12, 8 ; pop add r12, 8 ; pop
@@ -218,7 +219,7 @@
} }
; ;
# : % ( x1 x2 -- x3 ) #% [*, x1 | x2] -> [* | x3]
:asm % { :asm % {
mov rbx, [r12] ; divisor mov rbx, [r12] ; divisor
add r12, 8 ; pop add r12, 8 ; pop
@@ -229,7 +230,7 @@
} }
; ;
# : == ( x1 x2 -- flag ) #== [*, x1 | x2] -> [* | flag]
:asm == { :asm == {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -241,7 +242,7 @@
} }
; ;
# : != ( x1 x2 -- flag ) #!= [*, x1 | x2] -> [* | flag]
:asm != { :asm != {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -253,7 +254,7 @@
} }
; ;
# : < ( x1 x2 -- flag ) #< [*, x1 | x2] -> [* | flag]
:asm < { :asm < {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -265,7 +266,7 @@
} }
; ;
# : > ( x1 x2 -- flag ) #> [*, x1 | x2] -> [* | flag]
:asm > { :asm > {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -277,7 +278,7 @@
} }
; ;
# : <= ( x1 x2 -- flag ) #<= [*, x1 | x2] -> [* | flag]
:asm <= { :asm <= {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -289,7 +290,7 @@
} }
; ;
# : >= ( x1 x2 -- flag ) #>= [*, x1 | x2] -> [* | flag]
:asm >= { :asm >= {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -301,7 +302,7 @@
} }
; ;
# : @ ( addr -- x ) #@ [* | addr] -> [* | x]
:asm @ { :asm @ {
mov rax, [r12] ; get address mov rax, [r12] ; get address
mov rax, [rax] ; load value mov rax, [rax] ; load value
@@ -309,7 +310,7 @@
} }
; ;
# : ! ( x addr -- ) #! [*, x | addr] -> [*]
:asm ! { :asm ! {
mov rax, [r12] ; get value (TOS) mov rax, [r12] ; get value (TOS)
add r12, 8 ; pop value add r12, 8 ; pop value
@@ -319,7 +320,7 @@
} }
; ;
# : mmap ( addr len prot flags fd offset -- addr ) #mmap [*, addr, len, prot, flags, fd | offset] -> [* | addr]
:asm mmap { :asm mmap {
mov r9, [r12] ; offset mov r9, [r12] ; offset
add r12, 8 add r12, 8
@@ -339,7 +340,7 @@
} }
; ;
# : munmap ( addr len -- res ) #munmap [*, addr | len] -> [* | res]
:asm munmap { :asm munmap {
mov rsi, [r12] ; len mov rsi, [r12] ; len
add r12, 8 add r12, 8
@@ -352,7 +353,7 @@
} }
; ;
# : exit ( code -- ) #exit [* | code] -> [*]
:asm exit { :asm exit {
mov rdi, [r12] ; exit code mov rdi, [r12] ; exit code
add r12, 8 add r12, 8
@@ -361,7 +362,7 @@
} }
; ;
# : and ( x1 x2 -- flag ) #and [*, x1 | x2] -> [* | flag]
:asm and { :asm and {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -377,7 +378,7 @@
} }
; ;
# : or ( x1 x2 -- flag ) #or [*, x1 | x2] -> [* | flag]
:asm or { :asm or {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -393,7 +394,7 @@
} }
; ;
# : not ( x -- flag ) #not [* | x] -> [* | flag]
:asm not { :asm not {
mov rax, [r12] ; get value mov rax, [r12] ; get value
test rax, rax test rax, rax
@@ -403,7 +404,7 @@
} }
; ;
# : >r ( x -- ) #>r [* | x] -> [*]
:asm >r { :asm >r {
mov rax, [r12] ; get value mov rax, [r12] ; get value
add r12, 8 ; pop add r12, 8 ; pop
@@ -412,7 +413,7 @@
} }
; ;
# : r> ( -- x ) #r> [*] -> [* | x]
:asm r> { :asm r> {
mov rax, [r13] ; get value from return stack mov rax, [r13] ; get value from return stack
add r13, 8 ; pop return stack add r13, 8 ; pop return stack
@@ -421,13 +422,13 @@
} }
; ;
# : rdrop ( -- ) #rdrop [*] -> [*]
:asm rdrop { :asm rdrop {
add r13, 8 ; pop return stack add r13, 8 ; pop return stack
} }
; ;
# : pick ( n -- x ) #pick [* | n] -> [* | x]
:asm pick { :asm pick {
mov rcx, [r12] ; get index mov rcx, [r12] ; get index
add r12, 8 ; pop add r12, 8 ; pop
@@ -437,7 +438,7 @@
} }
; ;
# : rpick ( n -- x ) #rpick [* | n] -> [* | x]
:asm rpick { :asm rpick {
mov rcx, [r12] ; get index mov rcx, [r12] ; get index
add r12, 8 ; pop add r12, 8 ; pop
@@ -447,7 +448,7 @@
} }
; ;
# : neg ( x -- -x ) #neg [* | x] -> [* | -x]
:asm neg { :asm neg {
mov rax, [r12] ; get value mov rax, [r12] ; get value
neg rax ; arithmetic negation neg rax ; arithmetic negation
@@ -455,7 +456,7 @@
} }
; ;
# : abs ( x -- |x| ) #abs [* | x] -> [* | |x|]
:asm abs { :asm abs {
mov rax, [r12] ; get value mov rax, [r12] ; get value
test rax, rax ; check sign test rax, rax ; check sign
@@ -466,7 +467,7 @@
} }
; ;
# : bitnot ( 0|1 -- 1|0 ) #bitnot [* | bool] -> [* | bool]
:asm bitnot { :asm bitnot {
mov rax, [r12] ; get value mov rax, [r12] ; get value
xor rax, 1 ; flip lowest bit xor rax, 1 ; flip lowest bit
@@ -474,7 +475,7 @@
} }
; ;
# : band ( x1 x2 -- x3 ) #band [*, x1 | x2] -> [* | x3]
:asm band { :asm band {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -482,7 +483,7 @@
} }
; ;
# : bor ( x1 x2 -- x3 ) #bor [*, x1 | x2] -> [* | x3]
:asm bor { :asm bor {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -490,7 +491,7 @@
} }
; ;
# : bxor ( x1 x2 -- x3 ) #bxor [*, x1 | x2] -> [* | x3]
:asm bxor { :asm bxor {
mov rax, [r12] ; get top mov rax, [r12] ; get top
add r12, 8 ; pop add r12, 8 ; pop
@@ -498,13 +499,13 @@
} }
; ;
# : bnot ( x -- x ) #bnot [* | x] -> [* | x]
:asm bnot { :asm bnot {
not qword [r12] ; bitwise not not qword [r12] ; bitwise not
} }
; ;
# : shl ( x1 x2 -- x3 ) #shl [*, x1 | x2] -> [* | x3]
:asm shl { :asm shl {
mov rcx, [r12] ; shift count mov rcx, [r12] ; shift count
add r12, 8 ; pop add r12, 8 ; pop
@@ -512,7 +513,7 @@
} }
; ;
# : sal ( x1 x2 -- x3 ) #sal [*, x1 | x2] -> [* | x3]
:asm sal { :asm sal {
mov rcx, [r12] ; shift count mov rcx, [r12] ; shift count
add r12, 8 ; pop add r12, 8 ; pop
@@ -520,7 +521,7 @@
} }
; ;
# : shr ( x1 x2 -- x3 ) #shr [*, x1 | x2] -> [* | x3]
:asm shr { :asm shr {
mov rcx, [r12] ; shift count mov rcx, [r12] ; shift count
add r12, 8 ; pop add r12, 8 ; pop
@@ -528,7 +529,7 @@
} }
; ;
# : sar ( x1 x2 -- x3 ) #sar [*, x1 | x2] -> [* | x3]
:asm sar { :asm sar {
mov rcx, [r12] ; shift count mov rcx, [r12] ; shift count
add r12, 8 ; pop add r12, 8 ; pop
@@ -536,7 +537,7 @@
} }
; ;
# : rol ( x1 x2 -- x3 ) #rol [*, x1 | x2] -> [* | x3]
:asm rol { :asm rol {
mov rcx, [r12] ; shift count mov rcx, [r12] ; shift count
add r12, 8 ; pop add r12, 8 ; pop
@@ -544,7 +545,7 @@
} }
; ;
# : ror ( x1 x2 -- x3 ) #ror [*, x1 | x2] -> [* | x3]
:asm ror { :asm ror {
mov rcx, [r12] ; shift count mov rcx, [r12] ; shift count
add r12, 8 ; pop add r12, 8 ; pop
@@ -552,19 +553,19 @@
} }
; ;
# : inc ( x -- x+1 ) #inc [* | x] -> [* | x+1]
:asm inc { :asm inc {
inc qword [r12] inc qword [r12]
} }
; ;
# : dec ( x -- x-1 ) #dec [* | x] -> [* | x-1]
:asm dec { :asm dec {
dec qword [r12] dec qword [r12]
} }
; ;
# : min ( x1 x2 -- x3 ) #min [*, x1 | x2] -> [* | x3]
:asm min { :asm min {
mov rax, [r12] ; x2 mov rax, [r12] ; x2
add r12, 8 ; pop add r12, 8 ; pop
@@ -575,7 +576,7 @@
} }
; ;
# : max ( x1 x2 -- x3 ) #max [*, x1 | x2] -> [* | x3]
:asm max { :asm max {
mov rax, [r12] ; x2 mov rax, [r12] ; x2
add r12, 8 ; pop add r12, 8 ; pop
@@ -586,7 +587,7 @@
} }
; ;
# : clamp ( x lo hi -- y ) #clamp [*, x, lo | hi] -> [* | y]
:asm clamp { :asm clamp {
mov rax, [r12] ; hi mov rax, [r12] ; hi
mov rbx, [r12 + 8] ; lo mov rbx, [r12 + 8] ; lo
@@ -600,7 +601,7 @@
} }
; ;
# : time ( -- t ) #time [*] -> [* | t]
:asm time { :asm time {
mov rax, 201 ; syscall: time mov rax, 201 ; syscall: time
xor rdi, rdi xor rdi, rdi
@@ -611,7 +612,7 @@
} }
; ;
# : rand ( -- n ) #rand [*] -> [* | n]
:asm rand { :asm rand {
lea rbx, [rel persistent] lea rbx, [rel persistent]
mov rax, [rbx] ; state mov rax, [rbx] ; state

View File

@@ -1,7 +1,7 @@
import stdlib.sl import stdlib.sl
import io.sl import io.sl
# : dump ( n -- ) #dump [* | n] -> [*]
# dump takes the firts element from the stack # dump takes the firts element from the stack
# and prints that much consequent elements # and prints that much consequent elements
@@ -28,7 +28,7 @@ word rdump
drop drop
end end
# : int3 ( -- ) #int3 [*] -> [*]
:asm int3 { :asm int3 {
int3 int3
} }

View File

@@ -1,8 +1,8 @@
# L2 IO Primitives # L2 IO Primitives
# : read_file ( path_addr path_len -- addr len | 0 0 ) #read_file [*, path_addr | path_len] -> [*, addr | len] || [*, tag | neg_errno]
# Reads the file at the given path (pointer+length, not null-terminated), # Reads the file at the given path (pointer+length, not null-terminated),
# returns (addr len) of mapped file, or (0 0) on error. # returns (addr len) of mapped file, or (tag neg_errno) on error.
:asm read_file { :asm read_file {
; stack: path_addr (NOS), path_len (TOS) ; stack: path_addr (NOS), path_len (TOS)
@@ -79,7 +79,7 @@
} }
; ;
# : write_file ( path_ptr path_len buf_ptr buf_len -- bytes_written | neg_errno ) #write_file [*, path_ptr, path_len, buf_ptr | buf_len] -> [* | bytes_written] || [* | neg_errno]
:asm write_file { :asm write_file {
; stack: path_addr, path_len, buf_addr, buf_len (TOS) ; stack: path_addr, path_len, buf_addr, buf_len (TOS)
mov r13, [r12] ; buf_len mov r13, [r12] ; buf_len
@@ -132,7 +132,7 @@
} }
; ;
# : read_stdin ( max_len -- addr len | neg_errno 0 ) #read_stdin [* | max_len] -> [*, addr | len] || [*, tag | neg_errno]
:asm read_stdin { :asm read_stdin {
; stack: max_len ; stack: max_len
mov r14, [r12] ; max_len mov r14, [r12] ; max_len
@@ -268,7 +268,7 @@
} }
; ;
# : write_buf ( addr len -- ) #write_buf [*, addr | len] -> [*]
:asm write_buf (effects string-io) { :asm write_buf (effects string-io) {
mov rdx, [r12] ; len mov rdx, [r12] ; len
mov rsi, [r12 + 8] ; addr mov rsi, [r12 + 8] ; addr
@@ -280,7 +280,7 @@
} }
; ;
# : ewrite_buf ( addr len -- ) #ewrite_buf [*, addr | len] -> [*]
:asm ewrite_buf (effects string-io) { :asm ewrite_buf (effects string-io) {
mov rdx, [r12] ; len mov rdx, [r12] ; len
mov rsi, [r12 + 8] ; addr mov rsi, [r12 + 8] ; addr
@@ -292,7 +292,7 @@
} }
; ;
# : putc ( char -- ) #putc [* | char] -> [*]
:asm putc { :asm putc {
mov rax, [r12] mov rax, [r12]
add r12, 8 add r12, 8
@@ -306,7 +306,7 @@
} }
; ;
# : puti ( int -- ) #puti [* | int] -> [*]
:asm puti { :asm puti {
mov rax, [r12] ; get int mov rax, [r12] ; get int
add r12, 8 ; pop add r12, 8 ; pop

View File

@@ -2,7 +2,7 @@
# Provides syscall constants and helpers for L2 programs # Provides syscall constants and helpers for L2 programs
# swap impl is provided so this can be used without the need for stdlib # swap impl is provided so this can be used without the need for stdlib
# : ___linux_swap ( x1 x2 -- x2 x1 ) #___linux_swap [*, x1 | x2] -> [*, x2 | x1]
:asm ___linux_swap { :asm ___linux_swap {
mov rax, [r12] ; get top mov rax, [r12] ; get top
mov rbx, [r12 + 8] ; get second mov rbx, [r12 + 8] ; get second

View File

@@ -1,5 +1,6 @@
import stdlib.sl import stdlib.sl
#alloc [* | size] -> [* | addr]
word alloc word alloc
0 # addr hint (NULL) 0 # addr hint (NULL)
swap # size swap # size
@@ -11,11 +12,13 @@ word alloc
swap drop swap drop
end end
#free [*, addr | size] -> [*]
word free word free
munmap drop munmap drop
end end
word memcpy #(dst_addr src_addr len -- dst_addr len) #memcpy [*, dst_addr, src_addr | len] -> [*, dst_addr | len]
word memcpy
dup dup
>r >r
swap swap
@@ -40,7 +43,8 @@ word memcpy #(dst_addr src_addr len -- dst_addr len)
r> dup -rot - swap r> dup -rot - swap
end end
word memset #( value len addr -- ) #memset [*, value, len | addr] -> [*]
word memset
swap swap
0 swap for 0 swap for
-rot swap 2 pick + 2dup swap ! 1 + -rot swap -rot swap 2 pick + 2dup swap ! 1 + -rot swap
@@ -48,13 +52,15 @@ word memset #( value len addr -- )
2drop drop 2drop drop
end end
word memdump #( len addr -- addr ) #memdump [*, len | addr] -> [* | addr]
word memdump
for for
dup c@ puti cr 1 + dup c@ puti cr 1 +
end end
end end
word realloc #( addr old_len new_len -- new_addr ) #realloc [*, addr, old_len | new_len] -> [* | new_addr]
word realloc
2 pick swap alloc 2 pick swap alloc
rot rot swap rot rot swap
memcpy memcpy

View File

@@ -1,10 +1,10 @@
# : strcmp ( addr len addr len -- bool addr len addr len) #strcmp [*, addr, len, addr | len] -> [*, addr, len, addr, len | bool]
word strcmp word strcmp
3 pick 2 pick @ swap @ == 3 pick 2 pick @ swap @ ==
end end
# : strconcat ( addr len addr len -- addr len) #strconcat [*, addr, len, addr | len] -> [*, addr | len]
word strconcat word strconcat
0 pick 3 pick + 0 pick 3 pick +
dup dup
@@ -31,7 +31,7 @@ word strconcat
rdrop rdrop rdrop rdrop rdrop rdrop
end end
# : strlen ( addr -- len ) #strlen [* | addr] -> [* | len]
# for null terminated strings # for null terminated strings
word strlen word strlen
0 swap # len addr 0 swap # len addr
@@ -42,7 +42,8 @@ word strlen
drop # drop addr, leave len drop # drop addr, leave len
end end
word digitsN>num # ( d_{n-1} ... d0 n -- value ), digits bottom=MSD, top=LSD, length on top (MSD-most significant digit, LSD-least significant digit) #digitsN>num [*, d_{n-1}, d0 | n] -> [* | value]
word digitsN>num # digits bottom=MSD, top=LSD, length on top (MSD-most significant digit, LSD-least significant digit)
0 swap # place accumulator below length 0 swap # place accumulator below length
for # loop n times using the length on top for # loop n times using the length on top
r@ pick # fetch next digit starting from MSD (uses loop counter as index) r@ pick # fetch next digit starting from MSD (uses loop counter as index)
@@ -52,7 +53,8 @@ word digitsN>num # ( d_{n-1} ... d0 n -- value ), digits bottom=MSD, top=LSD, l
end end
end end
# : toint (addr len -- int ) converts a string to an int #toint [*, addr | len] -> [* | int]
# converts a string to an int
word toint word toint
swap swap
over 0 swap over 0 swap
@@ -75,7 +77,8 @@ word toint
rdrop rdrop rdrop rdrop
end end
# : count_digits ( int -- int) returns the amount of digits of an int #count_digits [* | int] -> [* | int]
# returns the amount of digits of an int
word count_digits word count_digits
0 0
swap swap
@@ -85,7 +88,8 @@ word count_digits
drop drop
end end
# : tostr ( int -- addr len ) the function allocates a buffer to remember to free it #tostr [* | int] -> [*, addr | len]
# the function allocates a buffer, remember to free it
word tostr word tostr
dup dup
count_digits count_digits