This commit is contained in:
IgorCielniak
2025-12-08 18:14:52 +01:00
parent 3a63347380
commit 2ea49d26f7
8 changed files with 2099 additions and 18 deletions

20
SPEC.md
View File

@@ -25,6 +25,7 @@
- `lookup`: resolves token → word entry; can be replaced to build new namespaces or module systems. - `lookup`: resolves token → word entry; can be replaced to build new namespaces or module systems.
- **Compile vs interpret**: Each word advertises stack effect + immediacy. Immediate words execute during compilation (macro behavior). Others emit code or inline asm. - **Compile vs interpret**: Each word advertises stack effect + immediacy. Immediate words execute during compilation (macro behavior). Others emit code or inline asm.
- **Syntax morphing**: Provide primitives `set-reader`, `with-reader`, and word-lists so layers (e.g., Lisp-like forms) can be composed. - **Syntax morphing**: Provide primitives `set-reader`, `with-reader`, and word-lists so layers (e.g., Lisp-like forms) can be composed.
- **Inline Python hooks**: `:py name { ... } ;` executes the enclosed Python block immediately, then registers `name` as a word whose behavior is provided by that block. Define a `macro(ctx)` function to intercept compilation (receiving a `MacroContext` with helpers like `next_token`, `emit_literal`, `new_label`, `inject_tokens`, and direct access to the active parser), and/or an `intrinsic(builder)` function to emit custom assembly. This lets end users extend the language—parsing source, manipulating AST nodes, or writing NASM—without touching the bootstrap source. The standard librarys `extend-syntax` and `fn` forms are ordinary `:py` blocks built with these APIs, so users can clone or replace them entirely from L2 source files.
## 4. Core Types & Data Model ## 4. Core Types & Data Model
- **Cells**: 64-bit signed integers; all stack operations use cells. - **Cells**: 64-bit signed integers; all stack operations use cells.
@@ -49,6 +50,24 @@ struct: Point
- `<Struct>.<field>! ( value addr -- )` stores a field via `addr + offset !`. - `<Struct>.<field>! ( value addr -- )` stores a field via `addr + offset !`.
- Because the output is plain L2 code, users can inspect or override any generated word, and additional helpers (e.g., pointer arithmetic or iterators) can be layered on top with regular macros. - Because the output is plain L2 code, users can inspect or override any generated word, and additional helpers (e.g., pointer arithmetic or iterators) can be layered on top with regular macros.
### 4.2 Lightweight C-style Sugar
- `extend-syntax` is implemented as a `:py` macro that toggles a reader mode where identifiers suffixed with `()` (e.g., `foo()`) are rewritten as ordinary word calls. The call still obeys data-stack calling conventions; the parentheses are purely syntactic sugar.
- The same user-defined macro stack unlocks a compact function form:
```
fn add(int left, int right){
return (left + right) * right;
}
```
expands into a normal colon definition which consumes two stack arguments (`left` and `right`), mirrors them onto the return stack, evaluates the infix expression, and cleans up the temporary frame before returning.
- Current limitations:
- Only `int` parameters are recognized.
- Function bodies must be a single `return <expr>;` statement. `<expr>` may contain parameter names, integer literals, parentheses, and the binary operators `+ - * / %`.
- Parameter names become available by index via `rpick`, so advanced bodies can still drop into raw L2 code if needed.
- Since the generated code uses the return stack to store arguments, it happily composes with loops/conditionals—the frame lives beneath any subsequent `for` counters and is explicitly released before the word returns. Because `fn` lives in user space, nothing stops you from swapping it out for a completely different parser (pattern matching, keyword arguments, etc.) using the same `:py` facility.
## 5. Stacks & Calling Convention ## 5. Stacks & Calling Convention
- **Data stack**: Unlimited (up to memory). Manipulated via standard words (`dup`, `swap`, `rot`, `over`). Compiled code keeps top-of-stack in registers when possible for performance. - **Data stack**: Unlimited (up to memory). Manipulated via standard words (`dup`, `swap`, `rot`, `over`). Compiled code keeps top-of-stack in registers when possible for performance.
- **Return stack**: Used for control flow. Directly accessible for meta-programming; users must avoid corrupting call frames unless intentional. - **Return stack**: Used for control flow. Directly accessible for meta-programming; users must avoid corrupting call frames unless intentional.
@@ -102,6 +121,7 @@ struct: Point
## 14. Standard Library Sketch ## 14. Standard Library Sketch
- **Core words**: Arithmetic, logic, stack ops, comparison, memory access, control flow combinators. - **Core words**: Arithmetic, logic, stack ops, comparison, memory access, control flow combinators.
- **Return-stack helpers**: `>r`, `r>`, `rdrop`, and `rpick` shuffle values between the data stack and the return stack. Theyre used by the `fn` sugar but also available to user code for building custom control constructs.
- **Meta words**: Reader management, dictionary inspection, definition forms (`:`, `:noninline`, `:asm`, `immediate`). - **Meta words**: Reader management, dictionary inspection, definition forms (`:`, `:noninline`, `:asm`, `immediate`).
- **Allocators**: Default bump allocator, arena allocator, and hook to install custom malloc/free pairs. - **Allocators**: Default bump allocator, arena allocator, and hook to install custom malloc/free pairs.
- **FFI/syscalls**: Thin wrappers plus convenience words for POSIX-level APIs. - **FFI/syscalls**: Thin wrappers plus convenience words for POSIX-level APIs.

730
build/test.asm Normal file
View File

@@ -0,0 +1,730 @@
section .text
%define DSTK_BYTES 65536
%define RSTK_BYTES 65536
%define PRINT_BUF_BYTES 128
global _start
_start:
; initialize data/return stack pointers
lea r12, [rel dstack_top]
mov r15, r12
lea r13, [rel rstack_top]
call word_main
mov rax, 0
cmp r12, r15
je .no_exit_value
mov rax, [r12]
add r12, 8
.no_exit_value:
mov rdi, rax
mov rax, 60
syscall
word_puts:
mov rax, [r12]
add r12, 8
mov rbx, rax
mov r8, 0
cmp rbx, 0
jge puts_abs
neg rbx
mov r8, 1
puts_abs:
lea rsi, [rel print_buf_end]
mov rcx, 0
mov r10, 10
cmp rbx, 0
jne puts_digits
dec rsi
mov byte [rsi], '0'
inc rcx
jmp puts_sign
puts_digits:
puts_loop:
xor rdx, rdx
mov rax, rbx
div r10
add dl, '0'
dec rsi
mov [rsi], dl
inc rcx
mov rbx, rax
test rbx, rbx
jne puts_loop
puts_sign:
cmp r8, 0
je puts_finish_digits
dec rsi
mov byte [rsi], '-'
inc rcx
puts_finish_digits:
mov byte [rsi + rcx], 10
inc rcx
mov rax, 1
mov rdi, 1
mov rdx, rcx
mov r9, rsi
mov rsi, r9
syscall
ret
word_dup:
mov rax, [r12]
sub r12, 8
mov [r12], rax
ret
word_drop:
add r12, 8
ret
word_swap:
mov rax, [r12]
mov rbx, [r12 + 8]
mov [r12], rbx
mov [r12 + 8], rax
ret
word__2b:
mov rax, [r12]
add r12, 8
add qword [r12], rax
ret
word__2d:
mov rax, [r12]
add r12, 8
sub qword [r12], rax
ret
word__2a:
mov rax, [r12]
add r12, 8
imul qword [r12]
mov [r12], rax
ret
word__2f:
mov rbx, [r12]
add r12, 8
mov rax, [r12]
cqo
idiv rbx
mov [r12], rax
ret
word__25:
mov rbx, [r12]
add r12, 8
mov rax, [r12]
cqo
idiv rbx
mov [r12], rdx
ret
word__3d_3d:
mov rax, [r12]
add r12, 8
mov rbx, [r12]
cmp rbx, rax
mov rbx, 0
sete bl
mov [r12], rbx
ret
word__21_3d:
mov rax, [r12]
add r12, 8
mov rbx, [r12]
cmp rbx, rax
mov rbx, 0
setne bl
mov [r12], rbx
ret
word__3c:
mov rax, [r12]
add r12, 8
mov rbx, [r12]
cmp rbx, rax
mov rbx, 0
setl bl
mov [r12], rbx
ret
word__3e:
mov rax, [r12]
add r12, 8
mov rbx, [r12]
cmp rbx, rax
mov rbx, 0
setg bl
mov [r12], rbx
ret
word__3c_3d:
mov rax, [r12]
add r12, 8
mov rbx, [r12]
cmp rbx, rax
mov rbx, 0
setle bl
mov [r12], rbx
ret
word__3e_3d:
mov rax, [r12]
add r12, 8
mov rbx, [r12]
cmp rbx, rax
mov rbx, 0
setge bl
mov [r12], rbx
ret
word__40:
mov rax, [r12]
mov rax, [rax]
mov [r12], rax
ret
word__21:
mov rax, [r12]
add r12, 8
mov rbx, [r12]
mov [rax], rbx
add r12, 8
ret
word_mmap:
mov r9, [r12]
add r12, 8
mov r8, [r12]
add r12, 8
mov r10, [r12]
add r12, 8
mov rdx, [r12]
add r12, 8
mov rsi, [r12]
add r12, 8
mov rdi, [r12]
mov rax, 9
syscall
mov [r12], rax
ret
word_munmap:
mov rsi, [r12]
add r12, 8
mov rdi, [r12]
mov rax, 11
syscall
mov [r12], rax
ret
word_exit:
mov rdi, [r12]
add r12, 8
mov rax, 60
syscall
ret
word__3er:
mov rax, [r12]
add r12, 8
sub r13, 8
mov [r13], rax
ret
word_r_3e:
mov rax, [r13]
add r13, 8
sub r12, 8
mov [r12], rax
ret
word_rdrop:
add r13, 8
ret
word_rpick:
mov rcx, [r12]
add r12, 8
mov rax, [r13 + rcx * 8]
sub r12, 8
mov [r12], rax
ret
word_mem_2dslot:
lea rax, [rel print_buf]
sub r12, 8
mov [r12], rax
ret
word_MAGIC:
; push 99
sub r12, 8
mov qword [r12], 99
ret
word_add13:
; push 5
sub r12, 8
mov qword [r12], 5
; push 8
sub r12, 8
mov qword [r12], 8
call word__2b
ret
word_Point_2esize:
; push 16
sub r12, 8
mov qword [r12], 16
ret
word_Point_2ex_2esize:
; push 8
sub r12, 8
mov qword [r12], 8
ret
word_Point_2ex_2eoffset:
; push 0
sub r12, 8
mov qword [r12], 0
ret
word_Point_2ex_40:
call word_Point_2ex_2eoffset
call word__2b
call word__40
ret
word_Point_2ex_21:
call word_Point_2ex_2eoffset
call word__2b
call word__21
ret
word_Point_2ey_2esize:
; push 8
sub r12, 8
mov qword [r12], 8
ret
word_Point_2ey_2eoffset:
; push 8
sub r12, 8
mov qword [r12], 8
ret
word_Point_2ey_40:
call word_Point_2ey_2eoffset
call word__2b
call word__40
ret
word_Point_2ey_21:
call word_Point_2ey_2eoffset
call word__2b
call word__21
ret
word_fancy_add:
call word__3er
call word__3er
; push 0
sub r12, 8
mov qword [r12], 0
call word_rpick
; push 1
sub r12, 8
mov qword [r12], 1
call word_rpick
call word__2b
; push 1
sub r12, 8
mov qword [r12], 1
call word_rpick
call word__2a
call word_rdrop
call word_rdrop
ret
word_test_2dadd:
; push 5
sub r12, 8
mov qword [r12], 5
; push 7
sub r12, 8
mov qword [r12], 7
call word__2b
call word_puts
ret
word_test_2dsub:
; push 10
sub r12, 8
mov qword [r12], 10
; push 3
sub r12, 8
mov qword [r12], 3
call word__2d
call word_puts
ret
word_test_2dmul:
; push 6
sub r12, 8
mov qword [r12], 6
; push 7
sub r12, 8
mov qword [r12], 7
call word__2a
call word_puts
ret
word_test_2ddiv:
; push 84
sub r12, 8
mov qword [r12], 84
; push 7
sub r12, 8
mov qword [r12], 7
call word__2f
call word_puts
ret
word_test_2dmod:
; push 85
sub r12, 8
mov qword [r12], 85
; push 7
sub r12, 8
mov qword [r12], 7
call word__25
call word_puts
ret
word_test_2ddrop:
; push 10
sub r12, 8
mov qword [r12], 10
; push 20
sub r12, 8
mov qword [r12], 20
call word_drop
call word_puts
ret
word_test_2ddup:
; push 11
sub r12, 8
mov qword [r12], 11
call word_dup
call word__2b
call word_puts
ret
word_test_2dswap:
; push 2
sub r12, 8
mov qword [r12], 2
; push 5
sub r12, 8
mov qword [r12], 5
call word_swap
call word__2d
call word_puts
ret
word_test_2dstore:
call word_mem_2dslot
call word_dup
; push 123
sub r12, 8
mov qword [r12], 123
call word_swap
call word__21
call word__40
call word_puts
ret
word_test_2dmmap:
; push 0
sub r12, 8
mov qword [r12], 0
; push 4096
sub r12, 8
mov qword [r12], 4096
; push 3
sub r12, 8
mov qword [r12], 3
; push 34
sub r12, 8
mov qword [r12], 34
; push -1
sub r12, 8
mov qword [r12], -1
; push 0
sub r12, 8
mov qword [r12], 0
call word_mmap
call word_dup
; push 1337
sub r12, 8
mov qword [r12], 1337
call word_swap
call word__21
call word_dup
call word__40
call word_puts
; push 4096
sub r12, 8
mov qword [r12], 4096
call word_munmap
call word_drop
ret
word_test_2dmacro:
; push 9
sub r12, 8
mov qword [r12], 9
call word_dup
call word__2a
call word_puts
call word_MAGIC
call word_puts
call word_add13
call word_puts
ret
word_test_2dif:
; push 5
sub r12, 8
mov qword [r12], 5
; push 5
sub r12, 8
mov qword [r12], 5
call word__3d_3d
mov rax, [r12]
add r12, 8
test rax, rax
jz L_if_false_0
; push 111
sub r12, 8
mov qword [r12], 111
call word_puts
jmp L_if_end_1
L_if_false_0:
; push 222
sub r12, 8
mov qword [r12], 222
call word_puts
L_if_end_1:
ret
word_test_2delse_2dif:
; push 2
sub r12, 8
mov qword [r12], 2
call word_dup
; push 1
sub r12, 8
mov qword [r12], 1
call word__3d_3d
mov rax, [r12]
add r12, 8
test rax, rax
jz L_if_false_2
; push 50
sub r12, 8
mov qword [r12], 50
call word_puts
jmp L_if_end_3
L_if_false_2:
call word_dup
; push 2
sub r12, 8
mov qword [r12], 2
call word__3d_3d
mov rax, [r12]
add r12, 8
test rax, rax
jz L_if_false_4
; push 60
sub r12, 8
mov qword [r12], 60
call word_puts
jmp L_if_end_5
L_if_false_4:
; push 70
sub r12, 8
mov qword [r12], 70
call word_puts
L_if_end_5:
L_if_end_3:
call word_drop
ret
word_test_2dfor:
; push 0
sub r12, 8
mov qword [r12], 0
; push 5
sub r12, 8
mov qword [r12], 5
mov rax, [r12]
add r12, 8
cmp rax, 0
jle L_for_end_7
sub r13, 8
mov [r13], rax
L_for_loop_6:
; push 1
sub r12, 8
mov qword [r12], 1
call word__2b
mov rax, [r13]
dec rax
mov [r13], rax
jg L_for_loop_6
add r13, 8
L_for_end_7:
call word_puts
ret
word_test_2dfor_2dzero:
; push 123
sub r12, 8
mov qword [r12], 123
; push 0
sub r12, 8
mov qword [r12], 0
mov rax, [r12]
add r12, 8
cmp rax, 0
jle L_for_end_9
sub r13, 8
mov [r13], rax
L_for_loop_8:
call word_drop
mov rax, [r13]
dec rax
mov [r13], rax
jg L_for_loop_8
add r13, 8
L_for_end_9:
call word_puts
ret
word_test_2dstruct:
call word_mem_2dslot
call word_dup
; push 111
sub r12, 8
mov qword [r12], 111
call word_swap
call word_Point_2ex_21
call word_dup
; push 222
sub r12, 8
mov qword [r12], 222
call word_swap
call word_Point_2ey_21
call word_dup
call word_Point_2ex_40
call word_puts
call word_Point_2ey_40
call word_puts
call word_Point_2esize
call word_puts
ret
word_test_2dcmp:
; push 5
sub r12, 8
mov qword [r12], 5
; push 5
sub r12, 8
mov qword [r12], 5
call word__3d_3d
call word_puts
; push 5
sub r12, 8
mov qword [r12], 5
; push 4
sub r12, 8
mov qword [r12], 4
call word__3d_3d
call word_puts
; push 5
sub r12, 8
mov qword [r12], 5
; push 4
sub r12, 8
mov qword [r12], 4
call word__21_3d
call word_puts
; push 4
sub r12, 8
mov qword [r12], 4
; push 4
sub r12, 8
mov qword [r12], 4
call word__21_3d
call word_puts
; push 3
sub r12, 8
mov qword [r12], 3
; push 5
sub r12, 8
mov qword [r12], 5
call word__3c
call word_puts
; push 5
sub r12, 8
mov qword [r12], 5
; push 3
sub r12, 8
mov qword [r12], 3
call word__3c
call word_puts
; push 5
sub r12, 8
mov qword [r12], 5
; push 3
sub r12, 8
mov qword [r12], 3
call word__3e
call word_puts
; push 3
sub r12, 8
mov qword [r12], 3
; push 5
sub r12, 8
mov qword [r12], 5
call word__3e
call word_puts
; push 5
sub r12, 8
mov qword [r12], 5
; push 5
sub r12, 8
mov qword [r12], 5
call word__3c_3d
call word_puts
; push 6
sub r12, 8
mov qword [r12], 6
; push 5
sub r12, 8
mov qword [r12], 5
call word__3c_3d
call word_puts
; push 5
sub r12, 8
mov qword [r12], 5
; push 5
sub r12, 8
mov qword [r12], 5
call word__3e_3d
call word_puts
; push 4
sub r12, 8
mov qword [r12], 4
; push 5
sub r12, 8
mov qword [r12], 5
call word__3e_3d
call word_puts
ret
word_test_2dc_2dfn:
; push 3
sub r12, 8
mov qword [r12], 3
; push 7
sub r12, 8
mov qword [r12], 7
call word_fancy_add
call word_puts
ret
word_main:
call word_test_2dadd
call word_test_2dsub
call word_test_2dmul
call word_test_2ddiv
call word_test_2dmod
call word_test_2ddrop
call word_test_2ddup
call word_test_2dswap
call word_test_2dstore
call word_test_2dmmap
call word_test_2dmacro
call word_test_2dif
call word_test_2delse_2dif
call word_test_2dfor
call word_test_2dfor_2dzero
call word_test_2dcmp
call word_test_2dstruct
call word_test_2dc_2dfn
; push 0
sub r12, 8
mov qword [r12], 0
ret
section .bss
align 16
dstack: resb DSTK_BYTES
dstack_top:
align 16
rstack: resb RSTK_BYTES
rstack_top:
align 16
print_buf: resb PRINT_BUF_BYTES
print_buf_end:

BIN
build/test.o Normal file

Binary file not shown.

1108
main.py

File diff suppressed because it is too large Load Diff

10
main.sl
View File

@@ -3,5 +3,13 @@ import stdlib.sl
: main : main
2 40 + 2 40 +
puts puts
extend-syntax
1
2
foo()
puts
0 0
; ;
fn foo(int a, int b){
return a + b;
}

235
stdlib.sl
View File

@@ -47,6 +47,211 @@ puts_finish_digits:
} }
; ;
: extend-syntax
enable-call-syntax
;
immediate
compile-only
:py fn {
FN_SPLIT_CHARS = set("(),{};+-*/%,")
def split_token(token):
lex = token.lexeme
parts = []
idx = 0
while idx < len(lex):
char = lex[idx]
if char in FN_SPLIT_CHARS:
parts.append(Token(
lexeme=char,
line=token.line,
column=token.column + idx,
start=token.start + idx,
end=token.start + idx + 1,
))
idx += 1
continue
start_idx = idx
while idx < len(lex) and lex[idx] not in FN_SPLIT_CHARS:
idx += 1
segment = lex[start_idx:idx]
if segment:
parts.append(Token(
lexeme=segment,
line=token.line,
column=token.column + start_idx,
start=token.start + start_idx,
end=token.start + idx,
))
return [part for part in parts if part.lexeme]
class FnLexer:
def __init__(self, parser):
self.parser = parser
self.buffer = []
def _fill(self):
while not self.buffer:
if self.parser._eof():
raise ParseError("unexpected EOF inside fn definition")
token = self.parser.next_token()
split = split_token(token)
if not split:
continue
self.buffer.extend(split)
def peek(self):
self._fill()
return self.buffer[0]
def pop(self):
token = self.peek()
self.buffer.pop(0)
return token
def expect(self, lexeme):
token = self.pop()
if token.lexeme != lexeme:
raise ParseError(f"expected '{lexeme}' but found '{token.lexeme}'")
return token
def push_back_remaining(self):
if not self.buffer:
return
self.parser.tokens[self.parser.pos:self.parser.pos] = self.buffer
self.buffer = []
def collect_block_tokens(self):
depth = 1
collected = []
while depth > 0:
token = self.pop()
if token.lexeme == "{":
depth += 1
collected.append(token)
continue
if token.lexeme == "}":
depth -= 1
if depth == 0:
break
collected.append(token)
continue
collected.append(token)
return collected
OP_PRECEDENCE = {}
OP_PRECEDENCE["+"] = 1
OP_PRECEDENCE["-"] = 1
OP_PRECEDENCE["*"] = 2
OP_PRECEDENCE["/"] = 2
OP_PRECEDENCE["%"] = 2
def parse_fn_body(tokens):
if not tokens:
raise ParseError("empty function body")
lexemes = [tok.lexeme for tok in tokens if tok.lexeme]
if not lexemes or lexemes[0] != "return":
raise ParseError("function body must start with 'return'")
if lexemes[-1] != ";":
raise ParseError("function body must terminate with ';'")
extra = lexemes[1:-1]
if not extra:
raise ParseError("missing return expression")
return extra
def shunting_yard(tokens):
output = []
stack = []
for token in tokens:
if token == "(":
stack.append(token)
continue
if token == ")":
while stack and stack[-1] != "(":
output.append(stack.pop())
if not stack:
raise ParseError("mismatched parentheses in return expression")
stack.pop()
continue
if token in OP_PRECEDENCE:
while stack and stack[-1] in OP_PRECEDENCE and OP_PRECEDENCE[stack[-1]] >= OP_PRECEDENCE[token]:
output.append(stack.pop())
stack.append(token)
continue
output.append(token)
while stack:
top = stack.pop()
if top == "(":
raise ParseError("mismatched parentheses in return expression")
output.append(top)
return output
def is_int_literal(text):
try:
int(text, 0)
return True
except ValueError:
return False
def translate_postfix(postfix, params):
indices = {name: idx for idx, name in enumerate(params)}
translated = []
for token in postfix:
if token in indices:
translated.append(str(indices[token]))
translated.append("rpick")
continue
if is_int_literal(token):
translated.append(token)
continue
translated.append(token)
return translated
def macro(ctx):
parser = ctx.parser
if not isinstance(parser.context_stack[-1], Module):
raise ParseError("'fn' definitions must be top-level")
lexer = FnLexer(parser)
name_token = lexer.pop()
name = name_token.lexeme
if not is_identifier(name):
raise ParseError("invalid function name for 'fn'")
lexer.expect("(")
params = []
if lexer.peek().lexeme != ")":
while True:
type_token = lexer.pop()
if type_token.lexeme != "int":
raise ParseError("only 'int' parameters are supported in fn definitions")
param_token = lexer.pop()
if not is_identifier(param_token.lexeme):
raise ParseError("invalid parameter name in fn definition")
params.append(param_token.lexeme)
if lexer.peek().lexeme == ",":
lexer.pop()
continue
break
lexer.expect(")")
lexer.expect("{")
body_tokens = lexer.collect_block_tokens()
lexer.push_back_remaining()
if len(params) != len(set(params)):
raise ParseError("duplicate parameter names in fn definition")
return_tokens = parse_fn_body(body_tokens)
postfix = shunting_yard(return_tokens)
body_words = []
for _ in reversed(params):
body_words.append(">r")
body_words.extend(translate_postfix(postfix, params))
for _ in params:
body_words.append("rdrop")
generated = []
emit_definition(generated, name_token, name, body_words)
ctx.inject_token_objects(generated)
}
;
:asm dup { :asm dup {
mov rax, [r12] mov rax, [r12]
sub r12, 8 sub r12, 8
@@ -226,3 +431,33 @@ puts_finish_digits:
syscall syscall
} }
; ;
:asm >r {
mov rax, [r12]
add r12, 8
sub r13, 8
mov [r13], rax
}
;
:asm r> {
mov rax, [r13]
add r13, 8
sub r12, 8
mov [r12], rax
}
;
:asm rdrop {
add r13, 8
}
;
:asm rpick {
mov rcx, [r12]
add r12, 8
mov rax, [r13 + rcx * 8]
sub r12, 8
mov [r12], rax
}
;

BIN
test.bin Executable file

Binary file not shown.

14
test.sl
View File

@@ -31,6 +31,12 @@ struct: Point
field y 8 field y 8
;struct ;struct
extend-syntax
fn fancy_add(int left, int right){
return (left + right) * right;
}
: test-add : test-add
5 7 + puts 5 7 + puts
; ;
@@ -153,6 +159,13 @@ struct: Point
4 5 >= puts 4 5 >= puts
; ;
: test-c-fn
3
7
fancy_add()
puts
;
: main : main
test-add test-add
test-sub test-sub
@@ -171,5 +184,6 @@ struct: Point
test-for-zero test-for-zero
test-cmp test-cmp
test-struct test-struct
test-c-fn
0 0
; ;