This commit is contained in:
Lobo 2026-01-21 13:48:20 -03:00
parent 6a9a0cd4e4
commit d359c68c32
16 changed files with 2026 additions and 89 deletions

4
README
View file

@ -9,3 +9,7 @@
( ) | | ( ) | |
________| _/_ | | ________| _/_ | |
<__________\______)\__) <__________\______)\__)
TODO:
- [ ] "#load" pragma
- [ ] hand-rolled parser

View file

@ -3,7 +3,7 @@ project(
'c', 'c',
meson_version : '>= 1.3.0', meson_version : '>= 1.3.0',
version : '0.1', version : '0.1',
default_options : ['buildtype=debugoptimized', 'c_std=c11', 'warning_level=3'], default_options : ['buildtype=debugoptimized', 'c_std=gnu11', 'warning_level=3'],
) )
sources = [ sources = [
@ -16,6 +16,7 @@ sources = [
'src/gc.c', 'src/gc.c',
'src/parser.c', 'src/parser.c',
'src/print.c', 'src/print.c',
'src/string.c',
'src/vm.c', 'src/vm.c',
'src/vendor/mpc.c', 'src/vendor/mpc.c',
'src/vendor/yar.c', 'src/vendor/yar.c',

View file

@ -8,6 +8,7 @@
#include "gc.h" #include "gc.h"
#include "object.h" #include "object.h"
#include "vm.h" #include "vm.h"
#include "string.h"
#include "vendor/mpc.h" #include "vendor/mpc.h"
@ -26,10 +27,10 @@ struct {
{"dig", {OP_DIG, 0}}, {"dig", {OP_DIG, 0}},
{">r", {OP_TOR, 0}}, {">r", {OP_TOR, 0}},
{"r>", {OP_FROMR, 0}}, {"r>", {OP_FROMR, 0}},
{"dip", {OP_SWAP, OP_TOR, OP_APPLY, OP_FROMR, 0}}, {"dip", {OP_SWAP, OP_TOR, OP_CALL, OP_FROMR, 0}},
{"keep", {OP_OVER, OP_TOR, OP_APPLY, OP_FROMR, 0}}, {"keep", {OP_OVER, OP_TOR, OP_CALL, OP_FROMR, 0}},
{"if", {OP_CHOOSE, OP_APPLY, 0}}, {"if", {OP_CHOOSE, OP_CALL, 0}},
{"call", {OP_APPLY, 0}}, {"call", {OP_CALL, 0}},
{"?", {OP_CHOOSE, 0}}, {"?", {OP_CHOOSE, 0}},
{"+", {OP_ADD, 0}}, {"+", {OP_ADD, 0}},
{"-", {OP_SUB, 0}}, {"-", {OP_SUB, 0}},
@ -42,7 +43,10 @@ struct {
{">", {OP_GT, 0}}, {">", {OP_GT, 0}},
{"<=", {OP_LTE, 0}}, {"<=", {OP_LTE, 0}},
{">=", {OP_GTE, 0}}, {">=", {OP_GTE, 0}},
{"type", {OP_TYPE, 0}},
{"^", {OP_CONCAT, 0}},
{".", {OP_PPRINT, 0}}, {".", {OP_PPRINT, 0}},
{".s", {OP_PRINTSTACK, 0}},
{NULL, {0}}, {NULL, {0}},
}; };
// clang-format on // clang-format on
@ -82,28 +86,20 @@ static V optim_tailcall(Bc *chunk) {
Z i = 0; Z i = 0;
while (i < chunk->count) { while (i < chunk->count) {
U8 opcode = chunk->items[i]; U8 opcode = chunk->items[i];
if (opcode == OP_CALL) { if (opcode == OP_DOWORD) {
I ofs = peek_sleb128(&chunk->items[i + 1], NULL);
Z next = i + 1 + ofs;
if (next < chunk->count && chunk->items[next] == OP_RETURN) {
chunk->items[i] = OP_TAIL_CALL;
}
i++;
} else if (opcode == OP_DOWORD) {
I ofs = peek_sleb128(&chunk->items[i + 1], NULL); I ofs = peek_sleb128(&chunk->items[i + 1], NULL);
Z next = i + 1 + ofs; Z next = i + 1 + ofs;
if (next < chunk->count && chunk->items[next] == OP_RETURN) { if (next < chunk->count && chunk->items[next] == OP_RETURN) {
chunk->items[i] = OP_TAIL_DOWORD; chunk->items[i] = OP_TAIL_DOWORD;
} }
i++; i++;
} else if (opcode == OP_APPLY) { } else if (opcode == OP_CALL) {
Z ofs = i + 1; Z ofs = i + 1;
if (ofs < chunk->count && chunk->items[ofs] == OP_RETURN) { if (ofs < chunk->count && chunk->items[ofs] == OP_RETURN) {
chunk->items[i] = OP_TAIL_APPLY; chunk->items[i] = OP_TAIL_CALL;
} }
i++; i++;
} else if (opcode == OP_CONST || opcode == OP_JUMP || } else if (opcode == OP_CONST) {
opcode == OP_JUMP_IF_NIL) {
I ofs = peek_sleb128(&chunk->items[i + 1], NULL); I ofs = peek_sleb128(&chunk->items[i + 1], NULL);
i += 1 + ofs; i += 1 + ofs;
} else { } else {
@ -240,6 +236,14 @@ static I compile_expr(Cm *cm, mpc_ast_t *curr, mpc_ast_trav_t **next) {
if (strstr(curr->tag, "expr|number") != NULL) { if (strstr(curr->tag, "expr|number") != NULL) {
I num = strtol(curr->contents, NULL, 0); I num = strtol(curr->contents, NULL, 0);
return compile_constant(cm, NUM(num), line, col); return compile_constant(cm, NUM(num), line, col);
} else if (strstr(curr->tag, "expr|string") != NULL) {
curr->contents[strlen(curr->contents) - 1] = '\0';
char *unescaped = malloc(strlen(curr->contents + 1) + 1);
strcpy(unescaped, curr->contents + 1);
unescaped = mpcf_unescape(unescaped);
O obj = string_make(cm->vm, unescaped, -1);
free(unescaped);
return compile_constant(cm, obj, line, col);
} else if (strstr(curr->tag, "expr|word") != NULL) { } else if (strstr(curr->tag, "expr|word") != NULL) {
return compile_call(cm, curr->contents, line, col); return compile_call(cm, curr->contents, line, col);
} else if (strstr(curr->tag, "expr|quotation") != NULL) { } else if (strstr(curr->tag, "expr|quotation") != NULL) {

View file

@ -91,24 +91,6 @@ static Z dis_instr(Bc *chunk, Z offset, Dt **dictionary, I indent) {
SIMPLE(DIG); SIMPLE(DIG);
SIMPLE(TOR); SIMPLE(TOR);
SIMPLE(FROMR); SIMPLE(FROMR);
CASE(JUMP) {
Z bytes_read;
I ofs = decode_sleb128(&chunk->items[offset], &bytes_read);
printf("JUMP %ld -> %zu\n", ofs, offset + bytes_read + ofs);
return offset + bytes_read;
}
CASE(JUMP_IF_NIL) {
Z bytes_read;
I ofs = decode_sleb128(&chunk->items[offset], &bytes_read);
printf("JUMP_IF_NIL %ld -> %zu\n", ofs, offset + bytes_read + ofs);
return offset + bytes_read;
}
CASE(CALL) {
Z bytes_read;
I ofs = decode_sleb128(&chunk->items[offset], &bytes_read);
printf("CALL %ld\n", ofs);
return offset + bytes_read;
}
CASE(DOWORD) { CASE(DOWORD) {
Z bytes_read; Z bytes_read;
I hash = decode_sleb128(&chunk->items[offset], &bytes_read); I hash = decode_sleb128(&chunk->items[offset], &bytes_read);
@ -127,13 +109,7 @@ static Z dis_instr(Bc *chunk, Z offset, Dt **dictionary, I indent) {
printf("\n"); printf("\n");
return offset + bytes_read; return offset + bytes_read;
} }
SIMPLE(APPLY); SIMPLE(CALL);
CASE(TAIL_CALL) {
Z bytes_read;
I ofs = decode_sleb128(&chunk->items[offset], &bytes_read);
printf("TAIL_CALL %ld\n", ofs);
return offset + bytes_read;
}
CASE(TAIL_DOWORD) { CASE(TAIL_DOWORD) {
Z bytes_read; Z bytes_read;
I hash = decode_sleb128(&chunk->items[offset], &bytes_read); I hash = decode_sleb128(&chunk->items[offset], &bytes_read);
@ -152,7 +128,7 @@ static Z dis_instr(Bc *chunk, Z offset, Dt **dictionary, I indent) {
printf("\n"); printf("\n");
return offset + bytes_read; return offset + bytes_read;
} }
SIMPLE(TAIL_APPLY); SIMPLE(TAIL_CALL);
SIMPLE(RETURN); SIMPLE(RETURN);
SIMPLE(CHOOSE); SIMPLE(CHOOSE);
SIMPLE(ADD); SIMPLE(ADD);
@ -166,7 +142,10 @@ static Z dis_instr(Bc *chunk, Z offset, Dt **dictionary, I indent) {
SIMPLE(GT); SIMPLE(GT);
SIMPLE(LTE); SIMPLE(LTE);
SIMPLE(GTE); SIMPLE(GTE);
SIMPLE(TYPE);
SIMPLE(CONCAT);
SIMPLE(PPRINT); SIMPLE(PPRINT);
SIMPLE(PRINTSTACK);
default: default:
printf("??? (%d)\n", opcode); printf("??? (%d)\n", opcode);
return offset; return offset;

View file

@ -6,8 +6,8 @@
#include "chunk.h" #include "chunk.h"
#include "gc.h" #include "gc.h"
#include "object.h" #include "object.h"
#include "vm.h"
#include "vendor/yar.h" #include "vendor/yar.h"
#include "vm.h"
#define ALIGN(n) (((n) + 7) & ~7) #define ALIGN(n) (((n) + 7) & ~7)
static inline int infrom(Gc *gc, V *ptr) { static inline int infrom(Gc *gc, V *ptr) {
@ -67,7 +67,6 @@ V gc_collect(Vm *vm) {
printstats(gc, "before GC"); printstats(gc, "before GC");
#endif #endif
// Forward roots
for (Z i = 0; i < gc->roots.count; i++) { for (Z i = 0; i < gc->roots.count; i++) {
O *o = gc->roots.items[i]; O *o = gc->roots.items[i];
*o = forward(gc, *o); *o = forward(gc, *o);

View file

@ -13,6 +13,7 @@
enum { enum {
OBJ_FWD = 2, OBJ_FWD = 2,
OBJ_QUOT, OBJ_QUOT,
OBJ_STR,
}; };
enum { enum {
@ -20,6 +21,7 @@ enum {
TYPE_NUM = 1, TYPE_NUM = 1,
TYPE_FWD = OBJ_FWD, TYPE_FWD = OBJ_FWD,
TYPE_QUOT = OBJ_QUOT, TYPE_QUOT = OBJ_QUOT,
TYPE_STR = OBJ_STR,
}; };
typedef uintptr_t O; typedef uintptr_t O;
@ -29,12 +31,6 @@ typedef struct Hd {
U32 size, type; U32 size, type;
} Hd; } Hd;
/** String */
typedef struct Str {
Z len;
char data[];
} Str;
I type(O); I type(O);
#endif #endif

View file

@ -2,6 +2,7 @@
#include <stdio.h> #include <stdio.h>
#include "object.h" #include "object.h"
#include "string.h"
#include "print.h" #include "print.h"
V print(O o) { V print(O o) {
@ -10,10 +11,16 @@ V print(O o) {
} else if (IMM(o)) { } else if (IMM(o)) {
printf("%" PRIdPTR, ORD(o)); printf("%" PRIdPTR, ORD(o));
} else { } else {
switch (type(o)) { Hd *hdr = UNBOX(o);
case TYPE_QUOT: switch (hdr->type) {
case OBJ_QUOT:
printf("<quotation>"); printf("<quotation>");
break; break;
case OBJ_STR: {
Str *s = string_unwrap(o);
printf("\"%.*s\"", (int)s->len, s->data);
break;
}
default: default:
printf("<obj type=%ld ptr=%p>", type(o), (void *)o); printf("<obj type=%ld ptr=%p>", type(o), (void *)o);
} }

36
src/string.c Normal file
View file

@ -0,0 +1,36 @@
#include <string.h>
#include "string.h"
O string_make(Vm *vm, const char *str, I len) {
if (len < 0)
len = strlen(str);
Z size = sizeof(Hd) + sizeof(Str) + len + 1;
Hd *hdr = gc_alloc(vm, size);
hdr->type = OBJ_STR;
Str *s = (Str *)(hdr + 1);
s->len = len;
memcpy(s->data, str, len);
s->data[len] = 0;
return BOX(hdr);
}
Str *string_unwrap(O o) {
if (o == NIL || IMM(o))
return NULL;
Hd *hdr = UNBOX(o);
if (hdr->type != OBJ_STR)
return NULL;
return (Str *)(hdr + 1);
}
O string_concat(Vm *vm, Str *a, Str *b) {
O new_obj = string_make(vm, "", a->len + b->len);
Str *new = (Str *)(UNBOX(new_obj) + 1);
memcpy(new->data, a->data, a->len);
memcpy(new->data + a->len, b->data, b->len);
new->data[a->len + b->len] = 0;
return new_obj;
}

13
src/string.h Normal file
View file

@ -0,0 +1,13 @@
#include "common.h"
#include "object.h"
#include "vm.h"
/** String */
typedef struct Str {
Z len;
char data[];
} Str;
O string_make(Vm *, const char *, I);
Str *string_unwrap(O);
O string_concat(Vm *, Str *, Str *);

View file

View file

1763
src/vendor/linenoise.c vendored Normal file

File diff suppressed because it is too large Load diff

114
src/vendor/linenoise.h vendored Normal file
View file

@ -0,0 +1,114 @@
/* linenoise.h -- VERSION 1.0
*
* Guerrilla line editing library against the idea that a line editing lib
* needs to be 20,000 lines of C code.
*
* See linenoise.c for more information.
*
* ------------------------------------------------------------------------
*
* Copyright (c) 2010-2023, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __LINENOISE_H
#define __LINENOISE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h> /* For size_t. */
extern char *linenoiseEditMore;
/* The linenoiseState structure represents the state during line editing.
* We pass this state to functions implementing specific editing
* functionalities. */
struct linenoiseState {
int in_completion; /* The user pressed TAB and we are now in completion
* mode, so input is handled by completeLine(). */
size_t completion_idx; /* Index of next completion to propose. */
int ifd; /* Terminal stdin file descriptor. */
int ofd; /* Terminal stdout file descriptor. */
char *buf; /* Edited line buffer. */
size_t buflen; /* Edited line buffer size. */
const char *prompt; /* Prompt to display. */
size_t plen; /* Prompt length. */
size_t pos; /* Current cursor position. */
size_t oldpos; /* Previous refresh cursor position. */
size_t len; /* Current edited line length. */
size_t cols; /* Number of columns in terminal. */
size_t oldrows; /* Rows used by last refrehsed line (multiline mode) */
int oldrpos; /* Cursor row from last refresh (for multiline clearing). */
int history_index; /* The history index we are currently editing. */
};
typedef struct linenoiseCompletions {
size_t len;
char **cvec;
} linenoiseCompletions;
/* Non blocking API. */
int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt);
char *linenoiseEditFeed(struct linenoiseState *l);
void linenoiseEditStop(struct linenoiseState *l);
void linenoiseHide(struct linenoiseState *l);
void linenoiseShow(struct linenoiseState *l);
/* Blocking API. */
char *linenoise(const char *prompt);
void linenoiseFree(void *ptr);
/* Completion API. */
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
typedef void(linenoiseFreeHintsCallback)(void *);
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
/* History API. */
int linenoiseHistoryAdd(const char *line);
int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename);
/* Other utilities. */
void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml);
void linenoisePrintKeyCodes(void);
void linenoiseMaskModeEnable(void);
void linenoiseMaskModeDisable(void);
#ifdef __cplusplus
}
#endif
#endif /* __LINENOISE_H */

View file

@ -8,6 +8,7 @@
#include "gc.h" #include "gc.h"
#include "object.h" #include "object.h"
#include "print.h" #include "print.h"
#include "string.h"
#include "vm.h" #include "vm.h"
static I decode_sleb128(U8 **ptr) { static I decode_sleb128(U8 **ptr) {
@ -207,23 +208,6 @@ I vm_run(Vm *vm, Bc *chunk, I offset) {
vm_push(vm, vm_tpop(vm)); vm_push(vm, vm_tpop(vm));
break; break;
} }
case OP_JUMP: {
I ofs = decode_sleb128(&vm->ip);
vm->ip += ofs;
break;
}
case OP_JUMP_IF_NIL: {
I ofs = decode_sleb128(&vm->ip);
if (vm_pop(vm) == NIL)
vm->ip += ofs;
break;
}
case OP_CALL: {
I ofs = decode_sleb128(&vm->ip);
vm_rpush(vm, vm->chunk, vm->ip);
vm->ip = chunk->items + ofs;
break;
}
case OP_DOWORD: { case OP_DOWORD: {
I hash = decode_sleb128(&vm->ip); I hash = decode_sleb128(&vm->ip);
Dt *word = lookup_hash(&vm->dictionary, hash); Dt *word = lookup_hash(&vm->dictionary, hash);
@ -234,7 +218,7 @@ I vm_run(Vm *vm, Bc *chunk, I offset) {
vm->ip = word->chunk->items; vm->ip = word->chunk->items;
break; break;
} }
case OP_APPLY: { case OP_CALL: {
O quot = vm_pop(vm); O quot = vm_pop(vm);
if (type(quot) == TYPE_QUOT) { if (type(quot) == TYPE_QUOT) {
Bc **ptr = (Bc **)(UNBOX(quot) + 1); Bc **ptr = (Bc **)(UNBOX(quot) + 1);
@ -243,15 +227,10 @@ I vm_run(Vm *vm, Bc *chunk, I offset) {
vm->chunk = chunk; vm->chunk = chunk;
vm->ip = chunk->items; vm->ip = chunk->items;
} else { } else {
vm_error(vm, VM_ERR_TYPE, "attempt to apply non-quotation object"); vm_error(vm, VM_ERR_TYPE, "attempt to call non-quotation object");
} }
break; break;
} }
case OP_TAIL_CALL: {
I ofs = decode_sleb128(&vm->ip);
vm->ip = chunk->items + ofs;
break;
}
case OP_TAIL_DOWORD: { case OP_TAIL_DOWORD: {
I hash = decode_sleb128(&vm->ip); I hash = decode_sleb128(&vm->ip);
Dt *word = lookup_hash(&vm->dictionary, hash); Dt *word = lookup_hash(&vm->dictionary, hash);
@ -261,7 +240,7 @@ I vm_run(Vm *vm, Bc *chunk, I offset) {
vm->ip = word->chunk->items; vm->ip = word->chunk->items;
break; break;
} }
case OP_TAIL_APPLY: { case OP_TAIL_CALL: {
O quot = vm_pop(vm); O quot = vm_pop(vm);
if (type(quot) == TYPE_QUOT) { if (type(quot) == TYPE_QUOT) {
Bc **ptr = (Bc **)(UNBOX(quot) + 1); Bc **ptr = (Bc **)(UNBOX(quot) + 1);
@ -269,7 +248,7 @@ I vm_run(Vm *vm, Bc *chunk, I offset) {
vm->chunk = chunk; vm->chunk = chunk;
vm->ip = chunk->items; vm->ip = chunk->items;
} else { } else {
vm_error(vm, VM_ERR_TYPE, "attempt to apply non-quotation object\n"); vm_error(vm, VM_ERR_TYPE, "attempt to call non-quotation object\n");
} }
break; break;
} }
@ -315,11 +294,37 @@ I vm_run(Vm *vm, Bc *chunk, I offset) {
CMPOP(<=); CMPOP(<=);
case OP_GTE: case OP_GTE:
CMPOP(>=); CMPOP(>=);
case OP_CONCAT: {
Str *b = string_unwrap(vm_pop(vm));
if (b == NULL)
vm_error(vm, VM_ERR_TYPE, "expected string");
Str *a = string_unwrap(vm_pop(vm));
if (a == NULL)
vm_error(vm, VM_ERR_TYPE, "expected string");
vm_push(vm, string_concat(vm, a, b));
break;
}
case OP_TYPE: {
Str *s = string_unwrap(vm_pop(vm));
if (s == NULL)
vm_error(vm, VM_ERR_TYPE, "expected string");
printf("%.*s", (int)s->len, s->data);
break;
}
case OP_PPRINT: { case OP_PPRINT: {
O obj = vm_pop(vm); O obj = vm_pop(vm);
println(obj); println(obj);
break; break;
} }
case OP_PRINTSTACK: {
printf("Stk:");
for (O *p = vm->stack; p < vm->sp; p++) {
putchar(' ');
print(*p);
}
putchar('\n');
break;
}
default: default:
vm_error(vm, VM_ERR_RUNTIME, "unknown opcode"); vm_error(vm, VM_ERR_RUNTIME, "unknown opcode");
} }

View file

@ -1,6 +1,8 @@
#ifndef VM_H #ifndef VM_H
#define VM_H #define VM_H
#include <setjmp.h>
#include "common.h" #include "common.h"
#include "arena.h" #include "arena.h"
@ -8,7 +10,6 @@
#include "dictionary.h" #include "dictionary.h"
#include "gc.h" #include "gc.h"
#include "object.h" #include "object.h"
#include <setjmp.h>
enum { enum {
OP_NOP = 0, OP_NOP = 0,
@ -23,14 +24,10 @@ enum {
OP_DIG, OP_DIG,
OP_TOR, // Push from stack to retain stack OP_TOR, // Push from stack to retain stack
OP_FROMR, // Push from retain stack to stack OP_FROMR, // Push from retain stack to stack
OP_JUMP, // Relative jump
OP_JUMP_IF_NIL, // Relative jump if top-of-stack is nil
OP_CALL,
OP_DOWORD, // Call word from dictionary by name hash OP_DOWORD, // Call word from dictionary by name hash
OP_APPLY, OP_CALL,
OP_TAIL_CALL, // Tail call within chunk (reuses current frame)
OP_TAIL_DOWORD, // Tail call to dictionary word (reuses current frame) OP_TAIL_DOWORD, // Tail call to dictionary word (reuses current frame)
OP_TAIL_APPLY, // Tail call to quotation (reuses current frame) OP_TAIL_CALL, // Tail call to quotation (reuses current frame)
OP_RETURN, OP_RETURN,
OP_CHOOSE, OP_CHOOSE,
OP_ADD, OP_ADD,
@ -44,7 +41,10 @@ enum {
OP_GT, OP_GT,
OP_LTE, OP_LTE,
OP_GTE, OP_GTE,
OP_TYPE,
OP_CONCAT,
OP_PPRINT, OP_PPRINT,
OP_PRINTSTACK,
}; };
#define STACK_SIZE 256 #define STACK_SIZE 256

View file

@ -1,9 +1,25 @@
def fib/aux { def fib/aux {
if: dig dup 0 = if: dig dup 0 =
[drop drop] [drop drop]
[bury [swap 1 - swap] dip dup [+] dip swap fib/aux] [bury [swap 1 - swap] dip dup [+] dip swap fib/aux];
;
} }
def fib { 0 1 fib/aux } def fib { 0 1 fib/aux }
[ 50 fib ] call . "50 fib => " type
50 fib .
def times {
if: over 0 =
[drop drop]
[swap over >r >r call r> 1 - r> times];
}
\ We can also calculate the Fibonnaci numbers using the `times' combinator
\ we just implemented:
def fib-iter {
0 1 dig times: [dup [+] dip swap]; drop
}
"50 fib-iter => " type
50 fib-iter .