kuroko: integrated language runtime support

This commit is contained in:
K. Lange 2023-05-30 08:05:56 +09:00
parent a627c732d5
commit 4291a61a92
60 changed files with 4063 additions and 2 deletions

1
.gitignore vendored
View File

@ -44,3 +44,4 @@
/common-uefi-riscv64
/decompressor-build
/stage1.stamp
/kuroko

View File

@ -25,6 +25,7 @@ fi
[ -d freestanding-headers ] || git clone https://github.com/mintsuki/freestanding-headers.git $SHALLOW_CLONE_FLAG
[ -d limine-efi ] || git clone https://github.com/limine-bootloader/limine-efi.git $SHALLOW_CLONE_FLAG
[ -d libgcc-binaries ] || git clone https://github.com/mintsuki/libgcc-binaries.git $SHALLOW_CLONE_FLAG
[ -d kuroko ] || git clone https://github.com/kuroko-lang/kuroko.git $SHALLOW_CLONE_FLAG
mkdir -p build-aux
cp "$(automake --print-libdir)/install-sh" build-aux

View File

@ -70,6 +70,9 @@ override CPPFLAGS_FOR_TARGET := \
-MMD \
-MP
$(call MKESCAPE,$(BUILDDIR))/./kuroko/%.o: override CFLAGS_FOR_TARGET += -DKRK_STATIC_ONLY -DKRK_DISABLE_THREADS -DKRK_NO_FILESYSTEM -DKRK_NO_CALLGRIND -DKRK_NO_SOURCE_IN_TRACEBACK -DKRK_NO_FLOAT -DKRK_NO_GC_TRACING -Wno-shadow -Wno-unused-parameter -Wno-misleading-indentation
$(call MKESCAPE,$(BUILDDIR))/./kuroko/%.o: override CPPFLAGS_FOR_TARGET += -I'$(call SHESCAPE,$(BUILDDIR))/../kuroko-inc'
ifeq ($(TARGET),bios)
override CFLAGS_FOR_TARGET += \
-fno-PIE \
@ -200,7 +203,7 @@ ifeq ($(TARGET),uefi-riscv64)
-z text
endif
override C_FILES := $(shell find . -type f -name '*.c')
override C_FILES := $(shell find . -xtype f -name '*.c')
ifeq ($(TARGET),bios)
override ASMX86_FILES := $(shell find . -type f -name '*.asm_x86')
override ASM32_FILES := $(shell find . -type f -name '*.asm_ia32')

View File

@ -2,6 +2,7 @@
#include <stdint.h>
#include <config.h>
#include <console.h>
#include <kuroko-limine.h>
#include <menu.h>
#include <mm/pmm.h>
#include <lib/print.h>
@ -18,6 +19,7 @@ static void console_help(void) {
"exit -- Exit Limine console.\n"
"clear -- Clear the console.\n"
"%s"
"kuroko -- Start a Kuroko repl.\n"
"lsvol -- List volumes.\n"
"version -- Print version.\n"
"copyright -- Print copyright.\n"
@ -55,6 +57,8 @@ void console(void) {
print(LIMINE_COPYRIGHT "\n");
print("Limine is distributed under the terms of the BSD-2-Clause license.\n");
print("There is ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n");
} else if (strcmp(prompt, "kuroko") == 0) {
limine_krk_enter_repl();
} else if (*prompt != 0) {
print("Invalid command: `%s`.\n", prompt);
}

View File

@ -16,6 +16,7 @@
#include <fs/file.h>
#include <lib/elf.h>
#include <mm/pmm.h>
#include <kuroko-limine.h>
#include <menu.h>
#include <pxe/pxe.h>
#include <pxe/tftp.h>
@ -130,6 +131,8 @@ noreturn void stage3_common(void) {
init_io_apics();
#endif
limine_krk_init();
term_notready();
menu(true);

8
common/kuroko-limine.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __KUROKO_LIMINE_H__
#define __KUROKO_LIMINE_H__
void limine_krk_init(void);
void limine_krk_enter_repl(void);
void limine_krk_cleanup(void);
#endif

1
common/kuroko/builtins.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/builtins.c

1
common/kuroko/chunk.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/chunk.c

1
common/kuroko/compiler.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/compiler.c

1
common/kuroko/debug.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/debug.c

1
common/kuroko/exceptions.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/exceptions.c

198
common/kuroko/limine-os.c Normal file
View File

@ -0,0 +1,198 @@
/**
* @file limine-os.c
* @brief Limine bindings for os, time, fileio modules.
*
*/
#include <config.h>
#include <menu.h>
#include <lib/print.h>
#include <lib/config.h>
#include <lib/time.h>
#include <lib/readline.h>
#include <mm/pmm.h>
#include <kuroko/vm.h>
#include <kuroko/util.h>
extern int krk_exitRepl;
extern void krk_repl(void);
KRK_Function(uname) {
KrkValue result = krk_dict_of(0, NULL, 0);
krk_push(result);
krk_attachNamedObject(AS_DICT(result), "sysname", (KrkObj*)S("Limine"));
krk_attachNamedObject(AS_DICT(result), "release", (KrkObj*)S(LIMINE_VERSION));
krk_attachNamedObject(AS_DICT(result), "nodename", (KrkObj*)S(""));
krk_attachNamedObject(AS_DICT(result), "version", (KrkObj*)
#if defined(BIOS)
S("BIOS")
#elif defined(UEFI)
S("UEFI")
#else
S("")
#endif
);
krk_attachNamedObject(AS_DICT(result), "machine", (KrkObj*)
#if defined(__x86_64__)
S("x86-64")
#elif defined(__aarch64__)
S("aarch64")
#elif defined(__i386__)
S("i386")
#elif defined(__riscv64)
S("riscv64")
#else
S("unknown")
#endif
);
return krk_pop();
}
/**
* def config_get_value(key: str, index: int = 0, config: str = None) -> str
*/
KRK_Function(config_get_value) {
char * config = NULL;
char * key = NULL;
size_t index = 0;
if (!krk_parseArgs("s|Nz", (const char*[]){"key", "index", "config"}, &key, &index, &config)) return NONE_VAL();
char * value = config_get_value(config, index, key);
if (!value) {
return NONE_VAL();
}
return OBJECT_VAL(krk_copyString(value, strlen(value)));
}
/**
* def boot(config: str) -> does not return
*/
KRK_Function(boot) {
char * config = NULL;
if (!krk_parseArgs("s", (const char*[]){"config"}, &config)) return NONE_VAL();
boot(config);
}
/**
* def getchar() -> int
*/
KRK_Function(getchar) {
return INTEGER_VAL(getchar());
}
/**
* def readline(prefix="",bufsize=1024) -> str
*/
KRK_Function(readline) {
int size = 1024;
char * prefix = "";
if (!krk_parseArgs("|si", (const char*[]){"prefix","bufsize"}, &prefix, &size)) return NONE_VAL();
char * buf = malloc(size);
readline(prefix,buf,size);
krk_push(OBJECT_VAL(krk_copyString(buf,strlen(buf))));
free(buf);
return krk_pop();
}
/**
* Builtins
*/
KRK_Function(exit) {
krk_exitRepl = 1;
return NONE_VAL();
}
KRK_Function(clear) {
print("\e[2J\e[H");
return NONE_VAL();
}
void krk_module_init_os(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "os", (KrkObj*)module);
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("os"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
BIND_FUNC(module,uname);
/* Let's also make a Limine-specific module */
KrkInstance * limine = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "limine", (KrkObj*)limine);
krk_attachNamedObject(&limine->fields, "__name__", (KrkObj*)S("limine"));
krk_attachNamedValue(&limine->fields, "__file__", NONE_VAL());
BIND_FUNC(limine,config_get_value);
BIND_FUNC(limine,boot);
BIND_FUNC(limine,getchar);
BIND_FUNC(limine,readline);
/* And some builtins */
BIND_FUNC(vm.builtins,exit);
BIND_FUNC(vm.builtins,clear);
}
KRK_Function(time) {
/* We don't have floats, so just return an int; 48 bits should be enough */
return INTEGER_VAL(time());
}
void krk_module_init_time(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "time", (KrkObj*)module);
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("time"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
BIND_FUNC(module,time);
}
void krk_module_init_fileio(void) {
/* Nope. Maybe later. */
}
/**
* @brief Initialize the Kuroko VM state and prep the @c limine module.
*/
void limine_krk_init(void) {
krk_initVM(0);
krk_startModule("__main__");
krk_interpret(
"if True:\n"
" import limine\n"
" def config(modules=[],**kwargs):\n"
" let args = [f'{k.upper()}={v}' for k,v in kwargs.items()]\n"
" for module in modules:\n"
" args.append(f'MODULE_PATH={module}')\n"
" return '\\n'.join(args)\n"
" limine.config = config\n",
"<stdin>");
}
/**
* @brief Start a repl session.
*/
void limine_krk_enter_repl(void) {
/* Print version number. */
krk_interpret(
"if True:\n"
" import kuroko\n"
" print(f'Kuroko {kuroko.version} ({kuroko.builddate}) with {kuroko.buildenv}')\n"
" print('Type `help` for guidance, `exit()` to quit.')\n",
"<stdin>");
/* Run the repl */
krk_repl();
}
/**
* @brief Cleanup VM resources.
*/
void limine_krk_cleanup(void) {
/* Free the VM resources; we never actually release the heap, so this doesn't really do anything,
* but the heap is shared through multiple Kuroko sessions, so freeing it is still useful. */
krk_freeVM();
}

211
common/kuroko/malloc.c Normal file
View File

@ -0,0 +1,211 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <mm/pmm.h>
static void * sbrk(size_t s) {
return ext_mem_alloc_type_aligned(s, MEMMAP_BOOTLOADER_RECLAIMABLE, 4096);
}
#if defined(__x86_64__) || defined(__aarch64__) || defined(__riscv64)
#define NUM_BINS 10U /* Number of bins, total, under 64-bit. */
#define SMALLEST_BIN_LOG 3U /* Logarithm base two of the smallest bin: log_2(sizeof(int32)). */
#else
#define NUM_BINS 11U /* Number of bins, total, under 32-bit. */
#define SMALLEST_BIN_LOG 2U /* Logarithm base two of the smallest bin: log_2(sizeof(int32)). */
#endif
#define BIG_BIN (NUM_BINS - 1) /* Index for the big bin, (NUM_BINS - 1) */
#define SMALLEST_BIN (1UL << SMALLEST_BIN_LOG) /* Size of the smallest bin. */
#define PAGE_SIZE 0x1000 /* Size of a page (in bytes), should be 4KB */
#define PAGE_MASK (PAGE_SIZE - 1) /* Block mask, size of a page * number of pages - 1. */
#define BIN_MAGIC 0xDEFAD00D
static void * __attribute__ ((malloc)) klmalloc(uintptr_t size);
static void * __attribute__ ((malloc)) klrealloc(void * ptr, uintptr_t size);
static void * __attribute__ ((malloc)) klcalloc(uintptr_t nmemb, uintptr_t size);
static void klfree(void * ptr);
void * __attribute__ ((malloc)) malloc(uintptr_t size) {
return klmalloc(size);
}
void * __attribute__ ((malloc)) realloc(void * ptr, uintptr_t size) {
return klrealloc(ptr, size);
}
void * __attribute__ ((malloc)) calloc(uintptr_t nmemb, uintptr_t size) {
return klcalloc(nmemb, size);
}
void free(void * ptr) {
klfree(ptr);
}
static inline uintptr_t __attribute__ ((always_inline, pure)) klmalloc_adjust_bin(uintptr_t bin)
{
if (bin <= (uintptr_t)SMALLEST_BIN_LOG)
{
return 0;
}
bin -= SMALLEST_BIN_LOG + 1;
if (bin > (uintptr_t)BIG_BIN) {
return BIG_BIN;
}
return bin;
}
static inline uintptr_t __attribute__ ((always_inline, pure)) klmalloc_bin_size(uintptr_t size) {
uintptr_t bin = sizeof(size) * 8 - __builtin_clzl(size);
bin += !!(size & (size - 1));
return klmalloc_adjust_bin(bin);
}
typedef struct _klmalloc_bin_header {
struct _klmalloc_bin_header * next; /* Pointer to the next node. */
void * head; /* Head of this bin. */
uintptr_t size; /* Size of this bin, if big; otherwise bin index. */
uint32_t bin_magic;
} klmalloc_bin_header;
typedef struct _klmalloc_bin_header_head {
klmalloc_bin_header * first;
} klmalloc_bin_header_head;
static klmalloc_bin_header_head klmalloc_bin_head[NUM_BINS - 1]; /* Small bins */
static inline void __attribute__ ((always_inline)) klmalloc_list_decouple(klmalloc_bin_header_head *head, klmalloc_bin_header *node) {
klmalloc_bin_header *next = node->next;
head->first = next;
node->next = NULL;
}
static inline void __attribute__ ((always_inline)) klmalloc_list_insert(klmalloc_bin_header_head *head, klmalloc_bin_header *node) {
node->next = head->first;
head->first = node;
}
static inline klmalloc_bin_header * __attribute__ ((always_inline)) klmalloc_list_head(klmalloc_bin_header_head *head) {
return head->first;
}
static void * klmalloc_stack_pop(klmalloc_bin_header *header) {
void *item = header->head;
uintptr_t **head = header->head;
uintptr_t *next = *head;
header->head = next;
return item;
}
static void klmalloc_stack_push(klmalloc_bin_header *header, void *ptr) {
uintptr_t **item = (uintptr_t **)ptr;
*item = (uintptr_t *)header->head;
header->head = item;
}
static inline int __attribute__ ((always_inline)) klmalloc_stack_empty(klmalloc_bin_header *header) {
return header->head == NULL;
}
static void * __attribute__ ((malloc)) klmalloc(uintptr_t size) {
if (__builtin_expect(size == 0, 0))
return NULL;
unsigned int bucket_id = klmalloc_bin_size(size);
if (bucket_id < BIG_BIN) {
klmalloc_bin_header * bin_header = klmalloc_list_head(&klmalloc_bin_head[bucket_id]);
if (!bin_header) {
bin_header = (klmalloc_bin_header*)sbrk(PAGE_SIZE);
bin_header->bin_magic = BIN_MAGIC;
bin_header->head = (void*)((uintptr_t)bin_header + sizeof(klmalloc_bin_header));
klmalloc_list_insert(&klmalloc_bin_head[bucket_id], bin_header);
uintptr_t adj = SMALLEST_BIN_LOG + bucket_id;
uintptr_t i, available = ((PAGE_SIZE - sizeof(klmalloc_bin_header)) >> adj) - 1;
uintptr_t **base = bin_header->head;
for (i = 0; i < available; ++i) {
base[i << bucket_id] = (uintptr_t *)&base[(i + 1) << bucket_id];
}
base[available << bucket_id] = NULL;
bin_header->size = bucket_id;
}
uintptr_t ** item = klmalloc_stack_pop(bin_header);
if (klmalloc_stack_empty(bin_header)) {
klmalloc_list_decouple(&(klmalloc_bin_head[bucket_id]),bin_header);
}
return item;
} else {
uintptr_t pages = (size + sizeof(klmalloc_bin_header)) / PAGE_SIZE + 1;
klmalloc_bin_header * bin_header = (klmalloc_bin_header*)sbrk(PAGE_SIZE * pages);
bin_header->bin_magic = BIN_MAGIC;
bin_header->size = pages * PAGE_SIZE - sizeof(klmalloc_bin_header);
bin_header->head = NULL;
return (void*)((uintptr_t)bin_header + sizeof(klmalloc_bin_header));
}
}
static void klfree(void *ptr) {
if (__builtin_expect(ptr == NULL, 0)) {
return;
}
if ((uintptr_t)ptr % PAGE_SIZE == 0) {
ptr = (void *)((uintptr_t)ptr - 1);
}
klmalloc_bin_header * header = (klmalloc_bin_header *)((uintptr_t)ptr & (uintptr_t)~PAGE_MASK);
if (header->bin_magic != BIN_MAGIC)
return;
uintptr_t bucket_id = header->size;
if (bucket_id > (uintptr_t)NUM_BINS) {
bucket_id = BIG_BIN;
klmalloc_bin_header *bheader = (klmalloc_bin_header*)header;
pmm_free(header, bheader->size + sizeof(klmalloc_bin_header));
} else {
if (klmalloc_stack_empty(header)) {
klmalloc_list_insert(&klmalloc_bin_head[bucket_id], header);
}
klmalloc_stack_push(header, ptr);
}
}
static void * __attribute__ ((malloc)) klrealloc(void *ptr, uintptr_t size) {
if (__builtin_expect(ptr == NULL, 0))
return klmalloc(size);
if (__builtin_expect(size == 0, 0))
{
free(ptr);
return NULL;
}
klmalloc_bin_header * header_old = (void *)((uintptr_t)ptr & (uintptr_t)~PAGE_MASK);
if (header_old->bin_magic != BIN_MAGIC) {
return NULL;
}
uintptr_t old_size = header_old->size;
if (old_size < (uintptr_t)BIG_BIN) {
old_size = (1UL << (SMALLEST_BIN_LOG + old_size));
}
if (old_size == size) return ptr;
void * newptr = klmalloc(size);
if (__builtin_expect(newptr != NULL, 1)) {
memcpy(newptr, ptr, (old_size < size) ? old_size : size);
klfree(ptr);
return newptr;
}
return NULL;
}
static void * __attribute__ ((malloc)) klcalloc(uintptr_t nmemb, uintptr_t size) {
void *ptr = klmalloc(nmemb * size);
if (ptr) memset(ptr,0x00,nmemb * size);
return ptr;
}

1
common/kuroko/memory.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/memory.c

1
common/kuroko/methods.h Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/methods.h

1
common/kuroko/obj_base.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_base.c

1
common/kuroko/obj_bytes.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_bytes.c

1
common/kuroko/obj_dict.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_dict.c

View File

@ -0,0 +1 @@
../../kuroko/src/obj_function.c

1
common/kuroko/obj_gen.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_gen.c

1
common/kuroko/obj_list.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_list.c

1
common/kuroko/obj_long.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_long.c

1
common/kuroko/obj_numeric.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_numeric.c

1
common/kuroko/obj_range.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_range.c

1
common/kuroko/obj_set.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_set.c

1
common/kuroko/obj_slice.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_slice.c

1
common/kuroko/obj_str.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_str.c

1
common/kuroko/obj_tuple.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_tuple.c

1
common/kuroko/obj_typing.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/obj_typing.c

1
common/kuroko/object.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/object.c

1
common/kuroko/opcode_enum.h Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/opcode_enum.h

1
common/kuroko/opcodes.h Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/opcodes.h

1
common/kuroko/parseargs.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/parseargs.c

1
common/kuroko/private.h Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/private.h

464
common/kuroko/repl.c Normal file
View File

@ -0,0 +1,464 @@
/**
* @file repl.c
* @brief General-purpose Kuroko repl using rline, with tab completion.
*
* This is a generic repl. Initialize the @c __main__ module and then
* call @c krk_repl() to run a repl session. You can bind a builtin
* @c exit() function to set @c krk_exitRepl to 1 to exit the repl;
* the repl will also terminate if rline detects an EOF condition.
*/
#include <kuroko/vm.h>
#include <kuroko/scanner.h>
#include <kuroko/util.h>
#include <rline.h>
#define PROMPT_MAIN ">>> "
#define PROMPT_BLOCK " > "
int krk_exitRepl = 0;
void krk_printResult(KrkValue result) {
if (IS_NONE(result)) return;
krk_attachNamedValue(&vm.builtins->fields, "_", result);
KrkClass * type = krk_getType(result);
const char * formatStr = " \033[1;90m=> %s\033[0m\n";
if (type->_reprer) {
krk_push(result);
result = krk_callDirect(type->_reprer, 1);
} else if (type->_tostr) {
krk_push(result);
result = krk_callDirect(type->_tostr, 1);
}
if (!IS_STRING(result)) {
printf(" \033[1;91m=> Unable to produce representation for value.\033[0m\n");
} else {
printf(formatStr, AS_CSTRING(result));
}
}
#if 1
static KrkValue findFromProperty(KrkValue current, KrkToken next) {
KrkValue member = OBJECT_VAL(krk_copyString(next.start, next.literalWidth));
krk_push(member);
KrkValue value = krk_valueGetAttribute_default(current, AS_CSTRING(member), NONE_VAL());
krk_pop();
return value;
}
static char * syn_krk_keywords[] = {
"and","class","def","else","for","if","in","import","del",
"let","not","or","return","while","try","except","raise",
"continue","break","as","from","elif","lambda","with","is",
"pass","assert","yield","finally","async","await",
"True","False","None",
NULL
};
static void tab_complete_func(rline_context_t * c) {
/* Figure out where the cursor is and if we should be completing anything. */
if (c->offset) {
size_t stackIn = krk_currentThread.stackTop - krk_currentThread.stack;
/* Copy up to the cursor... */
char * tmp = malloc(c->offset + 1);
memcpy(tmp, c->buffer, c->offset);
tmp[c->offset] = '\0';
/* and pass it to the scanner... */
KrkScanner scanner = krk_initScanner(tmp);
/* Logically, there can be at most (offset) tokens, plus some wiggle room. */
KrkToken * space = malloc(sizeof(KrkToken) * (c->offset + 2));
int count = 0;
do {
space[count++] = krk_scanToken(&scanner);
} while (space[count-1].type != TOKEN_EOF && space[count-1].type != TOKEN_ERROR);
/* If count == 1, it was EOF or an error and we have nothing to complete. */
if (count == 1) {
goto _cleanup;
}
/* Otherwise we want to see if we're on an identifier or a dot. */
int base = 2;
int n = base;
if (space[count-base].type == TOKEN_DOT) {
/* Dots we need to look back at the previous tokens for */
n--;
base--;
} else if (space[count-base].type >= TOKEN_IDENTIFIER && space[count-base].type <= TOKEN_WITH) {
/* Something alphanumeric; only for the last element */
} else {
/* Some other symbol */
goto _cleanup;
}
/* Work backwards to find the start of this chain of identifiers */
while (n < count) {
if (space[count-n-1].type != TOKEN_DOT) break;
n++;
if (n == count) break;
if (space[count-n-1].type != TOKEN_IDENTIFIER) break;
n++;
}
if (n <= count) {
/* Now work forwards, starting from the current globals. */
KrkValue root = OBJECT_VAL(krk_currentThread.module);
int isGlobal = 1;
while (n > base) {
/* And look at the potential fields for instances/classes */
KrkValue next = findFromProperty(root, space[count-n]);
if (IS_NONE(next)) {
/* If we hit None, we found something invalid (or literally hit a None
* object, but really the difference is minimal in this case: Nothing
* useful to tab complete from here. */
if (!isGlobal) goto _cleanup;
/* Does this match a builtin? */
if (!krk_tableGet_fast(&vm.builtins->fields,
krk_copyString(space[count-n].start,space[count-n].literalWidth), &next) || IS_NONE(next)) {
goto _cleanup;
}
}
isGlobal = 0;
root = next;
n -= 2; /* To skip every other dot. */
}
if (isGlobal && n < count && (space[count-n-1].type == TOKEN_IMPORT || space[count-n-1].type == TOKEN_FROM)) {
KrkInstance * modules = krk_newInstance(vm.baseClasses->objectClass);
root = OBJECT_VAL(modules);
krk_push(root);
for (size_t i = 0; i < vm.modules.capacity; ++i) {
KrkTableEntry * entry = &vm.modules.entries[i];
if (IS_KWARGS(entry->key)) continue;
krk_attachNamedValue(&modules->fields, AS_CSTRING(entry->key), NONE_VAL());
}
}
/* Now figure out what we're completing - did we already have a partial symbol name? */
int length = (space[count-base].type == TOKEN_DOT) ? 0 : (space[count-base].length);
isGlobal = isGlobal && (length != 0);
/* Collect up to 256 of those that match */
char * matches[256];
int matchCount = 0;
/* Take the last symbol name from the chain and get its member list from dir() */
for (;;) {
KrkValue dirList = krk_dirObject(1,(KrkValue[]){root},0);
krk_push(dirList);
if (!IS_INSTANCE(dirList)) {
fprintf(stderr,"\nInternal error while tab completting.\n");
goto _cleanup;
}
for (size_t i = 0; i < AS_LIST(dirList)->count; ++i) {
KrkString * s = AS_STRING(AS_LIST(dirList)->values[i]);
krk_push(OBJECT_VAL(s));
KrkToken asToken = {.start = s->chars, .literalWidth = s->length};
KrkValue thisValue = findFromProperty(root, asToken);
krk_push(thisValue);
if (IS_CLOSURE(thisValue) || IS_BOUND_METHOD(thisValue) || IS_NATIVE(thisValue)) {
size_t allocSize = s->length + 2;
char * tmp = malloc(allocSize);
size_t len = snprintf(tmp, allocSize, "%s(", s->chars);
s = krk_takeString(tmp, len);
krk_pop();
krk_push(OBJECT_VAL(s));
} else {
krk_pop();
}
/* If this symbol is shorter than the current submatch, skip it. */
if (length && (int)s->length < length) continue;
/* See if it's already in the matches */
int found = 0;
for (int i = 0; i < matchCount; ++i) {
if (!strcmp(matches[i], s->chars)) {
found = 1;
break;
}
}
if (found) continue;
if (!memcmp(s->chars, space[count-base].start, length)) {
matches[matchCount] = s->chars;
matchCount++;
if (matchCount == 255) goto _toomany;
}
}
/*
* If the object we were scanning was the current module,
* then we should also throw the builtins into the ring.
*/
if (isGlobal && AS_OBJECT(root) == (KrkObj*)krk_currentThread.module) {
root = OBJECT_VAL(vm.builtins);
continue;
} else if (isGlobal && AS_OBJECT(root) == (KrkObj*)vm.builtins) {
KrkInstance * fakeKeywordsObject = krk_newInstance(vm.baseClasses->objectClass);
root = OBJECT_VAL(fakeKeywordsObject);
krk_push(root);
for (char ** keyword = syn_krk_keywords; *keyword; keyword++) {
krk_attachNamedValue(&fakeKeywordsObject->fields, *keyword, NONE_VAL());
}
continue;
} else {
break;
}
}
_toomany:
/* Now we can do things with the matches. */
if (matchCount == 1) {
/* If there was only one, just fill it. */
rline_insert(c, matches[0] + length);
rline_place_cursor();
} else if (matchCount) {
/* Otherwise, try to find a common substring among them... */
int j = length;
while (1) {
char m = matches[0][j];
if (!m) break;
int diff = 0;
for (int i = 1; i < matchCount; ++i) {
if (matches[i][j] != m) {
diff = 1;
break;
}
}
if (diff) break;
j++;
}
/* If no common sub string could be filled in, we print the list. */
if (j == length) {
/* First find the maximum width of an entry */
int maxWidth = 0;
for (int i = 0; i < matchCount; ++i) {
if ((int)strlen(matches[i]) > maxWidth) maxWidth = strlen(matches[i]);
}
/* Now how many can we fit in a screen */
int colsPerLine = rline_terminal_width / (maxWidth + 2); /* +2 for the spaces */
fprintf(stderr, "\n");
int column = 0;
for (int i = 0; i < matchCount; ++i) {
fprintf(stderr, "%-*s ", maxWidth, matches[i]);
column += 1;
if (column >= colsPerLine) {
fprintf(stderr, "\n");
column = 0;
}
}
if (column != 0) fprintf(stderr, "\n");
} else {
/* If we do have a common sub string, fill in those characters. */
for (int i = length; i < j; ++i) {
char tmp[2] = {matches[0][i], '\0'};
rline_insert(c, tmp);
}
}
}
}
_cleanup:
free(tmp);
free(space);
krk_currentThread.stackTop = &krk_currentThread.stack[stackIn];
return;
}
}
void krk_repl(void) {
krk_exitRepl = 0;
while (!krk_exitRepl) {
size_t lineCapacity = 8;
size_t lineCount = 0;
char ** lines = ALLOCATE(char *, lineCapacity);
size_t totalData = 0;
int valid = 1;
char * allData = NULL;
int inBlock = 0;
int blockWidth = 0;
rline_exp_set_prompts(PROMPT_MAIN, "", 4, 0);
rline_exit_string="exit";
rline_exp_set_syntax("krk");
rline_exp_set_tab_complete_func(tab_complete_func);
while (1) {
char buf[4096] = {0};
if (inBlock) {
rline_exp_set_prompts(PROMPT_BLOCK, "", 4, 0);
rline_preload = malloc(blockWidth + 1);
for (int i = 0; i < blockWidth; ++i) {
rline_preload[i] = ' ';
}
rline_preload[blockWidth] = '\0';
}
rline_scroll = 0;
if (rline(buf, 4096) == 0) {
valid = 0;
krk_exitRepl = 1;
break;
}
if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) {
/* We should actually be properly raising the interrupt and printing it with an empty traceback, but whatever. */
krk_currentThread.flags &= ~(KRK_THREAD_SIGNALLED); /* Clear signal flag */
printf("KeyboardInterrupt\n");
valid = 0;
break;
}
if (buf[strlen(buf)-1] != '\n') {
valid = 0;
break;
}
if (lineCapacity < lineCount + 1) {
size_t old = lineCapacity;
lineCapacity = GROW_CAPACITY(old);
lines = GROW_ARRAY(char *,lines,old,lineCapacity);
}
int i = lineCount++;
lines[i] = strdup(buf);
size_t lineLength = strlen(lines[i]);
totalData += lineLength;
int isSpaces = 1;
int countSpaces = 0;
for (size_t j = 0; j < lineLength; ++j) {
if (lines[i][j] != ' ' && lines[i][j] != '\n') {
isSpaces = 0;
break;
}
countSpaces += 1;
}
if (lineLength > 1 && lines[i][lineLength-2] == ':') {
inBlock = 1;
blockWidth = countSpaces + 4;
continue;
} else if (lineLength > 1 && lines[i][lineLength-2] == '\\') {
inBlock = 1;
continue;
} else if (inBlock && lineLength != 1) {
if (isSpaces) {
free(lines[i]);
totalData -= lineLength;
lineCount--;
break;
}
blockWidth = countSpaces;
continue;
} else if (lineLength > 1 && lines[i][countSpaces] == '@') {
inBlock = 1;
blockWidth = countSpaces;
continue;
}
if (isSpaces && !i) valid = 0;
break;
}
if (valid) {
allData = malloc(totalData + 1);
allData[0] = '\0';
}
for (size_t i = 0; i < lineCount; ++i) {
if (valid) strcat(allData, lines[i]);
rline_history_insert(strdup(lines[i]));
rline_scroll = 0;
free(lines[i]);
}
FREE_ARRAY(char *, lines, lineCapacity);
if (valid) {
KrkValue result = krk_interpret(allData, "<stdin>");
krk_printResult(result);
krk_resetStack();
}
(void)blockWidth;
}
}
#else
/* repl without rline */
void krk_repl(void) {
krk_exitRepl = 0;
while (!krk_exitRepl) {
size_t lineCapacity = 8;
size_t lineCount = 0;
char ** lines = ALLOCATE(char *, lineCapacity);
size_t totalData = 0;
int valid = 1;
char * allData = NULL;
int inBlock = 0;
int blockWidth = 0;
while (1) {
char buf[4096] = {0};
print(">>> ");
readline("", buf, 4096);
if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) {
/* We should actually be properly raising the interrupt and printing it with an empty traceback, but whatever. */
krk_currentThread.flags &= ~(KRK_THREAD_SIGNALLED); /* Clear signal flag */
printf("KeyboardInterrupt\n");
valid = 0;
break;
}
if (buf[strlen(buf)-1] != '\n') {
valid = 0;
break;
}
if (lineCapacity < lineCount + 1) {
size_t old = lineCapacity;
lineCapacity = GROW_CAPACITY(old);
lines = GROW_ARRAY(char *,lines,old,lineCapacity);
}
int i = lineCount++;
lines[i] = strdup(buf);
size_t lineLength = strlen(lines[i]);
totalData += lineLength;
int isSpaces = 1;
int countSpaces = 0;
for (size_t j = 0; j < lineLength; ++j) {
if (lines[i][j] != ' ' && lines[i][j] != '\n') {
isSpaces = 0;
break;
}
countSpaces += 1;
}
if (lineLength > 1 && lines[i][lineLength-2] == ':') {
inBlock = 1;
blockWidth = countSpaces + 4;
continue;
} else if (lineLength > 1 && lines[i][lineLength-2] == '\\') {
inBlock = 1;
continue;
} else if (inBlock && lineLength != 1) {
if (isSpaces) {
free(lines[i]);
totalData -= lineLength;
lineCount--;
break;
}
blockWidth = countSpaces;
continue;
} else if (lineLength > 1 && lines[i][countSpaces] == '@') {
inBlock = 1;
blockWidth = countSpaces;
continue;
}
if (isSpaces && !i) valid = 0;
break;
}
if (valid) {
allData = malloc(totalData + 1);
allData[0] = '\0';
}
for (size_t i = 0; i < lineCount; ++i) {
if (valid) strcat(allData, lines[i]);
free(lines[i]);
}
FREE_ARRAY(char *, lines, lineCapacity);
if (valid) {
KrkValue result = krk_interpret(allData, "<stdin>");
krk_printResult(result);
krk_resetStack();
}
(void)blockWidth;
}
}
#endif

2348
common/kuroko/rline.c Normal file

File diff suppressed because it is too large Load Diff

1
common/kuroko/scanner.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/scanner.c

568
common/kuroko/stubs.c Normal file
View File

@ -0,0 +1,568 @@
/**
* @file stubs.c
* @brief Implementations of libc functions needed under EFI and BIOS.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <lib/print.h>
#include <lib/term.h>
void print_(char *str) {
FOR_TERM(flanterm_write(TERM, str, strlen(str)));
}
void abort(void) {print_("ABORT\n"); while(1); }
void exit(int status) {print_("EXIT\n"); while(1); }
char * strchr(const char * s, int c) {
while (*s && *s != c) s++;
return *s == c ? (char*)s : NULL;
}
char * strrchr(const char * s, int c) {
size_t l = strlen(s);
for (size_t i = 0; i < l; ++i) {
if (s[l-i-1] == c) {
return (char*)&s[l-i-1];
}
}
return NULL;
}
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
if (!nmemb) return;
if (!size) return;
char * tmp = malloc(size);
for (size_t i = 0; i < nmemb-1; ++i) {
for (size_t j = 0; j < nmemb-1; ++j) {
void * left = (char *)base + size * j;
void * right = (char *)base + size * (j + 1);
if (compar(left,right) > 0) {
memcpy(tmp, right, size);
memcpy(right, left, size);
memcpy(left, tmp, size);
}
}
}
free(tmp);
}
static int isspace(int c) {
return c == ' ';
}
static int is_valid(int base, char c) {
if (c < '0') return 0;
if (base <= 10) {
return c < ('0' + base);
}
if (c >= 'a' && c < 'a' + (base - 10)) return 1;
if (c >= 'A' && c < 'A' + (base - 10)) return 1;
if (c >= '0' && c <= '9') return 1;
return 0;
}
static int convert_digit(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'z') {
return c - 'a' + 0xa;
}
if (c >= 'A' && c <= 'Z') {
return c - 'A' + 0xa;
}
return 0;
}
#define LONG_MAX 2147483647
#define LONG_LONG_MAX 0x7FFFffffFFFFffffULL
#define strtox(max, type) \
if (base < 0 || base == 1 || base > 36) { \
return max; \
} \
while (*nptr && isspace(*nptr)) nptr++; \
int sign = 1; \
if (*nptr == '-') { \
sign = -1; \
nptr++; \
} else if (*nptr == '+') { \
nptr++; \
} \
if (base == 16) { \
if (*nptr == '0') { \
nptr++; \
if (*nptr == 'x') { \
nptr++; \
} \
} \
} \
if (base == 0) { \
if (*nptr == '0') { \
base = 8; \
nptr++; \
if (*nptr == 'x') { \
base = 16; \
nptr++; \
} \
} else { \
base = 10; \
} \
} \
type val = 0; \
while (is_valid(base, *nptr)) { \
val *= base; \
val += convert_digit(*nptr); \
nptr++; \
} \
if (endptr) { \
*endptr = (char *)nptr; \
} \
if (sign == -1) { \
return -val; \
} else { \
return val; \
}
long int strtol(const char *nptr, char **endptr, int base) {
strtox(LONG_MAX, unsigned long int);
}
long long int strtoll(const char *nptr, char **endptr, int base) {
strtox(LONG_LONG_MAX, unsigned long long int);
}
#define ULONG_MAX ((unsigned long)(-1))
unsigned long int strtoul(const char *nptr, char **endptr, int base) {
strtox(ULONG_MAX, unsigned long int);
}
int atoi(const char * c) {
return strtol(c,NULL,10);
}
FILE * stdout = NULL;
FILE * stderr = NULL;
FILE * stdin = NULL;
int fputc(int c, FILE * stream) {
if (stream == stdout) {
char tmp[2] = {c,0};
print_(tmp);
}
return c;
}
int fputs(const char * s, FILE * stream) {
while (*s) {
fputc(*s,stream);
s++;
}
return 0;
}
int puts(const char * s) {
fputs(s,stdout);
fputc('\n',stdout);
return 0;
}
#define OUT(c) do { callback(userData, (c)); written++; } while (0)
static size_t print_dec(unsigned long long value, unsigned int width, int (*callback)(void*,char), void * userData, int fill_zero, int align_right, int precision) {
size_t written = 0;
unsigned long long n_width = 1;
unsigned long long i = 9;
if (precision == -1) precision = 1;
if (value == 0) {
n_width = 0;
} else {
unsigned long long val = value;
while (val >= 10UL) {
val /= 10UL;
n_width++;
}
}
if (n_width < (unsigned long long)precision) n_width = precision;
int printed = 0;
if (align_right) {
while (n_width + printed < width) {
OUT(fill_zero ? '0' : ' ');
printed += 1;
}
i = n_width;
char tmp[100];
while (i > 0) {
unsigned long long n = value / 10;
long long r = value % 10;
tmp[i - 1] = r + '0';
i--;
value = n;
}
while (i < n_width) {
OUT(tmp[i]);
i++;
}
} else {
i = n_width;
char tmp[100];
while (i > 0) {
unsigned long long n = value / 10;
long long r = value % 10;
tmp[i - 1] = r + '0';
i--;
value = n;
printed++;
}
while (i < n_width) {
OUT(tmp[i]);
i++;
}
while (printed < (long long)width) {
OUT(fill_zero ? '0' : ' ');
printed += 1;
}
}
return written;
}
/*
* Hexadecimal to string
*/
static size_t print_hex(unsigned long long value, unsigned int width, int (*callback)(void*,char), void* userData, int fill_zero, int alt, int caps, int align) {
size_t written = 0;
int i = width;
unsigned long long n_width = 1;
unsigned long long j = 0x0F;
while (value > j && j < UINT64_MAX) {
n_width += 1;
j *= 0x10;
j += 0x0F;
}
if (!fill_zero && align == 1) {
while (i > (long long)n_width + 2*!!alt) {
OUT(' ');
i--;
}
}
if (alt) {
OUT('0');
OUT(caps ? 'X' : 'x');
}
if (fill_zero && align == 1) {
while (i > (long long)n_width + 2*!!alt) {
OUT('0');
i--;
}
}
i = (long long)n_width;
while (i-- > 0) {
char c = (caps ? "0123456789ABCDEF" : "0123456789abcdef")[(value>>(i*4))&0xF];
OUT(c);
}
if (align == 0) {
i = width;
while (i > (long long)n_width + 2*!!alt) {
OUT(' ');
i--;
}
}
return written;
}
/*
* vasprintf()
*/
size_t xvasprintf(int (*callback)(void *, char), void * userData, const char * fmt, va_list args) {
char * s;
int precision = -1;
size_t written = 0;
for (const char *f = fmt; *f; f++) {
if (*f != '%') {
OUT(*f);
continue;
}
++f;
unsigned int arg_width = 0;
int align = 1; /* right */
int fill_zero = 0;
int big = 0;
int alt = 0;
int always_sign = 0;
while (1) {
if (*f == '-') {
align = 0;
++f;
} else if (*f == '#') {
alt = 1;
++f;
} else if (*f == '*') {
arg_width = (char)va_arg(args, int);
++f;
} else if (*f == '0') {
fill_zero = 1;
++f;
} else if (*f == '+') {
always_sign = 1;
++f;
} else if (*f == ' ') {
always_sign = 2;
++f;
} else {
break;
}
}
while (*f >= '0' && *f <= '9') {
arg_width *= 10;
arg_width += *f - '0';
++f;
}
if (*f == '.') {
++f;
precision = 0;
if (*f == '*') {
precision = (int)va_arg(args, int);
++f;
} else {
while (*f >= '0' && *f <= '9') {
precision *= 10;
precision += *f - '0';
++f;
}
}
}
if (*f == 'l') {
big = 1;
++f;
if (*f == 'l') {
big = 2;
++f;
}
}
if (*f == 'j') {
big = (sizeof(uintmax_t) == sizeof(unsigned long long) ? 2 :
sizeof(uintmax_t) == sizeof(unsigned long) ? 1 : 0);
++f;
}
if (*f == 'z') {
big = (sizeof(size_t) == sizeof(unsigned long long) ? 2 :
sizeof(size_t) == sizeof(unsigned long) ? 1 : 0);
++f;
}
if (*f == 't') {
big = (sizeof(ptrdiff_t) == sizeof(unsigned long long) ? 2 :
sizeof(ptrdiff_t) == sizeof(unsigned long) ? 1 : 0);
++f;
}
/* fmt[i] == '%' */
switch (*f) {
case 's': /* String pointer -> String */
{
size_t count = 0;
if (big) {
return written;
} else {
s = (char *)va_arg(args, char *);
if (s == NULL) {
s = "(null)";
}
if (precision >= 0) {
while (*s && precision > 0) {
OUT(*s++);
count++;
precision--;
if (arg_width && count == arg_width) break;
}
} else {
while (*s) {
OUT(*s++);
count++;
if (arg_width && count == arg_width) break;
}
}
}
while (count < arg_width) {
OUT(' ');
count++;
}
}
break;
case 'c': /* Single character */
OUT((char)va_arg(args,int));
break;
case 'p':
alt = 1;
if (sizeof(void*) == sizeof(long long)) big = 2;
/* fallthrough */
case 'X':
case 'x': /* Hexadecimal number */
{
unsigned long long val;
if (big == 2) {
val = (unsigned long long)va_arg(args, unsigned long long);
} else if (big == 1) {
val = (unsigned long)va_arg(args, unsigned long);
} else {
val = (unsigned int)va_arg(args, unsigned int);
}
written += print_hex(val, arg_width, callback, userData, fill_zero, alt, !(*f & 32), align);
}
break;
case 'i':
case 'd': /* Decimal number */
{
long long val;
if (big == 2) {
val = (long long)va_arg(args, long long);
} else if (big == 1) {
val = (long)va_arg(args, long);
} else {
val = (int)va_arg(args, int);
}
if (val < 0) {
OUT('-');
val = -val;
} else if (always_sign) {
OUT(always_sign == 2 ? ' ' : '+');
}
written += print_dec(val, arg_width, callback, userData, fill_zero, align, precision);
}
break;
case 'u': /* Unsigned ecimal number */
{
unsigned long long val;
if (big == 2) {
val = (unsigned long long)va_arg(args, unsigned long long);
} else if (big == 1) {
val = (unsigned long)va_arg(args, unsigned long);
} else {
val = (unsigned int)va_arg(args, unsigned int);
}
written += print_dec(val, arg_width, callback, userData, fill_zero, align, precision);
}
break;
case '%': /* Escape */
OUT('%');
break;
default: /* Nothing at all, just dump it */
OUT(*f);
break;
}
}
return written;
}
struct CBData {
char * str;
size_t size;
size_t written;
};
static int cb_sprintf(void * user, char c) {
struct CBData * data = user;
if (data->size > data->written + 1) {
data->str[data->written] = c;
data->written++;
if (data->written < data->size) {
data->str[data->written] = '\0';
}
}
return 0;
}
int vsnprintf(char *str, size_t size, const char *format, va_list ap) {
struct CBData data = {str,size,0};
int out = xvasprintf(cb_sprintf, &data, format, ap);
cb_sprintf(&data, '\0');
return out;
}
int snprintf(char * str, size_t size, const char * format, ...) {
struct CBData data = {str,size,0};
va_list args;
va_start(args, format);
int out = xvasprintf(cb_sprintf, &data, format, args);
va_end(args);
cb_sprintf(&data, '\0');
return out;
}
static int cb_fprintf(void * user, char c) {
fputc(c,(FILE*)user);
return 0;
}
int fprintf(FILE *stream, const char * fmt, ...) {
va_list args;
va_start(args, fmt);
int out = xvasprintf(cb_fprintf, stream, fmt, args);
va_end(args);
return out;
}
char * strdup(const char * src) {
char * out = malloc(strlen(src)+1);
char * c = out;
while (*src) {
*c = *src;
c++; src++;
}
*c = 0;
return out;
}
char *strstr(const char *haystack, const char *needle) {
size_t s = strlen(needle);
const char * end = haystack + strlen(haystack);
while (haystack + s <= end) {
if (!memcmp(haystack,needle,s)) return (char*)haystack;
haystack++;
}
return NULL;
}
char * strcat(char *dest, const char *src) {
char * end = dest;
while (*end != '\0') {
++end;
}
while (*src) {
*end = *src;
end++;
src++;
}
*end = '\0';
return dest;
}
void ___chkstk_ms(void) { }
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE * stream) {
for (size_t i = 0; i < size * nmemb; ++i) {
fputc(((char*)ptr)[i], stream);
}
return size * nmemb;
}
void fflush(FILE * f) {
/* do nothing */
}

1
common/kuroko/sys.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/sys.c

1
common/kuroko/table.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/table.c

1
common/kuroko/threads.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/threads.c

1
common/kuroko/value.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/value.c

1
common/kuroko/vm.c Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/vm.c

1
common/kuroko/wcwidth._h Symbolic link
View File

@ -0,0 +1 @@
../../kuroko/src/wcwidth._h

View File

@ -91,6 +91,8 @@ int getchar_internal(uint8_t scancode, uint8_t ascii, uint32_t shift_state) {
}
}
if (ascii == '\t') return ascii;
// Guard against non-printable values
if (ascii < 0x20 || ascii > 0x7e) {
return -1;
@ -310,7 +312,7 @@ again:
}
if (kd.Key.ScanCode == 0x08) {
return '\b';
return GETCHAR_DELETE;
}
if (kd.Key.ScanCode == SCAN_ESC) {

View File

@ -3,6 +3,7 @@
#include <stdbool.h>
#include <stdnoreturn.h>
#include <config.h>
#include <kuroko-limine.h>
#include <menu.h>
#include <lib/print.h>
#include <lib/misc.h>
@ -815,6 +816,10 @@ refresh:
}
set_cursor_pos_helper(terms[0]->cols - 13, 3);
print("\e[32mC\e[0m Console");
set_cursor_pos_helper(terms[0]->cols - 24, 3);
print("\e[32mK\e[0m Kuroko");
set_cursor_pos_helper(x, y);
}
@ -928,6 +933,12 @@ timeout_aborted:
console();
goto refresh;
}
case 'k':
case 'K': {
reset_term();
limine_krk_enter_repl();
goto refresh;
}
}
}
}

3
kuroko-inc/assert.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
#define assert(...)

13
kuroko-inc/dirent.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <stdint.h>
typedef struct dirent {
int d_ino;
char d_name[256];
} dirent;
typedef void * DIR;
extern DIR * opendir(const char * name);
extern int closedir(DIR * dirp);
extern struct dirent * readdir(DIR *dirp);

0
kuroko-inc/errno.h Normal file
View File

28
kuroko-inc/inttypes.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
/**
* EFI is 32-bit long, 64-bit long long
*/
#define PRIi8 "i"
#define PRIi16 "i"
#define PRIi32 "i"
#define PRIi64 "lli"
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIx32 "x"
#define PRIx64 "llx"
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "u"
#define PRIu64 "llu"
#define PRId8 "d"
#define PRId16 "d"
#define PRId32 "d"
#define PRId64 "lld"

1
kuroko-inc/kuroko Symbolic link
View File

@ -0,0 +1 @@
../kuroko/src/kuroko

63
kuroko-inc/rline.h Normal file
View File

@ -0,0 +1,63 @@
#pragma once
struct rline_callback;
typedef struct {
char * buffer;
struct rline_callback * callbacks;
int collected;
int requested;
int newline;
int cancel;
int offset;
int tabbed;
int quiet;
} rline_context_t;
typedef void (*rline_callback_t)(rline_context_t * context);
typedef struct rline_callback {
rline_callback_t tab_complete;
rline_callback_t redraw_prompt;
rline_callback_t special_key;
rline_callback_t key_up;
rline_callback_t key_down;
rline_callback_t key_left;
rline_callback_t key_right;
rline_callback_t rev_search;
} rline_callbacks_t;
typedef enum {
/* Base colors */
RLINE_STYLE_MAIN,
RLINE_STYLE_ALT,
/* Syntax flags */
RLINE_STYLE_KEYWORD,
RLINE_STYLE_STRING,
RLINE_STYLE_COMMENT,
RLINE_STYLE_TYPE,
RLINE_STYLE_PRAGMA,
RLINE_STYLE_NUMERAL,
} rline_style_t;
extern int rline(char * buffer, int buf_size);
extern int rline_exp_set_prompts(char * left, char * right, int left_width, int right_width);
extern int rline_exp_set_shell_commands(char ** cmds, int len);
extern int rline_exp_set_tab_complete_func(rline_callback_t func);
extern int rline_exp_set_syntax(char * name);
extern void rline_history_insert(char * str);
extern void rline_history_append_line(char * str);
extern char * rline_history_get(int item);
extern char * rline_history_prev(int item);
extern void rline_place_cursor(void);
extern void rline_set_colors(rline_style_t style);
extern void rline_insert(rline_context_t * context, const char * what);
extern int rline_terminal_width;
#define RLINE_HISTORY_ENTRIES 128
extern char * rline_history[RLINE_HISTORY_ENTRIES];
extern int rline_history_count;
extern int rline_history_offset;
extern int rline_scroll;
extern char * rline_exit_string;
extern char * rline_preload;

36
kuroko-inc/stdio.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <string.h>
#include <stdarg.h>
typedef void * FILE;
extern FILE * stdout;
extern FILE * stderr;
extern FILE * stdin;
extern int fprintf(FILE *stream, const char * fmt, ...);
extern int snprintf(char * str, size_t size, const char * format, ...);
extern int fputc(int c, FILE * stream);
extern int vsnprintf(char *str, size_t size, const char *format, va_list ap);
extern int puts(const char * s);
#define printf(...) fprintf(stdout, __VA_ARGS__)
extern int fgetc(FILE * stream);
extern FILE * fopen(const char * pathname, const char * mode);
extern int fclose(FILE * stream);
extern size_t fread(void * ptr, size_t size, size_t nmemb, FILE * stream);
extern size_t fwrite(void * ptr, size_t size, size_t nmemb, FILE * stream);
extern int fseek(FILE * stream, long offset, int whence);
extern long ftell(FILE * stream);
extern void fflush(FILE * stream);
#define SEEK_SET 1
#define SEEK_END 2
struct stat {
int pad;
};
extern int stat(const char*,struct stat*);
extern int errno;
extern char * strerror(int errnum);
extern int feof(FILE * stream);
#define ferror(o) (0)

19
kuroko-inc/stdlib.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <stdint.h>
#include <string.h>
extern void * realloc(void * ptr, size_t size);
extern void free(void *ptr);
extern void * malloc(size_t size);
extern void * calloc(size_t nmemb, size_t size);
extern double strtod(const char *nptr, char **endptr);
extern long int strtol(const char *nptr, char **endptr, int base);
extern long long int strtoll(const char *nptr, char **endptr, int base);
extern unsigned long int strtoul(const char *nptr, char **endptr, int base);
extern void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
extern void abort(void);
extern void exit(int status);
extern int atoi(const char * c);

34
kuroko-inc/string.h Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <stddef.h>
#ifndef __SIZE_TYPE__
# if defined(__x86_64__) || defined(__aarch64__)
typedef unsigned long long size_t;
# else
typedef unsigned long size_t;
# endif
#else
typedef __SIZE_TYPE__ size_t;
#endif
#ifndef ssize_t
# if defined(__x86_64__) || defined(__aarch64__)
typedef long long ssize_t;
# else
typedef long ssize_t;
# endif
#endif
extern void * memcpy(void * restrict dest, const void * restrict src, size_t n);
extern void * memset(void * dest, int c, size_t n);
extern int strcmp(const char * l, const char * r);
extern size_t strlen(const char *s);
extern int memcmp(const void * vl, const void * vr, size_t n);
extern char * strdup(const char * src);
extern void * memmove(void * dest, const void * src, size_t n);
extern char * strcat(char *dest, const char *src);
extern char *strstr(const char *haystack, const char *needle);
extern char * strchr(const char * s, int c);
extern char * strrchr(const char * s, int c);
extern char * strcpy(char * restrict dest, const char * restrict src);

0
kuroko-inc/sys/stat.h Normal file
View File

0
kuroko-inc/sys/time.h Normal file
View File

0
kuroko-inc/sys/types.h Normal file
View File

9
kuroko-inc/time.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
struct timespec {
int tv_sec;
int tv_nsec;
};
#define CLOCK_MONOTONIC 0
#define clock_gettime(a,b)

0
kuroko-inc/unistd.h Normal file
View File