kuroko: Update with upstream, changes to classes
This commit is contained in:
parent
d54d93dd9d
commit
9ab445cb28
90
apps/bim.c
90
apps/bim.c
@ -16,15 +16,10 @@
|
||||
*/
|
||||
#define ENABLE_THREADING
|
||||
#include "bim.h"
|
||||
#ifdef __toaru__
|
||||
#include <kuroko.h>
|
||||
#include "vm.h"
|
||||
#include "debug.h"
|
||||
#else
|
||||
#include <kuroko/kuroko.h>
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/debug.h>
|
||||
#endif
|
||||
#include <kuroko/util.h>
|
||||
|
||||
global_config_t global_config = {
|
||||
/* State */
|
||||
@ -80,6 +75,7 @@ global_config_t global_config = {
|
||||
.smart_complete = 0,
|
||||
.has_terminal = 0,
|
||||
.search_wraps = 1,
|
||||
.had_error = 0,
|
||||
/* Integer config values */
|
||||
.cursor_padding = 4,
|
||||
.split_percent = 50,
|
||||
@ -3183,6 +3179,7 @@ void render_error(char * message, ...) {
|
||||
|
||||
/* Draw the message */
|
||||
printf("%s", buf);
|
||||
global_config.had_error = 1;
|
||||
} else {
|
||||
printf("bim: error during startup: %s\n", buf);
|
||||
}
|
||||
@ -9938,7 +9935,7 @@ struct CommandDef {
|
||||
|
||||
int process_krk_command(const char * cmd, KrkValue * outVal) {
|
||||
place_cursor(global_config.term_width, global_config.term_height);
|
||||
fprintf(stdout,"\n");
|
||||
fprintf(stdout, "\n");
|
||||
/* By resetting, we're at 0 frames. */
|
||||
krk_resetStack();
|
||||
/* Push something so we're not at the bottom of the stack when an
|
||||
@ -9998,7 +9995,8 @@ int process_krk_command(const char * cmd, KrkValue * outVal) {
|
||||
}
|
||||
}
|
||||
global_config.break_from_selection = 1;
|
||||
redraw_all();
|
||||
if (!global_config.had_error) redraw_all();
|
||||
global_config.had_error = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -10184,11 +10182,11 @@ static KrkValue krk_bim_register_syntax(int argc, KrkValue argv[], int hasKw) {
|
||||
if (argc < 1 || !IS_CLASS(argv[0]) || !checkClass(AS_CLASS(argv[0]), syntaxStateClass))
|
||||
return krk_runtimeError(vm.exceptions->typeError, "Can not register '%s' as a syntax highlighter, expected subclass of SyntaxState.", krk_typeName(argv[0]));
|
||||
|
||||
KrkValue name = NONE_VAL(), extensions = NONE_VAL(), spaces = BOOLEAN_VAL(0), calculate = NONE_VAL();
|
||||
krk_tableGet(&AS_CLASS(argv[0])->fields, OBJECT_VAL(S("name")), &name);
|
||||
krk_tableGet(&AS_CLASS(argv[0])->fields, OBJECT_VAL(S("extensions")), &extensions);
|
||||
krk_tableGet(&AS_CLASS(argv[0])->fields, OBJECT_VAL(S("spaces")), &spaces);
|
||||
krk_tableGet(&AS_CLASS(argv[0])->methods, OBJECT_VAL(S("calculate")), &calculate);
|
||||
KrkValue name = krk_valueGetAttribute_default(argv[0], "name", NONE_VAL());
|
||||
KrkValue extensions = krk_valueGetAttribute_default(argv[0], "extensions", NONE_VAL());
|
||||
KrkValue spaces = krk_valueGetAttribute_default(argv[0], "spaces", BOOLEAN_VAL(0));
|
||||
KrkValue calculate = krk_valueGetAttribute_default(argv[0], "calculate", NONE_VAL());
|
||||
|
||||
if (!IS_STRING(name))
|
||||
return krk_runtimeError(vm.exceptions->typeError, "%s.name must be str", AS_CLASS(argv[0])->name->chars);
|
||||
if (!IS_TUPLE(extensions))
|
||||
@ -10527,7 +10525,7 @@ void import_directory(char * dirName) {
|
||||
if (!dirp) {
|
||||
/* Try one last fallback */
|
||||
if (dirpath) free(dirpath);
|
||||
dirpath = strdup("/usr/share/bim");
|
||||
dirpath = strdup("/usr/local/share/bim");
|
||||
sprintf(file, "%s/%s", dirpath, dirName);
|
||||
extra = "/";
|
||||
dirp = opendir(file);
|
||||
@ -10620,6 +10618,37 @@ BIM_COMMAND(reload,"reload","Reloads all the Kuroko stuff.") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static KrkValue krk_bim_getDocumentText(int argc, KrkValue argv[], int hasKw) {
|
||||
struct StringBuilder sb = {0};
|
||||
|
||||
int i, j;
|
||||
for (i = 0; i < env->line_count; ++i) {
|
||||
line_t * line = env->lines[i];
|
||||
for (j = 0; j < line->actual; j++) {
|
||||
char_t c = line->text[j];
|
||||
if (c.codepoint == 0) {
|
||||
pushStringBuilder(&sb, 0);
|
||||
} else {
|
||||
char tmp[8] = {0};
|
||||
int len = to_eight(c.codepoint, tmp);
|
||||
pushStringBuilderStr(&sb, tmp, len);
|
||||
}
|
||||
}
|
||||
pushStringBuilder(&sb, '\n');
|
||||
}
|
||||
|
||||
return finishStringBuilder(&sb);
|
||||
}
|
||||
|
||||
static KrkValue krk_bim_renderError(int argc, KrkValue argv[], int hasKw) {
|
||||
if (argc != 1 || !IS_STRING(argv[0])) return TYPE_ERROR(str,argv[0]);
|
||||
if (AS_STRING(argv[0])->length == 0)
|
||||
redraw_commandline();
|
||||
else
|
||||
render_error(AS_CSTRING(argv[0]));
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run global initialization tasks
|
||||
*/
|
||||
@ -10671,6 +10700,9 @@ void initialize(void) {
|
||||
krk_bim_syntax_dict = krk_dict_of(0,NULL,0);
|
||||
krk_attachNamedValue(&bimModule->fields, "highlighters", krk_bim_syntax_dict);
|
||||
|
||||
krk_defineNative(&bimModule->fields, "getDocumentText", krk_bim_getDocumentText);
|
||||
krk_defineNative(&bimModule->fields, "renderError", krk_bim_renderError);
|
||||
|
||||
makeClass(bimModule, &ActionDef, "Action", vm.baseClasses->objectClass);
|
||||
ActionDef->allocSize = sizeof(struct ActionDef);
|
||||
krk_defineNative(&ActionDef->methods, ".__call__", bim_krk_action_call);
|
||||
@ -10718,21 +10750,21 @@ void initialize(void) {
|
||||
krk_defineNative(&syntaxStateClass->methods, ".matchAndPaint", bim_krk_state_matchAndPaint);
|
||||
krk_defineNative(&syntaxStateClass->methods, ".commentBuzzwords", bim_krk_state_commentBuzzwords);
|
||||
krk_defineNative(&syntaxStateClass->methods, ".rewind", bim_krk_state_rewind);
|
||||
krk_defineNative(&syntaxStateClass->methods, ".__get__", bim_krk_state_get);
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_NONE", INTEGER_VAL(FLAG_NONE));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_KEYWORD", INTEGER_VAL(FLAG_KEYWORD));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_STRING", INTEGER_VAL(FLAG_STRING));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_COMMENT", INTEGER_VAL(FLAG_COMMENT));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_TYPE", INTEGER_VAL(FLAG_TYPE));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_PRAGMA", INTEGER_VAL(FLAG_PRAGMA));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_NUMERAL", INTEGER_VAL(FLAG_NUMERAL));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_ERROR", INTEGER_VAL(FLAG_ERROR));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_DIFFPLUS", INTEGER_VAL(FLAG_DIFFPLUS));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_DIFFMINUS", INTEGER_VAL(FLAG_DIFFMINUS));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_NOTICE", INTEGER_VAL(FLAG_NOTICE));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_BOLD", INTEGER_VAL(FLAG_BOLD));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_LINK", INTEGER_VAL(FLAG_LINK));
|
||||
krk_attachNamedValue(&syntaxStateClass->fields, "FLAG_ESCAPE", INTEGER_VAL(FLAG_ESCAPE));
|
||||
krk_defineNative(&syntaxStateClass->methods, ".__getitem__", bim_krk_state_get);
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_NONE", INTEGER_VAL(FLAG_NONE));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_KEYWORD", INTEGER_VAL(FLAG_KEYWORD));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_STRING", INTEGER_VAL(FLAG_STRING));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_COMMENT", INTEGER_VAL(FLAG_COMMENT));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_TYPE", INTEGER_VAL(FLAG_TYPE));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_PRAGMA", INTEGER_VAL(FLAG_PRAGMA));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_NUMERAL", INTEGER_VAL(FLAG_NUMERAL));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_ERROR", INTEGER_VAL(FLAG_ERROR));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_DIFFPLUS", INTEGER_VAL(FLAG_DIFFPLUS));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_DIFFMINUS", INTEGER_VAL(FLAG_DIFFMINUS));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_NOTICE", INTEGER_VAL(FLAG_NOTICE));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_BOLD", INTEGER_VAL(FLAG_BOLD));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_LINK", INTEGER_VAL(FLAG_LINK));
|
||||
krk_attachNamedValue(&syntaxStateClass->methods, "FLAG_ESCAPE", INTEGER_VAL(FLAG_ESCAPE));
|
||||
|
||||
krk_finalizeClass(syntaxStateClass);
|
||||
|
||||
|
@ -22,11 +22,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __toaru__
|
||||
#include "vm.h"
|
||||
#else
|
||||
#include <kuroko/vm.h>
|
||||
#endif
|
||||
|
||||
#ifdef __DATE__
|
||||
# define BIM_BUILD_DATE " built " __DATE__ " at " __TIME__
|
||||
@ -213,6 +209,7 @@ typedef struct {
|
||||
unsigned int smart_complete:1;
|
||||
unsigned int has_terminal:1;
|
||||
unsigned int search_wraps:1;
|
||||
unsigned int had_error:1;
|
||||
|
||||
int cursor_padding;
|
||||
int split_percent;
|
||||
|
158
apps/kuroko.c
158
apps/kuroko.c
@ -29,23 +29,120 @@
|
||||
#include "memory.h"
|
||||
#include "scanner.h"
|
||||
#include "compiler.h"
|
||||
#include "util.h"
|
||||
|
||||
#define PROMPT_MAIN ">>> "
|
||||
#define PROMPT_BLOCK " > "
|
||||
|
||||
static int enableRline = 1;
|
||||
static int exitRepl = 0;
|
||||
static KrkValue exitFunc(int argc, KrkValue argv[], int hasKw) {
|
||||
static int pasteEnabled = 0;
|
||||
|
||||
KRK_FUNC(exit,{
|
||||
FUNCTION_TAKES_NONE();
|
||||
exitRepl = 1;
|
||||
})
|
||||
|
||||
KRK_FUNC(paste,{
|
||||
FUNCTION_TAKES_AT_MOST(1);
|
||||
if (argc) {
|
||||
CHECK_ARG(0,bool,int,enabled);
|
||||
pasteEnabled = enabled;
|
||||
} else {
|
||||
pasteEnabled = !pasteEnabled;
|
||||
}
|
||||
fprintf(stderr, "Pasting is %s.\n", pasteEnabled ? "enabled" : "disabled");
|
||||
})
|
||||
|
||||
static int doRead(char * buf, size_t bufSize) {
|
||||
#ifndef NO_RLINE
|
||||
if (enableRline)
|
||||
return rline(buf, bufSize);
|
||||
else
|
||||
#endif
|
||||
return read(STDIN_FILENO, buf, bufSize);
|
||||
}
|
||||
|
||||
static KrkValue readLine(char * prompt, int promptWidth, char * syntaxHighlighter) {
|
||||
struct StringBuilder sb = {0};
|
||||
|
||||
#ifndef NO_RLINE
|
||||
if (enableRline) {
|
||||
rline_exit_string = "";
|
||||
rline_exp_set_prompts(prompt, "", promptWidth, 0);
|
||||
rline_exp_set_syntax(syntaxHighlighter);
|
||||
rline_exp_set_tab_complete_func(NULL);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
fprintf(stdout, "%s", prompt);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* Read a line of input using a method that we can guarantee will be
|
||||
* interrupted by signal delivery. */
|
||||
while (1) {
|
||||
char buf[4096];
|
||||
ssize_t bytesRead = doRead(buf, 4096);
|
||||
if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) goto _exit;
|
||||
if (bytesRead < 0) {
|
||||
krk_runtimeError(vm.exceptions->ioError, "%s", strerror(errno));
|
||||
goto _exit;
|
||||
} else if (bytesRead == 0 && !sb.length) {
|
||||
krk_runtimeError(vm.exceptions->baseException, "EOF");
|
||||
goto _exit;
|
||||
} else {
|
||||
pushStringBuilderStr(&sb, buf, bytesRead);
|
||||
}
|
||||
/* Was there a linefeed? Then we can exit. */
|
||||
if (sb.length && sb.bytes[sb.length-1] == '\n') {
|
||||
sb.length--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_exit:
|
||||
discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
static int pasteEnabled = 0;
|
||||
static KrkValue paste(int argc, KrkValue argv[], int hasKw) {
|
||||
pasteEnabled = !pasteEnabled;
|
||||
fprintf(stderr, "Pasting is %s.\n", pasteEnabled ? "enabled" : "disabled");
|
||||
return NONE_VAL();
|
||||
}
|
||||
/**
|
||||
* @brief Read a line of input.
|
||||
*
|
||||
* In an interactive session, presents the configured prompt without
|
||||
* a trailing linefeed.
|
||||
*/
|
||||
KRK_FUNC(input,{
|
||||
FUNCTION_TAKES_AT_MOST(1);
|
||||
|
||||
char * prompt = "";
|
||||
int promptLength = 0;
|
||||
char * syntaxHighlighter = NULL;
|
||||
|
||||
if (argc) {
|
||||
CHECK_ARG(0,str,KrkString*,_prompt);
|
||||
prompt = _prompt->chars;
|
||||
promptLength = _prompt->codesLength;
|
||||
}
|
||||
|
||||
if (hasKw) {
|
||||
KrkValue promptwidth;
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("promptwidth")), &promptwidth)) {
|
||||
if (!IS_INTEGER(promptwidth)) return TYPE_ERROR(int,promptwidth);
|
||||
promptLength = AS_INTEGER(promptwidth);
|
||||
}
|
||||
|
||||
KrkValue syntax;
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("syntax")), &syntax)) {
|
||||
if (!IS_STRING(syntax)) return TYPE_ERROR(str,syntax);
|
||||
syntaxHighlighter = AS_CSTRING(syntax);
|
||||
}
|
||||
}
|
||||
|
||||
return readLine(prompt, promptLength, syntaxHighlighter);
|
||||
})
|
||||
|
||||
#ifndef NO_RLINE
|
||||
/**
|
||||
@ -358,7 +455,7 @@ static int debuggerHook(KrkCallFrame * frame) {
|
||||
} else {
|
||||
size_t frameCount = krk_currentThread.frameCount;
|
||||
/* Compile statement */
|
||||
KrkFunction * expression = krk_compile(arg,"<debugger>");
|
||||
KrkCodeObject * expression = krk_compile(arg,"<debugger>");
|
||||
if (expression) {
|
||||
/* Make sure stepping is disabled first. */
|
||||
krk_debug_disableSingleStep();
|
||||
@ -429,7 +526,7 @@ static int debuggerHook(KrkCallFrame * frame) {
|
||||
}
|
||||
|
||||
if (!strcmp(arg,"breakpoints")) {
|
||||
KrkFunction * codeObject = NULL;
|
||||
KrkCodeObject * codeObject = NULL;
|
||||
size_t offset = 0;
|
||||
int flags = 0;
|
||||
int enabled = 0;
|
||||
@ -521,11 +618,13 @@ _dbgQuit:
|
||||
}
|
||||
|
||||
static void handleSigint(int sigNum) {
|
||||
if (krk_currentThread.frameCount) {
|
||||
krk_currentThread.flags |= KRK_THREAD_SIGNALLED;
|
||||
}
|
||||
/* Don't set the signal flag if the VM is not running */
|
||||
if (!krk_currentThread.frameCount) return;
|
||||
krk_currentThread.flags |= KRK_THREAD_SIGNALLED;
|
||||
}
|
||||
|
||||
signal(sigNum, handleSigint);
|
||||
static void bindSignalHandlers(void) {
|
||||
signal(SIGINT, handleSigint);
|
||||
}
|
||||
|
||||
static void findInterpreter(char * argv[]) {
|
||||
@ -566,6 +665,7 @@ static int runString(char * argv[], int flags, char * string) {
|
||||
findInterpreter(argv);
|
||||
krk_initVM(flags);
|
||||
krk_startModule("__main__");
|
||||
krk_attachNamedValue(&krk_currentThread.module->fields,"__doc__", NONE_VAL());
|
||||
krk_interpret(string, "<stdin>");
|
||||
krk_freeVM();
|
||||
return 0;
|
||||
@ -595,7 +695,7 @@ static int compileFile(char * argv[], int flags, char * fileName) {
|
||||
krk_startModule("__main__");
|
||||
|
||||
/* Call the compiler directly. */
|
||||
KrkFunction * func = krk_compile(buf, fileName);
|
||||
KrkCodeObject * func = krk_compile(buf, fileName);
|
||||
|
||||
/* See if there was an exception. */
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
|
||||
@ -715,7 +815,7 @@ _finishArgs:
|
||||
for (int arg = optind; arg < argc + (optind == argc); ++arg) krk_pop();
|
||||
|
||||
/* Bind interrupt signal */
|
||||
signal(SIGINT, handleSigint);
|
||||
bindSignalHandlers();
|
||||
|
||||
#ifdef BUNDLE_LIBS
|
||||
/* Add any other modules you want to include that are normally built as shared objects. */
|
||||
@ -724,6 +824,24 @@ _finishArgs:
|
||||
|
||||
KrkValue result = INTEGER_VAL(0);
|
||||
|
||||
/**
|
||||
* Add general builtins that aren't part of the core VM.
|
||||
* This is where we provide @c input in particular.
|
||||
*/
|
||||
KRK_DOC(BIND_FUNC(vm.builtins,input), "@brief Read a line of input.\n"
|
||||
"@arguments [prompt], promptwidth=None, syntax=None\n\n"
|
||||
"Read a line of input from @c stdin. If the @c rline library is available, "
|
||||
"it will be used to gather input. Input reading stops on end-of file or when "
|
||||
"a read ends with a line feed, which will be removed from the returned string. "
|
||||
"If a prompt is provided, it will be printed without a line feed before requesting "
|
||||
"input. If @c rline is available, the prompt will be passed to the library as the "
|
||||
"left-hand prompt string. If not provided, @p promptwidth will default to the width "
|
||||
"of @p prompt in codepoints; if you are providing a prompt with escape characters or "
|
||||
"characters with multi-column East-Asian Character Width be sure to pass a value "
|
||||
"for @p promptwidth that reflects the display width of your prompt. "
|
||||
"If provided, @p syntax specifies the name of an @c rline syntax module to "
|
||||
"provide color highlighting of the input line.");
|
||||
|
||||
if (moduleAsMain) {
|
||||
krk_push(OBJECT_VAL(krk_copyString("__main__",8)));
|
||||
int out = !krk_importModule(
|
||||
@ -736,8 +854,14 @@ _finishArgs:
|
||||
return out;
|
||||
} else if (optind == argc) {
|
||||
/* Add builtins for the repl, but hide them from the globals() list. */
|
||||
krk_defineNative(&vm.builtins->fields, "exit", exitFunc);
|
||||
krk_defineNative(&vm.builtins->fields, "paste", paste);
|
||||
KRK_DOC(BIND_FUNC(vm.builtins,exit), "@brief Exit the interactive repl.\n\n"
|
||||
"Only available from the interactive interpreter; exits the repl.");
|
||||
KRK_DOC(BIND_FUNC(vm.builtins,paste), "@brief Toggle paste mode.\n"
|
||||
"@arguments enabled=None\n\n"
|
||||
"Toggles paste-safe mode, disabling automatic indentation in the repl. "
|
||||
"If @p enabled is specified, the mode can be directly specified, otherwise "
|
||||
"it will be set to the opposite of the current mode. The new mode will be "
|
||||
"printed to stderr.");
|
||||
|
||||
/* The repl runs in the context of a top-level module so each input
|
||||
* line can share a globals state with the others. */
|
||||
|
219
base/usr/include/kuroko/chunk.h
Normal file
219
base/usr/include/kuroko/chunk.h
Normal file
@ -0,0 +1,219 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file chunk.h
|
||||
* @brief Structures and enums for bytecode chunks.
|
||||
*/
|
||||
#include "kuroko.h"
|
||||
#include "value.h"
|
||||
|
||||
/**
|
||||
* @brief Instruction opcode values
|
||||
*
|
||||
* The instruction opcode table is divided in four parts. The high two bits of each
|
||||
* opcode encodes the number of operands to pull from the codeobject and thus the
|
||||
* size (generally) of the instruction (note that OP_CLOSURE(_LONG) has additional
|
||||
* arguments depending on the function it points to).
|
||||
*
|
||||
* 0-operand opcodes are "simple" instructions that generally only deal with stack
|
||||
* values and require no additional arguments.
|
||||
*
|
||||
* 1- and 3- operand opcodes are paired as 'short' and 'long'. While the VM does not
|
||||
* currently depend on these instructions having the same values in the lower 6 bits,
|
||||
* it is recommended that this property remain true.
|
||||
*
|
||||
* 2-operand opcodes are generally jump instructions.
|
||||
*/
|
||||
typedef enum {
|
||||
OP_ADD = 1,
|
||||
OP_BITAND,
|
||||
OP_BITNEGATE,
|
||||
OP_BITOR,
|
||||
OP_BITXOR,
|
||||
OP_CLEANUP_WITH,
|
||||
OP_CLOSE_UPVALUE,
|
||||
OP_DIVIDE,
|
||||
OP_DOCSTRING,
|
||||
OP_EQUAL,
|
||||
OP_FALSE,
|
||||
OP_FINALIZE,
|
||||
OP_GREATER,
|
||||
OP_INHERIT,
|
||||
OP_INVOKE_DELETE,
|
||||
OP_INVOKE_DELSLICE,
|
||||
OP_INVOKE_GETSLICE,
|
||||
OP_INVOKE_GETTER,
|
||||
OP_INVOKE_SETSLICE,
|
||||
OP_INVOKE_SETTER,
|
||||
OP_IS,
|
||||
OP_LESS,
|
||||
OP_MODULO,
|
||||
OP_MULTIPLY,
|
||||
OP_NEGATE,
|
||||
OP_NONE,
|
||||
OP_NOT,
|
||||
OP_POP,
|
||||
OP_POW,
|
||||
OP_RAISE,
|
||||
OP_RETURN,
|
||||
OP_SHIFTLEFT,
|
||||
OP_SHIFTRIGHT,
|
||||
OP_SUBTRACT,
|
||||
OP_SWAP,
|
||||
OP_TRUE,
|
||||
OP_FILTER_EXCEPT,
|
||||
OP_INVOKE_ITER,
|
||||
OP_INVOKE_CONTAINS,
|
||||
OP_BREAKPOINT, /* NEVER output this instruction in the compiler or bad things can happen */
|
||||
OP_YIELD,
|
||||
OP_ANNOTATE,
|
||||
/* current highest: 44 */
|
||||
|
||||
OP_CALL = 64,
|
||||
OP_CLASS,
|
||||
OP_CLOSURE,
|
||||
OP_CONSTANT,
|
||||
OP_DEFINE_GLOBAL,
|
||||
OP_DEL_GLOBAL,
|
||||
OP_DEL_PROPERTY,
|
||||
OP_DUP,
|
||||
OP_EXPAND_ARGS,
|
||||
OP_GET_GLOBAL,
|
||||
OP_GET_LOCAL,
|
||||
OP_GET_PROPERTY,
|
||||
OP_GET_SUPER,
|
||||
OP_GET_UPVALUE,
|
||||
OP_IMPORT,
|
||||
OP_IMPORT_FROM,
|
||||
OP_INC,
|
||||
OP_KWARGS,
|
||||
OP_CLASS_PROPERTY,
|
||||
OP_SET_GLOBAL,
|
||||
OP_SET_LOCAL,
|
||||
OP_SET_PROPERTY,
|
||||
OP_SET_UPVALUE,
|
||||
OP_TUPLE,
|
||||
OP_UNPACK,
|
||||
OP_LIST_APPEND,
|
||||
OP_DICT_SET,
|
||||
OP_SET_ADD,
|
||||
OP_MAKE_LIST,
|
||||
OP_MAKE_DICT,
|
||||
OP_MAKE_SET,
|
||||
OP_REVERSE,
|
||||
|
||||
OP_JUMP_IF_FALSE = 128,
|
||||
OP_JUMP_IF_TRUE,
|
||||
OP_JUMP,
|
||||
OP_LOOP,
|
||||
OP_PUSH_TRY,
|
||||
OP_PUSH_WITH,
|
||||
|
||||
OP_CALL_LONG = 192,
|
||||
OP_CLASS_LONG,
|
||||
OP_CLOSURE_LONG,
|
||||
OP_CONSTANT_LONG,
|
||||
OP_DEFINE_GLOBAL_LONG,
|
||||
OP_DEL_GLOBAL_LONG,
|
||||
OP_DEL_PROPERTY_LONG,
|
||||
OP_DUP_LONG,
|
||||
OP_EXPAND_ARGS_LONG,
|
||||
OP_GET_GLOBAL_LONG,
|
||||
OP_GET_LOCAL_LONG,
|
||||
OP_GET_PROPERTY_LONG,
|
||||
OP_GET_SUPER_LONG,
|
||||
OP_GET_UPVALUE_LONG,
|
||||
OP_IMPORT_LONG,
|
||||
OP_IMPORT_FROM_LONG,
|
||||
OP_INC_LONG,
|
||||
OP_KWARGS_LONG,
|
||||
OP_CLASS_PROPERTY_LONG,
|
||||
OP_SET_GLOBAL_LONG,
|
||||
OP_SET_LOCAL_LONG,
|
||||
OP_SET_PROPERTY_LONG,
|
||||
OP_SET_UPVALUE_LONG,
|
||||
OP_TUPLE_LONG,
|
||||
OP_UNPACK_LONG,
|
||||
OP_LIST_APPEND_LONG,
|
||||
OP_DICT_SET_LONG,
|
||||
OP_SET_ADD_LONG,
|
||||
OP_MAKE_LIST_LONG,
|
||||
OP_MAKE_DICT_LONG,
|
||||
OP_MAKE_SET_LONG,
|
||||
OP_REVERSE_LONG,
|
||||
} KrkOpCode;
|
||||
|
||||
/**
|
||||
* @brief Map entry of instruction offsets to line numbers.
|
||||
*
|
||||
* Each code object contains an array of line mappings, indicating
|
||||
* the start offset of each line. Since a line typically maps to
|
||||
* multiple opcodes, and spans of many lines may map to no opcodes
|
||||
* in the case of blank lines or docstrings, this array is stored
|
||||
* as a sequence of <starOffset, line> pairs rather than a simple
|
||||
* array of one or the other.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t startOffset;
|
||||
size_t line;
|
||||
} KrkLineMap;
|
||||
|
||||
/**
|
||||
* @brief Opcode chunk of a code object.
|
||||
*
|
||||
* Opcode chunks are internal to code objects and I'm not really
|
||||
* sure why we're still separating them from the KrkCodeObjects.
|
||||
*
|
||||
* Stores four flexible arrays using three different formats:
|
||||
* - Code, representing opcodes and operands.
|
||||
* - Lines, representing offset-to-line mappings.
|
||||
* - Filename, the string name of the source file.
|
||||
* - Constants, an array of values referenced by the code object.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
uint8_t * code;
|
||||
|
||||
size_t linesCount;
|
||||
size_t linesCapacity;
|
||||
KrkLineMap * lines;
|
||||
|
||||
KrkString * filename;
|
||||
KrkValueArray constants;
|
||||
} KrkChunk;
|
||||
|
||||
/**
|
||||
* @brief Initialize an opcode chunk.
|
||||
* @memberof KrkChunk
|
||||
*/
|
||||
extern void krk_initChunk(KrkChunk * chunk);
|
||||
|
||||
/**
|
||||
* @memberof KrkChunk
|
||||
* @brief Append a byte to an opcode chunk.
|
||||
*/
|
||||
extern void krk_writeChunk(KrkChunk * chunk, uint8_t byte, size_t line);
|
||||
|
||||
/**
|
||||
* @brief Release the resources allocated to an opcode chunk.
|
||||
* @memberof KrkChunk
|
||||
*/
|
||||
extern void krk_freeChunk(KrkChunk * chunk);
|
||||
|
||||
/**
|
||||
* @brief Add a new constant value to an opcode chunk.
|
||||
* @memberof KrkChunk
|
||||
*/
|
||||
extern size_t krk_addConstant(KrkChunk * chunk, KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Write an OP_CONSTANT(_LONG) instruction.
|
||||
* @memberof KrkChunk
|
||||
*/
|
||||
extern void krk_emitConstant(KrkChunk * chunk, size_t ind, size_t line);
|
||||
|
||||
/**
|
||||
* @brief Add a new constant and write an instruction for it.
|
||||
* @memberof KrkChunk
|
||||
*/
|
||||
extern size_t krk_writeConstant(KrkChunk * chunk, KrkValue value, size_t line);
|
22
base/usr/include/kuroko/compiler.h
Normal file
22
base/usr/include/kuroko/compiler.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file compiler.h
|
||||
* @brief Exported methods for the source compiler.
|
||||
*/
|
||||
#include "object.h"
|
||||
|
||||
/**
|
||||
* @brief Compile a string to a code object.
|
||||
*
|
||||
* Compiles the source string 'src' into a code object.
|
||||
*
|
||||
* @param src Source code string to compile.
|
||||
* @param fileName Path name of the source file or a representative string like "<stdin>"
|
||||
* @return The code object resulting from the compilation, or NULL if compilation failed.
|
||||
*/
|
||||
extern KrkCodeObject * krk_compile(const char * src, char * fileName);
|
||||
|
||||
/**
|
||||
* @brief Mark objects owned by the compiler as in use.
|
||||
*/
|
||||
extern void krk_markCompilerRoots(void);
|
248
base/usr/include/kuroko/debug.h
Normal file
248
base/usr/include/kuroko/debug.h
Normal file
@ -0,0 +1,248 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file debug.h
|
||||
* @brief Functions for debugging bytecode execution.
|
||||
*
|
||||
* This header provides functions for disassembly bytecode to
|
||||
* readable instruction traces, mapping bytecode offsets to
|
||||
* source code lines, and handling breakpoint instructions.
|
||||
*
|
||||
* Several of these functions are also exported to user code
|
||||
* in the @ref mod_dis module.
|
||||
*
|
||||
* Note that these functions are not related to manage code
|
||||
* exception handling, but instead inteaded to provide a low
|
||||
* level interface to the VM's execution process and allow
|
||||
* for the implementation of debuggers and debugger extensions.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "vm.h"
|
||||
#include "chunk.h"
|
||||
#include "object.h"
|
||||
|
||||
/**
|
||||
* @brief Print a disassembly of 'func' to the stream 'f'.
|
||||
*
|
||||
* Generates and prints a bytecode disassembly of the code object 'func',
|
||||
* writing it to the requested stream.
|
||||
*
|
||||
* @param f Stream to write to.
|
||||
* @param func Code object to disassemble.
|
||||
* @param name Function name to display in disassembly output.
|
||||
*/
|
||||
extern void krk_disassembleCodeObject(FILE * f, KrkCodeObject * func, const char * name);
|
||||
|
||||
/**
|
||||
* @brief Print a disassembly of a single opcode instruction.
|
||||
*
|
||||
* Generates and prints a bytecode disassembly for one instruction from
|
||||
* the code object 'func' at byte offset 'offset', printing the result to
|
||||
* the requested stream and returning the size of the instruction.
|
||||
*
|
||||
* @param f Stream to write to.
|
||||
* @param func Code object to disassemble.
|
||||
* @param offset Byte offset of the instruction to disassemble.
|
||||
* @return The size of the instruction in bytes.
|
||||
*/
|
||||
extern size_t krk_disassembleInstruction(FILE * f, KrkCodeObject * func, size_t offset);
|
||||
|
||||
/**
|
||||
* @brief Obtain the line number for a byte offset into a bytecode chunk.
|
||||
*
|
||||
* Scans the line mapping table for the given chunk to find the
|
||||
* correct line number from the original source file for the instruction
|
||||
* at byte index 'offset'.
|
||||
*
|
||||
* @param chunk Bytecode chunk containing the instruction.
|
||||
* @param offset Byte offset of the instruction to locate.
|
||||
* @return Line number, 1-indexed.
|
||||
*/
|
||||
extern size_t krk_lineNumber(KrkChunk * chunk, size_t offset);
|
||||
|
||||
/* Internal stuff */
|
||||
extern void _createAndBind_disMod(void);
|
||||
|
||||
/**
|
||||
* @brief Called by the VM when a breakpoint is encountered.
|
||||
*
|
||||
* Internal method, should not generally be called.
|
||||
*/
|
||||
extern int krk_debugBreakpointHandler(void);
|
||||
|
||||
/**
|
||||
* @brief Called by the VM on single step.
|
||||
*
|
||||
* Handles calling the registered debugger hook, if one has
|
||||
* been set, and performing the requested response action.
|
||||
* Also takes care of re-enabling REPEAT breakpoints.
|
||||
*
|
||||
* Internal method, should not generally be called.
|
||||
*/
|
||||
extern int krk_debuggerHook(KrkCallFrame * frame);
|
||||
|
||||
/**
|
||||
* @brief Function pointer for a debugger hook.
|
||||
* @ref krk_debug_registerCallback()
|
||||
*/
|
||||
typedef int (*KrkDebugCallback)(KrkCallFrame *frame);
|
||||
|
||||
/**
|
||||
* @brief Register a debugger callback.
|
||||
*
|
||||
* The registered function @p hook will be called when an
|
||||
* OP_BREAKPOINT instruction is encountered. The debugger
|
||||
* is provided a pointer to the active frame and can use
|
||||
* functions from the krk_debug_* suite to examine the
|
||||
* thread state, execute more code, and resume execution.
|
||||
*
|
||||
* The debugger hook will be called from the thread that
|
||||
* encountered the breakpoint, and should return one of
|
||||
* the KRK_DEBUGGER_ status values to inform the VM of
|
||||
* what action to take.
|
||||
*
|
||||
* @param hook The hook function to attach.
|
||||
* @return 0 if the hook was registered; 1 if a hook was
|
||||
* already registered, in which case the new hook
|
||||
* has not been registered.
|
||||
*/
|
||||
extern int krk_debug_registerCallback(KrkDebugCallback hook);
|
||||
|
||||
/**
|
||||
* @brief Add a breakpoint to the given line of a file.
|
||||
*
|
||||
* The interpreter will scan all code objects and attach
|
||||
* a breakpoint instruction to the first such object that
|
||||
* has a match filename and contains an instruction with
|
||||
* a matching line mapping. Breakpoints can only be added
|
||||
* to code which has already been compiled.
|
||||
*
|
||||
* @param filename KrkString * representation of a source
|
||||
* code filename to look for.
|
||||
* @param line The line to set the breakpoint at.
|
||||
* @param flags Allows configuring the disposition of the breakpoint.
|
||||
* @return A breakpoint identifier handle on success, or -1 on failure.
|
||||
*/
|
||||
extern int krk_debug_addBreakpointFileLine(KrkString * filename, size_t line, int flags);
|
||||
|
||||
/**
|
||||
* @brief Add a breakpoint to the given code object.
|
||||
*
|
||||
* A new breakpoint is added to the breakpoint table and
|
||||
* the code object's bytecode is overwritten to insert
|
||||
* the OP_BREAKPOINT instruction.
|
||||
*
|
||||
* Callers must ensure that @p offset points to the opcode
|
||||
* portion of an instruction, and not an operand, or the
|
||||
* attempt to add a breakpoint can corrupt the bytecode.
|
||||
*
|
||||
* @param codeObject KrkCodeObject* for the code object to break on.
|
||||
* @param offset Bytecode offset to insert the breakpoint at.
|
||||
* @param flags Allows configuring the disposition of the breakpoint.
|
||||
* @return A breakpoint identifier handle on success, or -1 on failure.
|
||||
*/
|
||||
extern int krk_debug_addBreakpointCodeOffset(KrkCodeObject * codeObject, size_t offset, int flags);
|
||||
|
||||
/**
|
||||
* @brief Remove a breakpoint from the breakpoint table.
|
||||
*
|
||||
* Removes the breakpoint @p breakpointId from the breakpoint
|
||||
* table, restoring the bytecode instruction for it if it
|
||||
* was enabled.
|
||||
*
|
||||
* @param breakpointId The breakpoint to remove.
|
||||
* @return 0 on success, 1 if the breakpoint identifier is invalid.
|
||||
*/
|
||||
extern int krk_debug_removeBreakpoint(int breakpointId);
|
||||
|
||||
/**
|
||||
* @brief Enable a breakpoint.
|
||||
*
|
||||
* Writes the OP_BREAKPOINT instruction into the function
|
||||
* bytecode chunk for the given breakpoint.
|
||||
*
|
||||
* @param breakpointId The breakpoint to enable.
|
||||
* @return 0 on success, 1 if the breakpoint identifier is invalid.
|
||||
*/
|
||||
extern int krk_debug_enableBreakpoint(int breakpointId);
|
||||
|
||||
/**
|
||||
* @brief Disable a breakpoint.
|
||||
*
|
||||
* Restores the bytecode instructions for the given breakpoint
|
||||
* if it is currently enabled.
|
||||
*
|
||||
* No error is returned if the breakpoint was already disabled.
|
||||
*
|
||||
* @param breakpointId The breakpoint to disable.
|
||||
* @return 0 on success, 1 if the breakpoint identifier is invalid.
|
||||
*/
|
||||
extern int krk_debug_disableBreakpoint(int breakpointId);
|
||||
|
||||
/**
|
||||
* @brief Enable single stepping in the current thread.
|
||||
*/
|
||||
extern void krk_debug_enableSingleStep(void);
|
||||
|
||||
/**
|
||||
* @brief Disable single stepping in the current thread.
|
||||
*/
|
||||
extern void krk_debug_disableSingleStep(void);
|
||||
|
||||
/**
|
||||
* @brief Safely dump a traceback to stderr.
|
||||
*
|
||||
* Wraps @ref krk_dumpTraceback() so it can be safely
|
||||
* called from a debugger.
|
||||
*/
|
||||
extern void krk_debug_dumpTraceback(void);
|
||||
|
||||
/**
|
||||
* @brief Retreive information on a breakpoint.
|
||||
*
|
||||
* Can be called by debuggers to examine the details of a breakpoint by its handle.
|
||||
* Information is returned through the pointers provided as parameters.
|
||||
*
|
||||
* @param breakIndex Breakpoint handle to examine.
|
||||
* @param funcOut (Out) The code object this breakpoint is in.
|
||||
* @param offsetOut (Out) The bytecode offset within the code object where the breakpoint is located.
|
||||
* @param flagsOut (Out) The configuration flags for the breakpoint.
|
||||
* @param enabledOut (Out) Whether the breakpoint is enabled or not.
|
||||
* @return 0 on success, -1 on out of range, -2 if the selected slot was removed.
|
||||
*/
|
||||
extern int krk_debug_examineBreakpoint(int breakIndex, KrkCodeObject ** funcOut, size_t * offsetOut, int * flagsOut, int *enabledOut);
|
||||
|
||||
/**
|
||||
* @brief Print the elements on the stack.
|
||||
*
|
||||
* Prints the elements on the stack for the current thread to @p file,
|
||||
* highlighting @p frame as the activate call point and indicating
|
||||
* where its arguments start.
|
||||
*/
|
||||
extern void krk_debug_dumpStack(FILE * f, KrkCallFrame * frame);
|
||||
|
||||
/**
|
||||
* @def KRK_BREAKPOINT_NORMAL
|
||||
*
|
||||
* This breakpoint should fire once and then remain in the table
|
||||
* to be re-enabled later.
|
||||
*
|
||||
* @def KRK_BREAKPOINT_ONCE
|
||||
*
|
||||
* This breakpoint should fire once and then be removed from the
|
||||
* breakpoint table.
|
||||
*
|
||||
* @def KRK_BREAKPOINT_REPEAT
|
||||
*
|
||||
* After this breakpoint has fired and execution resumes, the
|
||||
* interpreter should re-enable it to fire again until it is
|
||||
* removed by a call to @ref krk_debug_removeBreakpoint()
|
||||
*/
|
||||
#define KRK_BREAKPOINT_NORMAL 0
|
||||
#define KRK_BREAKPOINT_ONCE 1
|
||||
#define KRK_BREAKPOINT_REPEAT 2
|
||||
|
||||
#define KRK_DEBUGGER_CONTINUE 0
|
||||
#define KRK_DEBUGGER_ABORT 1
|
||||
#define KRK_DEBUGGER_STEP 2
|
||||
#define KRK_DEBUGGER_RAISE 3
|
||||
#define KRK_DEBUGGER_QUIT 4
|
37
base/usr/include/kuroko/kuroko.h
Normal file
37
base/usr/include/kuroko/kuroko.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file kuroko.h
|
||||
* @brief Top-level header with configuration macros.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
typedef long long krk_integer_type;
|
||||
# define PRIkrk_int "%lld"
|
||||
# define PRIkrk_hex "%llx"
|
||||
# define parseStrInt strtoll
|
||||
#elif defined(_WIN32)
|
||||
typedef long long krk_integer_type;
|
||||
# define PRIkrk_int "%I64d"
|
||||
# define PRIkrk_hex "%I64x"
|
||||
# define parseStrInt strtoll
|
||||
# define ENABLE_THREADING
|
||||
# else
|
||||
typedef long krk_integer_type;
|
||||
# define PRIkrk_int "%ld"
|
||||
# define PRIkrk_hex "%lx"
|
||||
# define parseStrInt strtol
|
||||
# define ENABLE_THREADING
|
||||
#endif
|
||||
|
||||
#define ENABLE_THREADING
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ENABLE_DISASSEMBLY
|
||||
#define ENABLE_TRACING
|
||||
#define ENABLE_SCAN_TRACING
|
||||
#define ENABLE_STRESS_GC
|
||||
#endif
|
||||
|
80
base/usr/include/kuroko/memory.h
Normal file
80
base/usr/include/kuroko/memory.h
Normal file
@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file memory.h
|
||||
* @brief Functions for dealing with garbage collection and memory allocation.
|
||||
*/
|
||||
#include "kuroko.h"
|
||||
#include "object.h"
|
||||
#include "table.h"
|
||||
|
||||
#define GROW_CAPACITY(c) ((c) < 8 ? 8 : (c) * 2)
|
||||
#define GROW_ARRAY(t,p,o,n) (t*)krk_reallocate(p,sizeof(t)*o,sizeof(t)*n)
|
||||
|
||||
#define FREE_ARRAY(t,a,c) krk_reallocate(a,sizeof(t) * c, 0)
|
||||
#define FREE(t,p) krk_reallocate(p,sizeof(t),0)
|
||||
|
||||
#define ALLOCATE(type, count) (type*)krk_reallocate(NULL,0,sizeof(type)*(count))
|
||||
|
||||
/**
|
||||
* @brief Resize an allocated heap object.
|
||||
*
|
||||
* Allocates or reallocates the heap object 'ptr', tracking changes
|
||||
* in sizes from 'old' to 'new'. If 'ptr' is NULL, 'old' should be 0,
|
||||
* and a new pointer will be allocated of size 'new'.
|
||||
*
|
||||
* @param ptr Heap object to resize.
|
||||
* @param old Current size of the object.
|
||||
* @param new New size of the object.
|
||||
* @return New pointer for heap object.
|
||||
*/
|
||||
extern void * krk_reallocate(void * ptr, size_t old, size_t new);
|
||||
|
||||
/**
|
||||
* @brief Release all objects.
|
||||
*
|
||||
* Generally called automatically by krk_freeVM(); releases all of
|
||||
* the GC-tracked heap objects.
|
||||
*/
|
||||
extern void krk_freeObjects(void);
|
||||
|
||||
/**
|
||||
* @brief Run a cycle of the garbage collector.
|
||||
*
|
||||
* Runs one scan-sweep cycle of the garbage collector, potentially
|
||||
* freeing unused resources and advancing potentially-unused
|
||||
* resources to the next stage of removal.
|
||||
*
|
||||
* @return The number of bytes released by this collection cycle.
|
||||
*/
|
||||
extern size_t krk_collectGarbage(void);
|
||||
|
||||
/**
|
||||
* @brief During a GC scan cycle, mark a value as used.
|
||||
*
|
||||
* When defining a new type in a C extension, this function should
|
||||
* be used by the type's _ongcscan callback to mark any values not
|
||||
* already tracked by the garbage collector.
|
||||
*
|
||||
* @param value The value to mark.
|
||||
*/
|
||||
extern void krk_markValue(KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief During a GC scan cycle, mark an object as used.
|
||||
*
|
||||
* Equivalent to krk_markValue but operates directly on an object.
|
||||
*
|
||||
* @param object The object to mark.
|
||||
*/
|
||||
extern void krk_markObject(KrkObj * object);
|
||||
|
||||
/**
|
||||
* @brief During a GC scan cycle, mark the contents of a table as used.
|
||||
*
|
||||
* Marks all keys and values in a table as used. Generally applied
|
||||
* to the internal storage of mapping types.
|
||||
*
|
||||
* @param table The table to mark.
|
||||
*/
|
||||
extern void krk_markTable(KrkTable * table);
|
||||
|
411
base/usr/include/kuroko/object.h
Normal file
411
base/usr/include/kuroko/object.h
Normal file
@ -0,0 +1,411 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file object.h
|
||||
* @brief Struct definitions for core object types.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "kuroko.h"
|
||||
#include "value.h"
|
||||
#include "chunk.h"
|
||||
#include "table.h"
|
||||
|
||||
#ifdef ENABLE_THREADING
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
KRK_OBJ_CODEOBJECT,
|
||||
KRK_OBJ_NATIVE,
|
||||
KRK_OBJ_CLOSURE,
|
||||
KRK_OBJ_STRING,
|
||||
KRK_OBJ_UPVALUE,
|
||||
KRK_OBJ_CLASS,
|
||||
KRK_OBJ_INSTANCE,
|
||||
KRK_OBJ_BOUND_METHOD,
|
||||
KRK_OBJ_TUPLE,
|
||||
KRK_OBJ_BYTES,
|
||||
} KrkObjType;
|
||||
|
||||
#undef KrkObj
|
||||
/**
|
||||
* @brief The most basic object type.
|
||||
*
|
||||
* This is the base of all object types and contains
|
||||
* the core structures for garbage collection.
|
||||
*/
|
||||
typedef struct KrkObj {
|
||||
KrkObjType type;
|
||||
unsigned char isMarked:1;
|
||||
unsigned char inRepr:1;
|
||||
unsigned char generation:2;
|
||||
unsigned char isImmortal:1;
|
||||
uint32_t hash;
|
||||
struct KrkObj * next;
|
||||
} KrkObj;
|
||||
|
||||
typedef enum {
|
||||
KRK_STRING_ASCII = 0,
|
||||
KRK_STRING_UCS1 = 1,
|
||||
KRK_STRING_UCS2 = 2,
|
||||
KRK_STRING_UCS4 = 4,
|
||||
KRK_STRING_INVALID = 5,
|
||||
} KrkStringType;
|
||||
|
||||
#undef KrkString
|
||||
/**
|
||||
* @brief Immutable sequence of Unicode codepoints.
|
||||
* @extends KrkObj
|
||||
*/
|
||||
typedef struct KrkString {
|
||||
KrkObj obj;
|
||||
KrkStringType type;
|
||||
size_t length;
|
||||
size_t codesLength;
|
||||
char * chars;
|
||||
void * codes;
|
||||
} KrkString;
|
||||
|
||||
/**
|
||||
* @brief Immutable sequence of bytes.
|
||||
* @extends KrkObj
|
||||
*/
|
||||
typedef struct {
|
||||
KrkObj obj;
|
||||
size_t length;
|
||||
uint8_t * bytes;
|
||||
} KrkBytes;
|
||||
|
||||
/**
|
||||
* @brief Storage for values referenced from nested functions.
|
||||
* @extends KrkObj
|
||||
*/
|
||||
typedef struct KrkUpvalue {
|
||||
KrkObj obj;
|
||||
int location;
|
||||
KrkValue closed;
|
||||
struct KrkUpvalue * next;
|
||||
struct KrkThreadState * owner;
|
||||
} KrkUpvalue;
|
||||
|
||||
/**
|
||||
* @brief Metadata on a local variable name in a function.
|
||||
*
|
||||
* This is used by the disassembler to print the names of
|
||||
* locals when they are referenced by instructions.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t id;
|
||||
size_t birthday;
|
||||
size_t deathday;
|
||||
KrkString * name;
|
||||
} KrkLocalEntry;
|
||||
|
||||
struct KrkInstance;
|
||||
|
||||
/**
|
||||
* @brief Code object.
|
||||
* @extends KrkObj
|
||||
*
|
||||
* Contains the static data associated with a chunk of bytecode.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkObj obj;
|
||||
short requiredArgs;
|
||||
short keywordArgs;
|
||||
size_t upvalueCount;
|
||||
KrkChunk chunk;
|
||||
KrkString * name;
|
||||
KrkString * docstring;
|
||||
KrkValueArray requiredArgNames;
|
||||
KrkValueArray keywordArgNames;
|
||||
size_t localNameCapacity;
|
||||
size_t localNameCount;
|
||||
KrkLocalEntry * localNames;
|
||||
unsigned char collectsArguments:1;
|
||||
unsigned char collectsKeywords:1;
|
||||
unsigned char isGenerator:1;
|
||||
struct KrkInstance * globalsContext;
|
||||
KrkString * qualname;
|
||||
} KrkCodeObject;
|
||||
|
||||
/**
|
||||
* @brief Function object.
|
||||
* @extends KrkObj
|
||||
*
|
||||
* Not to be confused with code objects, a closure is a single instance of a function.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkObj obj;
|
||||
KrkCodeObject * function;
|
||||
KrkUpvalue ** upvalues;
|
||||
size_t upvalueCount;
|
||||
unsigned char isClassMethod:1;
|
||||
unsigned char isStaticMethod:1;
|
||||
KrkValue annotations;
|
||||
KrkTable fields;
|
||||
} KrkClosure;
|
||||
|
||||
typedef void (*KrkCleanupCallback)(struct KrkInstance *);
|
||||
|
||||
/**
|
||||
* @brief Type object.
|
||||
* @extends KrkObj
|
||||
*
|
||||
* Represents classes defined in user code as well as classes defined
|
||||
* by C extensions to represent method tables for new types.
|
||||
*/
|
||||
typedef struct KrkClass {
|
||||
KrkObj obj;
|
||||
KrkString * name;
|
||||
KrkString * filename;
|
||||
KrkString * docstring;
|
||||
struct KrkClass * base;
|
||||
KrkTable methods;
|
||||
size_t allocSize;
|
||||
KrkCleanupCallback _ongcscan;
|
||||
KrkCleanupCallback _ongcsweep;
|
||||
|
||||
/* Quick access for common stuff */
|
||||
KrkObj * _getter;
|
||||
KrkObj * _setter;
|
||||
KrkObj * _getslice;
|
||||
KrkObj * _reprer;
|
||||
KrkObj * _tostr;
|
||||
KrkObj * _call;
|
||||
KrkObj * _init;
|
||||
KrkObj * _eq;
|
||||
KrkObj * _len;
|
||||
KrkObj * _enter;
|
||||
KrkObj * _exit;
|
||||
KrkObj * _delitem;
|
||||
KrkObj * _iter;
|
||||
KrkObj * _getattr;
|
||||
KrkObj * _dir;
|
||||
KrkObj * _setslice;
|
||||
KrkObj * _delslice;
|
||||
KrkObj * _contains;
|
||||
KrkObj * _descget;
|
||||
KrkObj * _descset;
|
||||
KrkObj * _classgetitem;
|
||||
} KrkClass;
|
||||
|
||||
/**
|
||||
* @brief An object of a class.
|
||||
* @extends KrkObj
|
||||
*
|
||||
* Created by class initializers, instances are the standard type of objects
|
||||
* built by managed code. Not all objects are instances, but all instances are
|
||||
* objects, and all instances have well-defined class.
|
||||
*/
|
||||
typedef struct KrkInstance {
|
||||
KrkObj obj;
|
||||
KrkClass * _class;
|
||||
KrkTable fields;
|
||||
} KrkInstance;
|
||||
|
||||
/**
|
||||
* @brief A function that has been attached to an object to serve as a method.
|
||||
* @extends KrkObj
|
||||
*
|
||||
* When a bound method is called, its receiver is implicitly extracted as
|
||||
* the first argument. Bound methods are created whenever a method is retreived
|
||||
* from the class of a value.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkObj obj;
|
||||
KrkValue receiver;
|
||||
KrkObj * method;
|
||||
} KrkBoundMethod;
|
||||
|
||||
typedef KrkValue (*NativeFn)(int argCount, KrkValue* args, int hasKwargs);
|
||||
|
||||
/**
|
||||
* @brief Managed binding to a C function.
|
||||
* @extends KrkObj
|
||||
*
|
||||
* Represents a C function that has been exposed to managed code.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkObj obj;
|
||||
NativeFn function;
|
||||
const char * name;
|
||||
const char * doc;
|
||||
int isMethod;
|
||||
} KrkNative;
|
||||
|
||||
/**
|
||||
* @brief Immutable sequence of arbitrary values.
|
||||
* @extends KrkObj
|
||||
*
|
||||
* Tuples are fixed-length non-mutable collections of values intended
|
||||
* for use in situations where the flexibility of a list is not needed.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkObj obj;
|
||||
KrkValueArray values;
|
||||
} KrkTuple;
|
||||
|
||||
/**
|
||||
* @brief Mutable array of values.
|
||||
* @extends KrkInstance
|
||||
*
|
||||
* A list is a flexible array of values that can be extended, cleared,
|
||||
* sorted, rearranged, iterated over, etc.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkInstance inst;
|
||||
KrkValueArray values;
|
||||
#ifdef ENABLE_THREADING
|
||||
pthread_rwlock_t rwlock;
|
||||
#endif
|
||||
} KrkList;
|
||||
|
||||
/**
|
||||
* @brief Flexible mapping type.
|
||||
* @extends KrkInstance
|
||||
*
|
||||
* Provides key-to-value mappings as a first-class object type.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkInstance inst;
|
||||
KrkTable entries;
|
||||
} KrkDict;
|
||||
|
||||
struct DictItems {
|
||||
KrkInstance inst;
|
||||
KrkValue dict;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
struct DictKeys {
|
||||
KrkInstance inst;
|
||||
KrkValue dict;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Yield ownership of a C string to the GC and obtain a string object.
|
||||
* @memberof KrkString
|
||||
*
|
||||
* Creates a string object represented by the characters in 'chars' and of
|
||||
* length 'length'. The source string must be nil-terminated and must
|
||||
* remain valid for the lifetime of the object, as its ownership is yielded
|
||||
* to the GC. Useful for strings which were allocated on the heap by
|
||||
* other mechanisms.
|
||||
*
|
||||
* 'chars' must be a nil-terminated C string representing a UTF-8
|
||||
* character sequence.
|
||||
*
|
||||
* @param chars C string to take ownership of.
|
||||
* @param length Length of the C string.
|
||||
* @return A string object.
|
||||
*/
|
||||
extern KrkString * krk_takeString(char * chars, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Obtain a string object representation of the given C string.
|
||||
* @memberof KrkString
|
||||
*
|
||||
* Converts the C string 'chars' into a string object by checking the
|
||||
* string table for it. If the string table does not have an equivalent
|
||||
* string, a new one will be created by copying 'chars'.
|
||||
*
|
||||
* 'chars' must be a nil-terminated C string representing a UTF-8
|
||||
* character sequence.
|
||||
*
|
||||
* @param chars C string to convert to a string object.
|
||||
* @param length Length of the C string.
|
||||
* @return A string object.
|
||||
*/
|
||||
extern KrkString * krk_copyString(const char * chars, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Ensure that a codepoint representation of a string is available.
|
||||
* @memberof KrkString
|
||||
*
|
||||
* Obtain an untyped pointer to the codepoint representation of a string.
|
||||
* If the string does not have a codepoint representation allocated, it will
|
||||
* be generated by this function and remain with the string for the duration
|
||||
* of its lifetime.
|
||||
*
|
||||
* @param string String to obtain the codepoint representation of.
|
||||
* @return A pointer to the bytes of the codepoint representation.
|
||||
*/
|
||||
extern void * krk_unicodeString(KrkString * string);
|
||||
|
||||
/**
|
||||
* @brief Obtain the codepoint at a given index in a string.
|
||||
* @memberof KrkString
|
||||
*
|
||||
* This is a convenience function which ensures that a Unicode codepoint
|
||||
* representation has been generated and returns the codepoint value at
|
||||
* the requested index. If you need to find multiple codepoints, it
|
||||
* is recommended that you use the KRK_STRING_FAST macro after calling
|
||||
* krk_unicodeString instead.
|
||||
*
|
||||
* @note This function does not perform any bounds checking.
|
||||
*
|
||||
* @param string String to index into.
|
||||
* @param index Offset of the codepoint to obtain.
|
||||
* @return Integer representation of the codepoint at the requested index.
|
||||
*/
|
||||
extern uint32_t krk_unicodeCodepoint(KrkString * string, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Convert an integer codepoint to a UTF-8 byte representation.
|
||||
* @memberof KrkString
|
||||
*
|
||||
* Converts a single codepoint to a sequence of bytes containing the
|
||||
* UTF-8 representation. 'out' must be allocated by the caller.
|
||||
*
|
||||
* @param value Codepoint to encode.
|
||||
* @param out Array to write UTF-8 sequence into.
|
||||
* @return The length of the UTF-8 sequence, in bytes.
|
||||
*/
|
||||
extern size_t krk_codepointToBytes(krk_integer_type value, unsigned char * out);
|
||||
|
||||
/* Internal stuff. */
|
||||
extern NativeFn KrkGenericAlias;
|
||||
extern KrkCodeObject * krk_newCodeObject(void);
|
||||
extern KrkNative * krk_newNative(NativeFn function, const char * name, int type);
|
||||
extern KrkClosure * krk_newClosure(KrkCodeObject * function);
|
||||
extern KrkUpvalue * krk_newUpvalue(int slot);
|
||||
extern KrkClass * krk_newClass(KrkString * name, KrkClass * base);
|
||||
extern KrkInstance * krk_newInstance(KrkClass * _class);
|
||||
extern KrkBoundMethod * krk_newBoundMethod(KrkValue receiver, KrkObj * method);
|
||||
extern KrkTuple * krk_newTuple(size_t length);
|
||||
extern KrkBytes * krk_newBytes(size_t length, uint8_t * source);
|
||||
extern void krk_bytesUpdateHash(KrkBytes * bytes);
|
||||
extern void krk_tupleUpdateHash(KrkTuple * self);
|
||||
|
||||
#define KRK_STRING_FAST(string,offset) (uint32_t)\
|
||||
(string->type <= 1 ? ((uint8_t*)string->codes)[offset] : \
|
||||
(string->type == 2 ? ((uint16_t*)string->codes)[offset] : \
|
||||
((uint32_t*)string->codes)[offset]))
|
||||
|
||||
#define CODEPOINT_BYTES(cp) (cp < 0x80 ? 1 : (cp < 0x800 ? 2 : (cp < 0x10000 ? 3 : 4)))
|
||||
|
||||
#define krk_isObjType(v,t) (IS_OBJECT(v) && (AS_OBJECT(v)->type == (t)))
|
||||
#define OBJECT_TYPE(value) (AS_OBJECT(value)->type)
|
||||
#define IS_STRING(value) krk_isObjType(value, KRK_OBJ_STRING)
|
||||
#define AS_STRING(value) ((KrkString *)AS_OBJECT(value))
|
||||
#define AS_CSTRING(value) (((KrkString *)AS_OBJECT(value))->chars)
|
||||
#define IS_BYTES(value) krk_isObjType(value, KRK_OBJ_BYTES)
|
||||
#define AS_BYTES(value) ((KrkBytes*)AS_OBJECT(value))
|
||||
#define IS_NATIVE(value) krk_isObjType(value, KRK_OBJ_NATIVE)
|
||||
#define AS_NATIVE(value) ((KrkNative *)AS_OBJECT(value))
|
||||
#define IS_CLOSURE(value) krk_isObjType(value, KRK_OBJ_CLOSURE)
|
||||
#define AS_CLOSURE(value) ((KrkClosure *)AS_OBJECT(value))
|
||||
#define IS_CLASS(value) krk_isObjType(value, KRK_OBJ_CLASS)
|
||||
#define AS_CLASS(value) ((KrkClass *)AS_OBJECT(value))
|
||||
#define IS_INSTANCE(value) krk_isObjType(value, KRK_OBJ_INSTANCE)
|
||||
#define AS_INSTANCE(value) ((KrkInstance *)AS_OBJECT(value))
|
||||
#define IS_BOUND_METHOD(value) krk_isObjType(value, KRK_OBJ_BOUND_METHOD)
|
||||
#define AS_BOUND_METHOD(value) ((KrkBoundMethod*)AS_OBJECT(value))
|
||||
#define IS_TUPLE(value) krk_isObjType(value, KRK_OBJ_TUPLE)
|
||||
#define AS_TUPLE(value) ((KrkTuple *)AS_OBJECT(value))
|
||||
#define AS_LIST(value) (&((KrkList *)AS_OBJECT(value))->values)
|
||||
#define AS_DICT(value) (&((KrkDict *)AS_OBJECT(value))->entries)
|
||||
|
||||
#define IS_codeobject(value) krk_isObjType(value, KRK_OBJ_CODEOBJECT)
|
||||
#define AS_codeobject(value) ((KrkCodeObject *)AS_OBJECT(value))
|
80
base/usr/include/kuroko/opcodes.h
Normal file
80
base/usr/include/kuroko/opcodes.h
Normal file
@ -0,0 +1,80 @@
|
||||
SIMPLE(OP_RETURN)
|
||||
SIMPLE(OP_ADD)
|
||||
SIMPLE(OP_SUBTRACT)
|
||||
SIMPLE(OP_MULTIPLY)
|
||||
SIMPLE(OP_DIVIDE)
|
||||
SIMPLE(OP_NEGATE)
|
||||
SIMPLE(OP_MODULO)
|
||||
SIMPLE(OP_NONE)
|
||||
SIMPLE(OP_TRUE)
|
||||
SIMPLE(OP_FALSE)
|
||||
SIMPLE(OP_NOT)
|
||||
SIMPLE(OP_EQUAL)
|
||||
SIMPLE(OP_GREATER)
|
||||
SIMPLE(OP_LESS)
|
||||
SIMPLE(OP_POP)
|
||||
SIMPLE(OP_INHERIT)
|
||||
SIMPLE(OP_RAISE)
|
||||
SIMPLE(OP_CLOSE_UPVALUE)
|
||||
SIMPLE(OP_DOCSTRING)
|
||||
SIMPLE(OP_BITOR)
|
||||
SIMPLE(OP_BITXOR)
|
||||
SIMPLE(OP_BITAND)
|
||||
SIMPLE(OP_SHIFTLEFT)
|
||||
SIMPLE(OP_SHIFTRIGHT)
|
||||
SIMPLE(OP_BITNEGATE)
|
||||
SIMPLE(OP_INVOKE_GETTER)
|
||||
SIMPLE(OP_INVOKE_SETTER)
|
||||
SIMPLE(OP_INVOKE_DELETE)
|
||||
SIMPLE(OP_INVOKE_GETSLICE)
|
||||
SIMPLE(OP_INVOKE_SETSLICE)
|
||||
SIMPLE(OP_INVOKE_DELSLICE)
|
||||
SIMPLE(OP_INVOKE_ITER)
|
||||
SIMPLE(OP_INVOKE_CONTAINS)
|
||||
SIMPLE(OP_SWAP)
|
||||
SIMPLE(OP_FINALIZE)
|
||||
SIMPLE(OP_IS)
|
||||
SIMPLE(OP_POW)
|
||||
SIMPLE(OP_CLEANUP_WITH)
|
||||
SIMPLE(OP_FILTER_EXCEPT)
|
||||
SIMPLE(OP_BREAKPOINT)
|
||||
SIMPLE(OP_YIELD)
|
||||
SIMPLE(OP_ANNOTATE)
|
||||
CONSTANT(OP_DEFINE_GLOBAL,(void)0)
|
||||
CONSTANT(OP_CONSTANT,(void)0)
|
||||
CONSTANT(OP_GET_GLOBAL,(void)0)
|
||||
CONSTANT(OP_SET_GLOBAL,(void)0)
|
||||
CONSTANT(OP_DEL_GLOBAL,(void)0)
|
||||
CONSTANT(OP_CLASS,(void)0)
|
||||
CONSTANT(OP_GET_PROPERTY, (void)0)
|
||||
CONSTANT(OP_SET_PROPERTY, (void)0)
|
||||
CONSTANT(OP_DEL_PROPERTY,(void)0)
|
||||
CONSTANT(OP_CLASS_PROPERTY, (void)0)
|
||||
CONSTANT(OP_CLOSURE, CLOSURE_MORE)
|
||||
CONSTANT(OP_IMPORT, (void)0)
|
||||
CONSTANT(OP_IMPORT_FROM, (void)0)
|
||||
CONSTANT(OP_GET_SUPER, (void)0)
|
||||
OPERAND(OP_KWARGS, (void)0)
|
||||
OPERAND(OP_SET_LOCAL, LOCAL_MORE)
|
||||
OPERAND(OP_GET_LOCAL, LOCAL_MORE)
|
||||
OPERAND(OP_SET_UPVALUE, (void)0)
|
||||
OPERAND(OP_GET_UPVALUE, (void)0)
|
||||
OPERAND(OP_CALL, (void)0)
|
||||
OPERAND(OP_INC, (void)0)
|
||||
OPERAND(OP_TUPLE, (void)0)
|
||||
OPERAND(OP_UNPACK, (void)0)
|
||||
OPERAND(OP_DUP,(void)0)
|
||||
OPERAND(OP_EXPAND_ARGS,EXPAND_ARGS_MORE)
|
||||
OPERAND(OP_LIST_APPEND, (void)0)
|
||||
OPERAND(OP_DICT_SET, (void)0)
|
||||
OPERAND(OP_SET_ADD, (void)0)
|
||||
OPERAND(OP_MAKE_LIST, (void)0)
|
||||
OPERAND(OP_MAKE_DICT, (void)0)
|
||||
OPERAND(OP_MAKE_SET, (void)0)
|
||||
OPERAND(OP_REVERSE, (void)0)
|
||||
JUMP(OP_JUMP,+)
|
||||
JUMP(OP_JUMP_IF_FALSE,+)
|
||||
JUMP(OP_JUMP_IF_TRUE,+)
|
||||
JUMP(OP_LOOP,-)
|
||||
JUMP(OP_PUSH_TRY,+)
|
||||
JUMP(OP_PUSH_WITH,+)
|
186
base/usr/include/kuroko/scanner.h
Normal file
186
base/usr/include/kuroko/scanner.h
Normal file
@ -0,0 +1,186 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file scanner.h
|
||||
* @brief Definitions used by the token scanner.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN,
|
||||
TOKEN_LEFT_BRACE, TOKEN_RIGHT_BRACE,
|
||||
TOKEN_LEFT_SQUARE, TOKEN_RIGHT_SQUARE,
|
||||
TOKEN_COLON,
|
||||
TOKEN_COMMA,
|
||||
TOKEN_DOT,
|
||||
TOKEN_MINUS,
|
||||
TOKEN_PLUS,
|
||||
TOKEN_SEMICOLON,
|
||||
TOKEN_SOLIDUS,
|
||||
TOKEN_ASTERISK,
|
||||
TOKEN_POW,
|
||||
TOKEN_MODULO,
|
||||
TOKEN_AT,
|
||||
TOKEN_CARET, /* ^ (xor) */
|
||||
TOKEN_AMPERSAND, /* & (and) */
|
||||
TOKEN_PIPE, /* | (or) */
|
||||
TOKEN_TILDE, /* ~ (negate) */
|
||||
TOKEN_LEFT_SHIFT, /* << */
|
||||
TOKEN_RIGHT_SHIFT,/* >> */
|
||||
TOKEN_BANG,
|
||||
TOKEN_GREATER,
|
||||
TOKEN_LESS,
|
||||
TOKEN_ARROW, /* -> */
|
||||
TOKEN_WALRUS, /* := */
|
||||
|
||||
/* Comparisons */
|
||||
TOKEN_GREATER_EQUAL,
|
||||
TOKEN_LESS_EQUAL,
|
||||
TOKEN_BANG_EQUAL,
|
||||
TOKEN_EQUAL_EQUAL,
|
||||
|
||||
/* Assignments */
|
||||
TOKEN_EQUAL,
|
||||
TOKEN_LSHIFT_EQUAL, /* <<= */
|
||||
TOKEN_RSHIFT_EQUAL, /* >>= */
|
||||
TOKEN_PLUS_EQUAL, /* += */
|
||||
TOKEN_MINUS_EQUAL, /* -= */
|
||||
TOKEN_PLUS_PLUS, /* ++ */
|
||||
TOKEN_MINUS_MINUS, /* -- */
|
||||
TOKEN_CARET_EQUAL,
|
||||
TOKEN_PIPE_EQUAL,
|
||||
TOKEN_AMP_EQUAL,
|
||||
TOKEN_SOLIDUS_EQUAL,
|
||||
TOKEN_ASTERISK_EQUAL,
|
||||
TOKEN_POW_EQUAL,
|
||||
TOKEN_MODULO_EQUAL,
|
||||
|
||||
TOKEN_STRING,
|
||||
TOKEN_BIG_STRING,
|
||||
TOKEN_NUMBER,
|
||||
|
||||
/*
|
||||
* Everything after this, up to indentation,
|
||||
* consists of alphanumerics.
|
||||
*/
|
||||
TOKEN_IDENTIFIER,
|
||||
TOKEN_AND,
|
||||
TOKEN_CLASS,
|
||||
TOKEN_DEF,
|
||||
TOKEN_DEL,
|
||||
TOKEN_ELSE,
|
||||
TOKEN_FALSE,
|
||||
TOKEN_FOR,
|
||||
TOKEN_IF,
|
||||
TOKEN_IMPORT,
|
||||
TOKEN_IN,
|
||||
TOKEN_IS,
|
||||
TOKEN_LET,
|
||||
TOKEN_NONE,
|
||||
TOKEN_NOT,
|
||||
TOKEN_OR,
|
||||
TOKEN_ELIF,
|
||||
TOKEN_PASS,
|
||||
TOKEN_RETURN,
|
||||
TOKEN_SELF,
|
||||
TOKEN_SUPER,
|
||||
TOKEN_TRUE,
|
||||
TOKEN_WHILE,
|
||||
TOKEN_TRY,
|
||||
TOKEN_EXCEPT,
|
||||
TOKEN_RAISE,
|
||||
TOKEN_BREAK,
|
||||
TOKEN_CONTINUE,
|
||||
TOKEN_AS,
|
||||
TOKEN_FROM,
|
||||
TOKEN_LAMBDA,
|
||||
TOKEN_ASSERT,
|
||||
TOKEN_YIELD,
|
||||
TOKEN_WITH,
|
||||
|
||||
TOKEN_PREFIX_B,
|
||||
TOKEN_PREFIX_F,
|
||||
|
||||
TOKEN_INDENTATION,
|
||||
|
||||
TOKEN_EOL,
|
||||
TOKEN_RETRY,
|
||||
TOKEN_ERROR,
|
||||
TOKEN_EOF,
|
||||
} KrkTokenType;
|
||||
|
||||
/**
|
||||
* @brief A token from the scanner.
|
||||
*
|
||||
* Represents a single scanned item from the scanner, such as a keyword,
|
||||
* string literal, numeric literal, identifier, etc.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkTokenType type;
|
||||
const char * start;
|
||||
size_t length;
|
||||
size_t line;
|
||||
const char * linePtr;
|
||||
size_t col;
|
||||
size_t literalWidth;
|
||||
} KrkToken;
|
||||
|
||||
/**
|
||||
* @brief Token scanner state.
|
||||
*
|
||||
* Stores the state of the compiler's scanner, reading from a source
|
||||
* character string and tracking the current line.
|
||||
*/
|
||||
typedef struct {
|
||||
const char * start;
|
||||
const char * cur;
|
||||
const char * linePtr;
|
||||
size_t line;
|
||||
int startOfLine;
|
||||
int hasUnget;
|
||||
KrkToken unget;
|
||||
} KrkScanner;
|
||||
|
||||
/**
|
||||
* @brief Initialize the compiler to scan tokens from 'src'.
|
||||
*
|
||||
* FIXME: There is currently only a single static scanner state;
|
||||
* along with making the compiler re-entrant, the scanner
|
||||
* needs to also be re-entrant; there's really no reason
|
||||
* these can't all just take a KrkScanner* argument.
|
||||
*/
|
||||
extern void krk_initScanner(const char * src);
|
||||
|
||||
/**
|
||||
* @brief Read the next token from the scanner.
|
||||
*
|
||||
* FIXME: Or, maybe the scanner shouldn't even be available outside
|
||||
* of the compiler, that would make some sense as well, as it's
|
||||
* a low-level detail, but we use it for tab completion in the
|
||||
* main repl, so I'm not sure that's feasible right now.
|
||||
*/
|
||||
extern KrkToken krk_scanToken(void);
|
||||
|
||||
/**
|
||||
* @brief Push a token back to the scanner to be reprocessed.
|
||||
*
|
||||
* Pushes a previously-scanned token back to the scanner.
|
||||
* Used to implement small backtracking operations at the
|
||||
* end of block constructs like 'if' and 'try'.
|
||||
*/
|
||||
extern void krk_ungetToken(KrkToken token);
|
||||
|
||||
/**
|
||||
* @brief Rewind the scanner to a previous state.
|
||||
*
|
||||
* Resets the current scanner to the state in 'to'. Used by
|
||||
* the compiler to implement comprehensions, which would otherwise
|
||||
* not be possible in a single-pass compiler.
|
||||
*/
|
||||
extern void krk_rewindScanner(KrkScanner to);
|
||||
|
||||
/**
|
||||
* @brief Retreive a copy of the current scanner state.
|
||||
*
|
||||
* Used with krk_rewindScanner() to implement rescanning
|
||||
* for comprehensions.
|
||||
*/
|
||||
extern KrkScanner krk_tellScanner(void);
|
153
base/usr/include/kuroko/table.h
Normal file
153
base/usr/include/kuroko/table.h
Normal file
@ -0,0 +1,153 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file table.h
|
||||
* @brief Implementation of a generic hash table.
|
||||
*
|
||||
* I was going to just use the ToaruOS hashmap library, but to make following
|
||||
* the book easier, let's just start from their Table implementation; it has
|
||||
* an advantage of using stored entries and fixed arrays, so it has some nice
|
||||
* properties despite being chained internally...
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "kuroko.h"
|
||||
#include "value.h"
|
||||
#include "threads.h"
|
||||
|
||||
/**
|
||||
* @brief One (key,value) pair in a table.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkValue key;
|
||||
KrkValue value;
|
||||
} KrkTableEntry;
|
||||
|
||||
/**
|
||||
* @brief Simple hash table of arbitrary keys to values.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
KrkTableEntry * entries;
|
||||
} KrkTable;
|
||||
|
||||
/**
|
||||
* @brief Initialize a hash table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* This should be called for any new hash table, especially ones
|
||||
* initialized in heap or stack space, to set up the capacity, count
|
||||
* and initial entries pointer.
|
||||
*
|
||||
* @param table Hash table to initialize.
|
||||
*/
|
||||
extern void krk_initTable(KrkTable * table);
|
||||
|
||||
/**
|
||||
* @brief Release resources associated with a hash table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Frees the entries array for the table and resets count and capacity.
|
||||
*
|
||||
* @param table Hash table to release.
|
||||
*/
|
||||
extern void krk_freeTable(KrkTable * table);
|
||||
|
||||
/**
|
||||
* @brief Add all key-value pairs from 'from' into 'to'.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Copies each key-value pair from one hash table to another. If a key
|
||||
* from 'from' already exists in 'to', the existing value in 'to' will be
|
||||
* overwritten with the value from 'from'.
|
||||
*
|
||||
* @param from Source table.
|
||||
* @param to Destination table.
|
||||
*/
|
||||
extern void krk_tableAddAll(KrkTable * from, KrkTable * to);
|
||||
|
||||
/**
|
||||
* @brief Find a character sequence in the string interning table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Scans through the entries in a given table - usually vm.strings - to find
|
||||
* an entry equivalent to the string specified by the 'chars' and 'length'
|
||||
* parameters, using the 'hash' parameter to speed up lookup.
|
||||
*
|
||||
* @param table Should always be @c &vm.strings
|
||||
* @param chars C array of chars representing the string.
|
||||
* @param length Length of the string.
|
||||
* @param hash Precalculated hash value for the string.
|
||||
* @return If the string was found, the string object representation, else NULL.
|
||||
*/
|
||||
extern KrkString * krk_tableFindString(KrkTable * table, const char * chars, size_t length, uint32_t hash);
|
||||
|
||||
/**
|
||||
* @brief Assign a value to a key in a table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Inserts the key-value pair specified by 'key' and 'value' into the hash
|
||||
* table 'table', replacing any value that was already preseng with the
|
||||
* same key.
|
||||
*
|
||||
* @param table Table to assign to.
|
||||
* @param key Key to assign.
|
||||
* @param value Value to assign to the key.
|
||||
* @return 0 if the key was already present and has been overwritten, 1 if the key is new to the table.
|
||||
*/
|
||||
extern int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Obtain the value associated with a key in a table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Scans the table 'table' for the key 'key' and, if found, outputs
|
||||
* the associated value to *value. If the key is not found, then
|
||||
* *value will not be changed.
|
||||
*
|
||||
* @param table Table to look up.
|
||||
* @param key Key to look for.
|
||||
* @param value Output pointer to place resulting value in.
|
||||
* @return 0 if the key was not found, 1 if it was.
|
||||
*/
|
||||
extern int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value);
|
||||
|
||||
/**
|
||||
* @brief Remove a key from a hash table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Scans the table 'table' for the key 'key' and, if found, removes
|
||||
* the entry, replacing it with a tombstone value.
|
||||
*
|
||||
* @param table Table to delete from.
|
||||
* @param key Key to delete.
|
||||
* @return 1 if the value was found and deleted, 0 if it was not present.
|
||||
*/
|
||||
extern int krk_tableDelete(KrkTable * table, KrkValue key);
|
||||
|
||||
/**
|
||||
* @brief Internal table scan function.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Scans through the the entry array 'entries' to find the appropriate entry
|
||||
* for 'key', return a pointer to the entry, which may be or may not have
|
||||
* an associated pair.
|
||||
*
|
||||
* @param entries Table entry array to scan.
|
||||
* @param capacity Size of the table entry array, in entries.
|
||||
* @param key Key to locate.
|
||||
* @return A pointer to the entry for 'key'.
|
||||
*/
|
||||
extern KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key);
|
||||
|
||||
/**
|
||||
* @brief Calculate the hash for a value.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Retreives or calculates the hash value for 'value'.
|
||||
*
|
||||
* @param value Value to hash.
|
||||
* @return An unsigned 32-bit hash value.
|
||||
*/
|
||||
extern uint32_t krk_hashValue(KrkValue value);
|
||||
|
41
base/usr/include/kuroko/threads.h
Normal file
41
base/usr/include/kuroko/threads.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file threads.h
|
||||
* @brief Convience header for providing atomic operations to threads.
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_THREADING
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
#define sched_yield() YieldProcessor()
|
||||
#endif
|
||||
|
||||
static inline void _krk_internal_spin_lock(int volatile * lock) {
|
||||
while(__sync_lock_test_and_set(lock, 0x01)) {
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _krk_internal_spin_unlock(int volatile * lock) {
|
||||
__sync_lock_release(lock);
|
||||
}
|
||||
|
||||
#define _obtain_lock(v) _krk_internal_spin_lock(&v);
|
||||
#define _release_lock(v) _krk_internal_spin_unlock(&v);
|
||||
|
||||
#else
|
||||
|
||||
#define _obtain_lock(v)
|
||||
#define _release_lock(v)
|
||||
|
||||
#define pthread_rwlock_init(a,b)
|
||||
#define pthread_rwlock_wrlock(a)
|
||||
#define pthread_rwlock_rdlock(a)
|
||||
#define pthread_rwlock_unlock(a)
|
||||
|
||||
#endif
|
||||
|
296
base/usr/include/kuroko/util.h
Normal file
296
base/usr/include/kuroko/util.h
Normal file
@ -0,0 +1,296 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file util.h
|
||||
* @brief Utilities for creating native bindings.
|
||||
*
|
||||
* This is intended for use in C extensions to provide a uniform interface
|
||||
* for defining extension methods and ensuring they have consistent argument
|
||||
* and keyword argument usage.
|
||||
*/
|
||||
#include "object.h"
|
||||
#include "vm.h"
|
||||
#include "memory.h"
|
||||
|
||||
/* Quick macro for turning string constants into KrkString*s */
|
||||
#define S(c) (krk_copyString(c,sizeof(c)-1))
|
||||
|
||||
#define likely(cond) __builtin_expect(!!(cond), 1)
|
||||
#define unlikely(cond) __builtin_expect(!!(cond), 0)
|
||||
#ifndef _WIN32
|
||||
#define _noexport __attribute__((visibility("hidden")))
|
||||
#else
|
||||
#define _noexport
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Binding macros.
|
||||
*
|
||||
* These macros are intended to be used together to define functions for a class.
|
||||
*/
|
||||
static inline const char * _method_name(const char * func) {
|
||||
const char * out = func;
|
||||
if (*out == '_') out++;
|
||||
while (*out && *out != '_') out++;
|
||||
if (*out == '_') out++;
|
||||
return out;
|
||||
}
|
||||
|
||||
#define ADD_BASE_CLASS(obj, name, baseClass) krk_makeClass(vm.builtins, &obj, name, baseClass)
|
||||
|
||||
/* _method_name works for this, but let's skip the inlined function call where possible */
|
||||
#define _function_name(f) (f+5)
|
||||
|
||||
#define ATTRIBUTE_NOT_ASSIGNABLE() do { if (argc != 1) return krk_runtimeError(vm.exceptions->attributeError, "attribute '%s' is not assignable", \
|
||||
_method_name(__func__)); } while (0)
|
||||
|
||||
#define METHOD_TAKES_NONE() do { if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes no arguments (%d given)", \
|
||||
_method_name(__func__), (argc-1)); } while (0)
|
||||
|
||||
#define METHOD_TAKES_EXACTLY(n) do { if (argc != (n+1)) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d argument%s (%d given)", \
|
||||
_method_name(__func__), "exactly", n, (n != 1) ? "s" : "", (argc-1)); } while (0)
|
||||
|
||||
#define METHOD_TAKES_AT_LEAST(n) do { if (argc < (n+1)) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d argument%s (%d given)", \
|
||||
_method_name(__func__), "at least", n, (n != 1) ? "s" : "", (argc-1)); } while (0)
|
||||
|
||||
#define METHOD_TAKES_AT_MOST(n) do { if (argc > (n+1)) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d argument%s (%d given)", \
|
||||
_method_name(__func__), "at most", n, (n != 1) ? "s" : "", (argc-1)); } while (0)
|
||||
|
||||
#define FUNCTION_TAKES_NONE() do { if (argc != 0) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes no arguments (%d given)", \
|
||||
_function_name(__func__), (argc)); } while (0)
|
||||
|
||||
#define FUNCTION_TAKES_EXACTLY(n) do { if (argc != n) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d argument%s (%d given)", \
|
||||
_function_name(__func__), "exactly", n, (n != 1) ? "s" : "", (argc)); } while (0)
|
||||
|
||||
#define FUNCTION_TAKES_AT_LEAST(n) do { if (argc < n) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d argument%s (%d given)", \
|
||||
_function_name(__func__), "at least", n, (n != 1) ? "s" : "", (argc)); } while (0)
|
||||
|
||||
#define FUNCTION_TAKES_AT_MOST(n) do { if (argc > n) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d argument%s (%d given)", \
|
||||
_function_name(__func__), "at most", n, (n != 1) ? "s" : "", (argc)); } while (0)
|
||||
|
||||
#define TYPE_ERROR(expected,value) krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%s'", \
|
||||
/* Function name */ _method_name(__func__), /* expected type */ #expected, krk_typeName(value))
|
||||
|
||||
#define NOT_ENOUGH_ARGS() krk_runtimeError(vm.exceptions->argumentError, "%s() missing required positional argument", \
|
||||
/* Function name */ _method_name(__func__))
|
||||
|
||||
#define CHECK_ARG(i, type, ctype, name) \
|
||||
if (argc < (i+1)) return NOT_ENOUGH_ARGS(); \
|
||||
if (!IS_ ## type (argv[i])) return TYPE_ERROR(type,argv[i]); \
|
||||
ctype name __attribute__((unused)) = AS_ ## type (argv[i])
|
||||
|
||||
#define FUNC_NAME(klass, name) _ ## klass ## _ ## name
|
||||
#define FUNC_SIG(klass, name) _noexport KrkValue FUNC_NAME(klass,name) (int argc, KrkValue argv[], int hasKw)
|
||||
#define KRK_METHOD(klass, name, body) FUNC_SIG(klass, name) { \
|
||||
CHECK_ARG(0,klass,CURRENT_CTYPE,CURRENT_NAME); \
|
||||
body; return NONE_VAL(); }
|
||||
|
||||
#define KRK_FUNC(name,body) static KrkValue _krk_ ## name (int argc, KrkValue argv[], int hasKw) { \
|
||||
body; return NONE_VAL(); }
|
||||
|
||||
/* This assumes you have a KrkInstance called `module` in the current scope. */
|
||||
#define MAKE_CLASS(klass) do { krk_makeClass(module,&klass,#klass,vm.baseClasses->objectClass); klass ->allocSize = sizeof(struct klass); } while (0)
|
||||
#define BIND_METHOD(klass,method) krk_defineNative(&klass->methods, "." #method, _ ## klass ## _ ## method)
|
||||
#define BIND_FIELD(klass,method) krk_defineNative(&klass->methods, ":" #method, _ ## klass ## _ ## method)
|
||||
#define BIND_PROP(klass,method) krk_defineNativeProperty(&klass->methods, #method, _ ## klass ## _ ## method)
|
||||
#define BIND_FUNC(module,func) krk_defineNative(&module->fields, #func, _krk_ ## func)
|
||||
|
||||
/**
|
||||
* @brief Inline flexible string array.
|
||||
*/
|
||||
struct StringBuilder {
|
||||
size_t capacity;
|
||||
size_t length;
|
||||
char * bytes;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Add a character to the end of a string builder.
|
||||
*
|
||||
* @param sb String builder to append to.
|
||||
* @param c Character to append.
|
||||
*/
|
||||
static inline void pushStringBuilder(struct StringBuilder * sb, char c) {
|
||||
if (sb->capacity < sb->length + 1) {
|
||||
size_t old = sb->capacity;
|
||||
sb->capacity = GROW_CAPACITY(old);
|
||||
sb->bytes = GROW_ARRAY(char, sb->bytes, old, sb->capacity);
|
||||
}
|
||||
sb->bytes[sb->length++] = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append a string to the end of a string builder.
|
||||
*
|
||||
* @param sb String builder to append to.
|
||||
* @param str C string to add.
|
||||
* @param len Length of the C string.
|
||||
*/
|
||||
static inline void pushStringBuilderStr(struct StringBuilder * sb, char *str, size_t len) {
|
||||
if (sb->capacity < sb->length + len) {
|
||||
while (sb->capacity < sb->length + len) {
|
||||
size_t old = sb->capacity;
|
||||
sb->capacity = GROW_CAPACITY(old);
|
||||
}
|
||||
sb->bytes = realloc(sb->bytes, sb->capacity);
|
||||
}
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
sb->bytes[sb->length++] = *(str++);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finalize a string builder into a string object.
|
||||
*
|
||||
* Creates a string object from the contents of the string builder and
|
||||
* frees the space allocated for the builder, returning a value representing
|
||||
* the newly created string object.
|
||||
*
|
||||
* @param sb String builder to finalize.
|
||||
* @return A value representing a string object.
|
||||
*/
|
||||
static inline KrkValue finishStringBuilder(struct StringBuilder * sb) {
|
||||
KrkValue out = OBJECT_VAL(krk_copyString(sb->bytes, sb->length));
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finalize a string builder in a bytes object.
|
||||
*
|
||||
* Converts the contents of a string builder into a bytes object and
|
||||
* frees the space allocated for the builder.
|
||||
*
|
||||
* @param sb String builder to finalize.
|
||||
* @return A value representing a bytes object.
|
||||
*/
|
||||
static inline KrkValue finishStringBuilderBytes(struct StringBuilder * sb) {
|
||||
KrkValue out = OBJECT_VAL(krk_newBytes(sb->length, (uint8_t*)sb->bytes));
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Discard the contents of a string builder.
|
||||
*
|
||||
* Frees the resources allocated for the string builder without converting
|
||||
* it to a string or bytes object. Call this when an error has been encountered
|
||||
* and the contents of a string builder are no longer needed.
|
||||
*
|
||||
* @param sb String builder to discard.
|
||||
* @return None, as a convenience.
|
||||
*/
|
||||
static inline KrkValue discardStringBuilder(struct StringBuilder * sb) {
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
#define IS_int(o) (IS_INTEGER(o))
|
||||
#define AS_int(o) (AS_INTEGER(o))
|
||||
|
||||
#define IS_bool(o) (IS_BOOLEAN(o))
|
||||
#define AS_bool(o) (AS_BOOLEAN(o))
|
||||
|
||||
#define IS_float(o) (IS_FLOATING(o))
|
||||
#define AS_float(o) (AS_FLOATING(o))
|
||||
|
||||
#define IS_list(o) krk_isInstanceOf(o,vm.baseClasses->listClass)
|
||||
#define AS_list(o) (KrkList*)AS_OBJECT(o)
|
||||
|
||||
#define IS_listiterator(o) krk_isInstanceOf(o,vm.baseClasses->listiteratorClass)
|
||||
#define AS_listiterator(o) AS_INSTANCE(o)
|
||||
|
||||
#define IS_str(o) (IS_STRING(o)||krk_isInstanceOf(o,vm.baseClasses->strClass))
|
||||
#define AS_str(o) (KrkString*)AS_OBJECT(o)
|
||||
|
||||
#define IS_striterator(o) (krk_isInstanceOf(o,vm.baseClasses->striteratorClass))
|
||||
#define AS_striterator(o) (AS_INSTANCE(o))
|
||||
|
||||
#define IS_dict(o) krk_isInstanceOf(o,vm.baseClasses->dictClass)
|
||||
#define AS_dict(o) (KrkDict*)AS_OBJECT(o)
|
||||
|
||||
#define IS_dictitems(o) krk_isInstanceOf(o,vm.baseClasses->dictitemsClass)
|
||||
#define AS_dictitems(o) ((struct DictItems*)AS_OBJECT(o))
|
||||
|
||||
#define IS_dictkeys(o) krk_isInstanceOf(o,vm.baseClasses->dictkeysClass)
|
||||
#define AS_dictkeys(o) ((struct DictKeys*)AS_OBJECT(o))
|
||||
|
||||
#define IS_bytesiterator(o) (krk_isInstanceOf(o,vm.baseClasses->bytesiteratorClass))
|
||||
#define AS_bytesiterator(o) (AS_INSTANCE(o))
|
||||
|
||||
#ifndef unpackError
|
||||
#define unpackError(fromInput) return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(fromInput));
|
||||
#endif
|
||||
|
||||
#define unpackIterable(fromInput) do { \
|
||||
KrkClass * type = krk_getType(fromInput); \
|
||||
if (type->_iter) { \
|
||||
size_t stackOffset = krk_currentThread.stackTop - krk_currentThread.stack; \
|
||||
krk_push(fromInput); \
|
||||
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0)); \
|
||||
do { \
|
||||
krk_push(krk_currentThread.stack[stackOffset]); \
|
||||
krk_push(krk_callSimple(krk_peek(0), 0, 1)); \
|
||||
if (krk_valuesSame(krk_currentThread.stack[stackOffset], krk_peek(0))) { \
|
||||
krk_pop(); \
|
||||
krk_pop(); \
|
||||
break; \
|
||||
} \
|
||||
unpackArray(1,krk_peek(0)); \
|
||||
krk_pop(); \
|
||||
} while (1); \
|
||||
} else { \
|
||||
unpackError(fromInput); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define unpackIterableFast(fromInput) do { \
|
||||
KrkValue iterableValue = (fromInput); \
|
||||
if (IS_TUPLE(iterableValue)) { \
|
||||
unpackArray(AS_TUPLE(iterableValue)->values.count, AS_TUPLE(iterableValue)->values.values[i]); \
|
||||
} else if (IS_INSTANCE(iterableValue) && AS_INSTANCE(iterableValue)->_class == vm.baseClasses->listClass) { \
|
||||
unpackArray(AS_LIST(iterableValue)->count, AS_LIST(iterableValue)->values[i]); \
|
||||
} else if (IS_INSTANCE(iterableValue) && AS_INSTANCE(iterableValue)->_class == vm.baseClasses->dictClass) { \
|
||||
unpackArray(AS_DICT(iterableValue)->count, krk_dict_nth_key_fast(AS_DICT(iterableValue)->capacity, AS_DICT(iterableValue)->entries, i)); \
|
||||
} else if (IS_STRING(iterableValue)) { \
|
||||
unpackArray(AS_STRING(iterableValue)->codesLength, krk_string_get(2,(KrkValue[]){iterableValue,INTEGER_VAL(i)},0)); \
|
||||
} else { \
|
||||
unpackIterable(iterableValue); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline void _setDoc_class(KrkClass * thing, const char * text, size_t size) {
|
||||
thing->docstring = krk_copyString(text, size);
|
||||
}
|
||||
static inline void _setDoc_instance(KrkInstance * thing, const char * text, size_t size) {
|
||||
krk_attachNamedObject(&thing->fields, "__doc__", (KrkObj*)krk_copyString(text, size));
|
||||
}
|
||||
static inline void _setDoc_native(KrkNative * thing, const char * text, size_t size) {
|
||||
(void)size;
|
||||
thing->doc = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @def KRK_DOC(thing,text)
|
||||
* @brief Attach documentation to a thing of various types.
|
||||
*
|
||||
* Classes store their docstrings directly, rather than in their attribute tables.
|
||||
* Instances use the attribute table and store strings with the name @c \__doc__.
|
||||
* Native functions store direct C string pointers for documentation.
|
||||
*
|
||||
* This macro provides a generic interface for applying documentation strings to
|
||||
* any of the above types, and handles not attaching documentation when built
|
||||
* with KRK_NO_DOCUMENTATION.
|
||||
*/
|
||||
#ifdef KRK_NO_DOCUMENTATION
|
||||
# define KRK_DOC(thing, text) (thing);
|
||||
#else
|
||||
# define KRK_DOC(thing, text) \
|
||||
_Generic(&((thing)[0]), \
|
||||
KrkClass*: _setDoc_class, \
|
||||
KrkInstance*: _setDoc_instance, \
|
||||
KrkNative*: _setDoc_native \
|
||||
)(thing,text,sizeof(text)-1)
|
||||
#endif
|
||||
|
||||
#define BUILTIN_FUNCTION(name, func, docStr) KRK_DOC(krk_defineNative(&vm.builtins->fields, name, func), docStr)
|
||||
|
210
base/usr/include/kuroko/value.h
Normal file
210
base/usr/include/kuroko/value.h
Normal file
@ -0,0 +1,210 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file value.h
|
||||
* @brief Definitions for primitive stack references.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "kuroko.h"
|
||||
|
||||
/**
|
||||
* @brief Base structure of all heap objects.
|
||||
*
|
||||
* KrkObj is the base type of all objects stored on the heap and
|
||||
* managed by the garbage collector.
|
||||
*/
|
||||
typedef struct KrkObj KrkObj;
|
||||
typedef struct KrkString KrkString;
|
||||
|
||||
/**
|
||||
* @brief Tag enum for basic value types.
|
||||
*
|
||||
* Value types are tagged unions of a handful of small
|
||||
* types represented directly on the stack: Integers,
|
||||
* double-precision floating point values, booleans,
|
||||
* exception handler references, complex function argument
|
||||
* processing sentinels, object reference pointers, and None.
|
||||
*/
|
||||
typedef enum {
|
||||
KRK_VAL_NONE,
|
||||
KRK_VAL_BOOLEAN,
|
||||
KRK_VAL_INTEGER,
|
||||
KRK_VAL_FLOATING,
|
||||
KRK_VAL_HANDLER,
|
||||
KRK_VAL_OBJECT,
|
||||
KRK_VAL_KWARGS,
|
||||
} KrkValueType;
|
||||
|
||||
/**
|
||||
* @brief Stack value representation of a 'with' or 'try' block.
|
||||
*
|
||||
* When a 'with' or 'try' block is entered, a handler value is
|
||||
* created on the stack representing the type (with, try) and the
|
||||
* jump target to leave the block (entering the 'except' block of
|
||||
* a 'try', if present, or calling the __exit__ method of an object
|
||||
* __enter__'d by a 'with' block). When the relevant conditions are
|
||||
* triggered in the VM, the stack will be scanned from top to bottom
|
||||
* to look for these values.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned short type;
|
||||
unsigned short target;
|
||||
} KrkJumpTarget;
|
||||
|
||||
/**
|
||||
* @brief Stack reference or primative value.
|
||||
*
|
||||
* This type stores a stack reference to an object, or the contents of
|
||||
* a primitive type. Each VM thread's stack consists of an array of
|
||||
* these values, and they are generally passed around in the VM through
|
||||
* direct copying rather than as pointers, avoiding the need to track
|
||||
* memory used by them.
|
||||
*
|
||||
* Each value is a tagged union with a type (see the enum KrkValueType)
|
||||
* and its contents.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkValueType type;
|
||||
union {
|
||||
char boolean;
|
||||
krk_integer_type integer;
|
||||
double floating;
|
||||
KrkJumpTarget handler;
|
||||
KrkObj * object;
|
||||
} as;
|
||||
} KrkValue;
|
||||
|
||||
/**
|
||||
* @brief Flexible vector of stack references.
|
||||
*
|
||||
* Value Arrays provide a resizable collection of values and are the
|
||||
* backbone of lists and tuples.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t capacity; /**< Available allocated space. */
|
||||
size_t count; /**< Current number of used slots. */
|
||||
KrkValue * values; /**< Pointer to heap-allocated storage. */
|
||||
} KrkValueArray;
|
||||
|
||||
/**
|
||||
* @brief Initialize a value array.
|
||||
* @memberof KrkValueArray
|
||||
*
|
||||
* This should be called for any new value array, especially ones
|
||||
* initialized in heap or stack space, to set up the capacity, count
|
||||
* and initial value pointer.
|
||||
*
|
||||
* @param array Value array to initialize.
|
||||
*/
|
||||
extern void krk_initValueArray(KrkValueArray * array);
|
||||
|
||||
/**
|
||||
* @brief Add a value to a value array.
|
||||
* @memberof KrkValueArray
|
||||
*
|
||||
* Appends 'value' to the end of the given array, adjusting count values
|
||||
* and resizing as necessary.
|
||||
*
|
||||
* @param array Array to append to.
|
||||
* @param value Value to append to array.
|
||||
*/
|
||||
extern void krk_writeValueArray(KrkValueArray * array, KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Release relesources used by a value array.
|
||||
* @memberof KrkValueArray
|
||||
*
|
||||
* Frees the storage associated with a given value array and resets
|
||||
* its capacity and count. Does not directly free resources associated
|
||||
* with heap objects referenced by the values in this array: The GC
|
||||
* is responsible for taking care of that.
|
||||
*
|
||||
* @param array Array to release.
|
||||
*/
|
||||
extern void krk_freeValueArray(KrkValueArray * array);
|
||||
|
||||
/**
|
||||
* @brief Print a string representation of a value.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Print a string representation of 'value' to the stream 'f'.
|
||||
* For primitives, performs appropriate formatting. For objects,
|
||||
* this will call __str__ on the object's representative type.
|
||||
* If the type does not have a __str__ method, __repr__ will be
|
||||
* tried before falling back to krk_typeName to directly print
|
||||
* the name of the class with no information on the value.
|
||||
*
|
||||
* This function provides the backend for the print() built-in.
|
||||
*
|
||||
* @param f Stream to write to.
|
||||
* @param value Value to display.
|
||||
*/
|
||||
extern void krk_printValue(FILE * f, KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Print a value without calling the VM.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Print a string representation of 'value' to the stream 'f',
|
||||
* avoiding calls to managed code by using simplified representations
|
||||
* where necessary. This is intended for use in debugging code, such
|
||||
* as during disassembly, or when printing values in an untrusted context.
|
||||
*
|
||||
* @note This function will truncate long strings and print them in a form
|
||||
* closer to the 'repr()' representation, with escaped bytes, rather
|
||||
* than directly printing them to the stream.
|
||||
*
|
||||
* @param f Stream to write to.
|
||||
* @param value Value to display.
|
||||
*/
|
||||
extern void krk_printValueSafe(FILE * f, KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Compare two values for equality.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Performs a relaxed equality comparison between two values,
|
||||
* check for equivalence by contents. This may call managed
|
||||
* code to run __eq__ methods.
|
||||
*
|
||||
* @return 1 if values are equivalent, 0 otherwise.
|
||||
*/
|
||||
extern int krk_valuesEqual(KrkValue a, KrkValue b);
|
||||
|
||||
/**
|
||||
* @brief Compare two values by identity.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Performs a strict comparison between two values, comparing
|
||||
* their identities. For primitive values, this is generally
|
||||
* the same as comparing by equality. For objects, this compares
|
||||
* pointer values directly.
|
||||
*
|
||||
* @return 1 if values represent the same object or value, 0 otherwise.
|
||||
*/
|
||||
extern int krk_valuesSame(KrkValue a, KrkValue b);
|
||||
|
||||
#define BOOLEAN_VAL(value) ((KrkValue){KRK_VAL_BOOLEAN, {.integer = value}})
|
||||
#define NONE_VAL(value) ((KrkValue){KRK_VAL_NONE, {.integer = 0}})
|
||||
#define INTEGER_VAL(value) ((KrkValue){KRK_VAL_INTEGER, {.integer = value}})
|
||||
#define FLOATING_VAL(value) ((KrkValue){KRK_VAL_FLOATING,{.floating = value}})
|
||||
#define HANDLER_VAL(ty,ta) ((KrkValue){KRK_VAL_HANDLER, {.handler = (KrkJumpTarget){.type = ty, .target = ta}}})
|
||||
#define OBJECT_VAL(value) ((KrkValue){KRK_VAL_OBJECT, {.object = (KrkObj*)value}})
|
||||
#define KWARGS_VAL(value) ((KrkValue){KRK_VAL_KWARGS, {.integer = value}})
|
||||
|
||||
#define AS_BOOLEAN(value) ((value).as.integer)
|
||||
#define AS_INTEGER(value) ((value).as.integer)
|
||||
#define AS_FLOATING(value) ((value).as.floating)
|
||||
#define AS_HANDLER(value) ((value).as.handler)
|
||||
#define AS_OBJECT(value) ((value).as.object)
|
||||
|
||||
#define IS_BOOLEAN(value) ((value).type == KRK_VAL_BOOLEAN)
|
||||
#define IS_NONE(value) ((value).type == KRK_VAL_NONE)
|
||||
#define IS_INTEGER(value) (((value).type == KRK_VAL_INTEGER) || ((value.type) == KRK_VAL_BOOLEAN))
|
||||
#define IS_FLOATING(value) ((value).type == KRK_VAL_FLOATING)
|
||||
#define IS_HANDLER(value) ((value).type == KRK_VAL_HANDLER)
|
||||
#define IS_OBJECT(value) ((value).type == KRK_VAL_OBJECT)
|
||||
#define IS_KWARGS(value) ((value).type == KRK_VAL_KWARGS)
|
||||
|
||||
#define IS_TRY_HANDLER(value) (IS_HANDLER(value) && AS_HANDLER(value).type == OP_PUSH_TRY)
|
||||
#define IS_WITH_HANDLER(value) (IS_HANDLER(value) && AS_HANDLER(value).type == OP_PUSH_WITH)
|
||||
|
820
base/usr/include/kuroko/vm.h
Normal file
820
base/usr/include/kuroko/vm.h
Normal file
@ -0,0 +1,820 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file vm.h
|
||||
* @brief Core API for the bytecode virtual machine.
|
||||
*
|
||||
* Functions and structures declared here make up the bulk of the public C API
|
||||
* for Kuroko, including initializing the VM and passing code to be interpreted.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include "kuroko.h"
|
||||
#include "value.h"
|
||||
#include "table.h"
|
||||
#include "object.h"
|
||||
|
||||
/**
|
||||
* @def KRK_CALL_FRAMES_MAX
|
||||
* @brief Maximum depth of the call stack in managed-code function calls.
|
||||
*/
|
||||
#define KRK_CALL_FRAMES_MAX 64
|
||||
|
||||
/**
|
||||
* @def KRK_THREAD_SCRATCH_SIZE
|
||||
* @brief Extra space for each thread to store a set of working values safe from the GC.
|
||||
*
|
||||
* Various operations require threads to remove values from the stack but ensure
|
||||
* they are not lost to garbage collection. This space allows each thread to keep
|
||||
* a few things around during those operations.
|
||||
*/
|
||||
#define KRK_THREAD_SCRATCH_SIZE 3
|
||||
|
||||
/**
|
||||
* @brief Represents a managed call state in a VM thread.
|
||||
*
|
||||
* For every managed function call, including the top-level module,
|
||||
* a call frame is added to the stack to track the running function,
|
||||
* the current opcode instruction, the offset into the stack, and
|
||||
* the valid globals table.
|
||||
*
|
||||
* Call frames are used directly by the VM as the source of
|
||||
* opcodes and operands during execution, and are used by the exception
|
||||
* handler to roll back execution to the appropriate environment.
|
||||
*/
|
||||
typedef struct {
|
||||
KrkClosure * closure; /**< Pointer to the function object containing the code object for this frame */
|
||||
uint8_t * ip; /**< Instruction pointer within the code object's bytecode data */
|
||||
size_t slots; /**< Offset into the stack at which this function call's arguments begin */
|
||||
size_t outSlots; /**< Offset into the stack at which stackTop will be reset upon return */
|
||||
KrkTable * globals; /**< Pointer to the attribute table containing valud global vairables for this call */
|
||||
} KrkCallFrame;
|
||||
|
||||
/**
|
||||
* @brief Index numbers for always-available interned strings representing important method and member names.
|
||||
*
|
||||
* The VM must look up many methods and members by fixed names. To avoid
|
||||
* continuously having to box and unbox these from C strings to the appropriate
|
||||
* interned @c KrkString, we keep an array of the @c KrkString pointers in the global VM state.
|
||||
*
|
||||
* These values are the offsets into that index for each of the relevant
|
||||
* function names (generally with extra underscores removed). For example
|
||||
* @c METHOD_INIT is the offset for the string value for @c "__init__".
|
||||
*/
|
||||
typedef enum {
|
||||
METHOD_INIT,
|
||||
METHOD_STR,
|
||||
METHOD_REPR,
|
||||
METHOD_GET,
|
||||
METHOD_SET,
|
||||
METHOD_CLASS,
|
||||
METHOD_NAME,
|
||||
METHOD_FILE,
|
||||
METHOD_INT,
|
||||
METHOD_FLOAT,
|
||||
METHOD_CHR,
|
||||
METHOD_LEN,
|
||||
METHOD_DOC,
|
||||
METHOD_BASE,
|
||||
METHOD_GETSLICE,
|
||||
METHOD_ORD,
|
||||
METHOD_CALL,
|
||||
METHOD_EQ,
|
||||
METHOD_ENTER,
|
||||
METHOD_EXIT,
|
||||
METHOD_DELITEM,
|
||||
METHOD_ITER,
|
||||
METHOD_GETATTR,
|
||||
METHOD_DIR,
|
||||
METHOD_SETSLICE,
|
||||
METHOD_DELSLICE,
|
||||
METHOD_CONTAINS,
|
||||
METHOD_DESCGET,
|
||||
METHOD_DESCSET,
|
||||
METHOD_CLASSGETITEM,
|
||||
|
||||
METHOD__MAX,
|
||||
} KrkSpecialMethods;
|
||||
|
||||
/**
|
||||
* @brief Table of basic exception types.
|
||||
*
|
||||
* These are the core exception types, available in managed code
|
||||
* from the builtin namespace. A single instance of this struct
|
||||
* is attached to the global VM state so that C code can quickly
|
||||
* access these exception types for use with krk_runtimeException.
|
||||
*
|
||||
* @see krk_runtimeException
|
||||
*/
|
||||
struct Exceptions {
|
||||
KrkClass * baseException; /**< @exception Exception The base exception type. */
|
||||
KrkClass * typeError; /**< @exception TypeError An argument or value was not of the expected type. */
|
||||
KrkClass * argumentError; /**< @exception ArgumentException The number of arguments passed to a function was not as expected. */
|
||||
KrkClass * indexError; /**< @exception IndexError An attempt was made to reference an invalid array index. */
|
||||
KrkClass * keyError; /**< @exception KeyError An attempt was made to reference an invalid mapping key. */
|
||||
KrkClass * attributeError; /**< @exception AttributeError An attempt was made to reference an invalid object property. */
|
||||
KrkClass * nameError; /**< @exception NameError An attempt was made to reference an undeclared global variable. */
|
||||
KrkClass * importError; /**< @exception ImportError An error was encountered when attempting to import a module. */
|
||||
KrkClass * ioError; /**< @exception IOError An error was encountered in operating system's IO library. */
|
||||
KrkClass * valueError; /**< @exception ValueError The value of a parameter or variable is not valid. */
|
||||
KrkClass * keyboardInterrupt; /**< @exception KeyboardInterrupt An interrupt signal was received. */
|
||||
KrkClass * zeroDivisionError; /**< @exception ZeroDivisionError A mathematical function attempted to divide by zero. */
|
||||
KrkClass * notImplementedError; /**< @exception NotImplementedError The method is not implemented, either for the given arguments or in general. */
|
||||
KrkClass * syntaxError; /**< @exception SyntaxError The compiler encountered an unrecognized or invalid source code input. */
|
||||
KrkClass * assertionError; /**< @exception AssertionError An @c assert statement failed. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Table of classes for built-in object types.
|
||||
*
|
||||
* For use by C modules and within the VM, an instance of this struct
|
||||
* is attached to the global VM state. At VM initialization, each
|
||||
* built-in class is attached to this table, and the class values
|
||||
* stored here are used for integrated type checking with krk_isInstanceOf.
|
||||
*
|
||||
* @note As this and other tables are used directly by embedders, do not
|
||||
* reorder the layout of the individual class pointers, even if
|
||||
* it looks nicer. The ordering here is part of our library ABI.
|
||||
*/
|
||||
struct BaseClasses {
|
||||
KrkClass * objectClass; /**< The base of all classes within the type tree. */
|
||||
KrkClass * moduleClass; /**< A class for representing imported modules, both managed and C. */
|
||||
KrkClass * typeClass; /**< Classes themselves are of this class. */
|
||||
KrkClass * intClass; /**< Primitive integer type. */
|
||||
KrkClass * floatClass; /**< Primitive double-precision floating-point type. */
|
||||
KrkClass * boolClass; /**< Primitive boolean type. */
|
||||
KrkClass * noneTypeClass; /**< The class of the None value. */
|
||||
KrkClass * strClass; /**< Built-in Unicode string type. */
|
||||
KrkClass * functionClass; /**< Represents a function object (KrkClosure) or native bind (KrkNative) */
|
||||
KrkClass * methodClass; /**< Represents a bound method (KrkBoundMethod) */
|
||||
KrkClass * tupleClass; /**< An immutable collection of arbitrary values. */
|
||||
KrkClass * bytesClass; /**< An immutable sequence of bytes. */
|
||||
KrkClass * listiteratorClass; /**< Iterator over lists */
|
||||
KrkClass * rangeClass; /**< An object representing a start and end point for a sequence of integers. */
|
||||
KrkClass * rangeiteratorClass; /**< Iterator over a range of values */
|
||||
KrkClass * striteratorClass; /**< Iterator over characters (by codepoint) in a string */
|
||||
KrkClass * tupleiteratorClass; /**< Iterator over values in a tuple */
|
||||
KrkClass * listClass; /**< Mutable collection of arbitrary values. */
|
||||
KrkClass * dictClass; /**< Mutable mapping of hashable keys to arbitrary values. */
|
||||
KrkClass * dictitemsClass; /**< Iterator over the (key,value) pairs of a dict */
|
||||
KrkClass * dictkeysClass; /**< Iterator over the keys of a dict */
|
||||
KrkClass * bytesiteratorClass; /**< Iterator over the integer byte values of a bytes object. */
|
||||
KrkClass * propertyClass; /**< Magic object that calls a function when accessed from an instance through the dot operator. */
|
||||
KrkClass * codeobjectClass; /**< Static compiled bytecode container (KrkCodeObject) */
|
||||
KrkClass * generatorClass; /**< Generator object. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Execution state of a VM thread.
|
||||
*
|
||||
* Each thread in the VM has its own local thread state, which contains
|
||||
* the thread's stack, stack pointer, call frame stack, a thread-specific
|
||||
* VM flags bitarray, and an exception state.
|
||||
*
|
||||
* @see krk_currentThread
|
||||
*/
|
||||
typedef struct KrkThreadState {
|
||||
struct KrkThreadState * next; /**< Invasive list pointer to next thread. */
|
||||
|
||||
KrkCallFrame * frames; /**< Call frame stack for this thread, max KRK_CALL_FRAMES_MAX */
|
||||
size_t frameCount; /**< Number of active call frames. */
|
||||
size_t stackSize; /**< Size of the allocated stack space for this thread. */
|
||||
KrkValue * stack; /**< Pointer to the bottom of the stack for this thread. */
|
||||
KrkValue * stackTop; /**< Pointer to the top of the stack. */
|
||||
KrkUpvalue * openUpvalues; /**< Flexible array of unclosed upvalues. */
|
||||
ssize_t exitOnFrame; /**< When called in a nested context, the frame offset to exit the VM dispatch loop on. */
|
||||
|
||||
KrkInstance * module; /**< The current module execution context. */
|
||||
KrkValue currentException; /**< When an exception is thrown, it is stored here. */
|
||||
int flags; /**< Thread-local VM flags; each thread inherits the low byte of the global VM flags. */
|
||||
long watchdog; /**< Decrementing watchdog timer for embedding. */
|
||||
|
||||
KrkValue scratchSpace[KRK_THREAD_SCRATCH_SIZE]; /**< A place to store a few values to keep them from being prematurely GC'd. */
|
||||
} KrkThreadState;
|
||||
|
||||
/**
|
||||
* @brief Global VM state.
|
||||
*
|
||||
* This state is shared by all VM threads and stores the
|
||||
* path to the VM binary, global execution flags, the
|
||||
* string and module tables, tables of builtin types,
|
||||
* and the state of the (shared) garbage collector.
|
||||
*/
|
||||
typedef struct KrkVM {
|
||||
int globalFlags; /**< Global VM state flags */
|
||||
char * binpath; /**< A string representing the name of the interpreter binary. */
|
||||
KrkTable strings; /**< Strings table */
|
||||
KrkTable modules; /**< Module cache */
|
||||
KrkInstance * builtins; /**< '\__builtins__' module */
|
||||
KrkInstance * system; /**< 'kuroko' module */
|
||||
KrkValue * specialMethodNames; /**< Cached strings of important method and function names */
|
||||
struct BaseClasses * baseClasses; /**< Pointer to a (static) namespacing struct for the KrkClass*'s of built-in object types */
|
||||
struct Exceptions * exceptions; /**< Pointer to a (static) namespacing struct for the KrkClass*'s of basic exception types */
|
||||
|
||||
/* Garbage collector state */
|
||||
KrkObj * objects; /**< Linked list of all objects in the GC */
|
||||
size_t bytesAllocated; /**< Running total of bytes allocated */
|
||||
size_t nextGC; /**< Point at which we should sweep again */
|
||||
size_t grayCount; /**< Count of objects marked by scan. */
|
||||
size_t grayCapacity; /**< How many objects we can fit in the scan list. */
|
||||
KrkObj** grayStack; /**< Scan list */
|
||||
|
||||
KrkThreadState * threads; /**< Invasive linked list of all VM threads. */
|
||||
} KrkVM;
|
||||
|
||||
/* Thread-specific flags */
|
||||
#define KRK_THREAD_ENABLE_TRACING (1 << 0)
|
||||
#define KRK_THREAD_ENABLE_DISASSEMBLY (1 << 1)
|
||||
#define KRK_THREAD_ENABLE_SCAN_TRACING (1 << 2)
|
||||
#define KRK_THREAD_HAS_EXCEPTION (1 << 3)
|
||||
#define KRK_THREAD_SINGLE_STEP (1 << 4)
|
||||
#define KRK_THREAD_SIGNALLED (1 << 5)
|
||||
|
||||
/* Global flags */
|
||||
#define KRK_GLOBAL_ENABLE_STRESS_GC (1 << 8)
|
||||
#define KRK_GLOBAL_GC_PAUSED (1 << 9)
|
||||
#define KRK_GLOBAL_CLEAN_OUTPUT (1 << 10)
|
||||
|
||||
#ifdef ENABLE_THREADING
|
||||
# define threadLocal __thread
|
||||
#else
|
||||
# define threadLocal
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Thread-local VM state.
|
||||
*
|
||||
* See @c KrkThreadState for more information.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(KRKINLIB)
|
||||
#define krk_currentThread (*krk_getCurrentThread())
|
||||
#else
|
||||
extern threadLocal KrkThreadState krk_currentThread;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Singleton instance of the shared VM state.
|
||||
*/
|
||||
extern KrkVM krk_vm;
|
||||
|
||||
/**
|
||||
* @def vm
|
||||
* @brief Convenience macro for namespacing.
|
||||
*/
|
||||
#define vm krk_vm
|
||||
|
||||
/**
|
||||
* @brief Initialize the VM at program startup.
|
||||
* @memberof KrkVM
|
||||
*
|
||||
* All library users must call this exactly once on startup to create
|
||||
* the built-in types, modules, and functions for the VM and prepare
|
||||
* the string and module tables. Optionally, callers may set `vm.binpath`
|
||||
* before calling krk_initVM to allow the VM to locate the interpreter
|
||||
* binary and establish the default module paths.
|
||||
*
|
||||
* @param flags Combination of global VM flags and initial thread flags.
|
||||
*/
|
||||
extern void krk_initVM(int flags);
|
||||
|
||||
/**
|
||||
* @brief Release resources from the VM.
|
||||
* @memberof KrkVM
|
||||
*
|
||||
* Generally, it is desirable to call this once before the hosting program exits.
|
||||
* If a fresh VM state is needed, krk_freeVM should be called before a further
|
||||
* call to krk_initVM is made. The resources released here can include allocated
|
||||
* heap memory, FILE pointers or descriptors, or various other things which were
|
||||
* initialized by C extension modules.
|
||||
*/
|
||||
extern void krk_freeVM(void);
|
||||
|
||||
/**
|
||||
* @brief Reset the current thread's stack state to the top level.
|
||||
*
|
||||
* In a repl, this should be called before or after each iteration to clean up any
|
||||
* remnant stack entries from an uncaught exception. It should not be called
|
||||
* during normal execution by C extensions. Values on the stack may be lost
|
||||
* to garbage collection after a call to @c krk_resetStack .
|
||||
*/
|
||||
extern void krk_resetStack(void);
|
||||
|
||||
/**
|
||||
* @brief Compile and execute a source code input.
|
||||
*
|
||||
* This is the lowest level call for most usecases, including execution
|
||||
* of commands from a REPL or when executing a file.
|
||||
*
|
||||
* @param src Source code to compile and run.
|
||||
* @param fromFile Path to the source file, or a representative string like "<stdin>".
|
||||
* @return The value of the executed code, which is either the value of an explicit 'return'
|
||||
* statement, or the last expression value from an executed statement. If an uncaught
|
||||
* exception occurred, this will be @c None and @c krk_currentThread.flags should
|
||||
* indicate @c KRK_THREAD_HAS_EXCEPTION and @c krk_currentThread.currentException
|
||||
* should contain the raised exception value.
|
||||
*/
|
||||
extern KrkValue krk_interpret(const char * src, char * fromFile);
|
||||
|
||||
/**
|
||||
* @brief Load and run a source file and return when execution completes.
|
||||
*
|
||||
* Loads and runs a source file. Can be used by interpreters to run scripts,
|
||||
* either in the context of a new a module or as if they were continuations
|
||||
* of the current module state (eg. as if they were lines entered on a repl)
|
||||
*
|
||||
* @param fileName Path to the source file to read and execute.
|
||||
* @param fromFile Value to assign to @c \__file__
|
||||
* @return As with @c krk_interpret, an object representing the newly created module,
|
||||
* or the final return value of the VM execution.
|
||||
*/
|
||||
extern KrkValue krk_runfile(const char * fileName, char * fromFile);
|
||||
|
||||
/**
|
||||
* @brief Load and run a file as a module.
|
||||
*
|
||||
* Similar to @c krk_runfile but ensures that execution of the VM returns to the caller
|
||||
* after the file is run. This should be run after calling @c krk_startModule to initialize
|
||||
* a new module context and is used internally by the import mechanism.
|
||||
*
|
||||
* @param fileName Path to the source file to read and execute.
|
||||
* @param fromFile Value to assign to @c \__file__
|
||||
* @return The object representing the module, or None if execution of the file failed.
|
||||
*/
|
||||
extern KrkValue krk_callfile(const char * fileName, char * fromFile);
|
||||
|
||||
/**
|
||||
* @brief Push a stack value.
|
||||
*
|
||||
* Pushes a value onto the current thread's stack, triggering a
|
||||
* stack resize if there is not enough space to hold the new value.
|
||||
*
|
||||
* @param value Value to push.
|
||||
*/
|
||||
extern void krk_push(KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Pop the top of the stack.
|
||||
*
|
||||
* Removes and returns the value at the top of current thread's stack.
|
||||
* Generally, it is preferably to leave values on the stack and use
|
||||
* krk_peek if the value is desired, as removing a value from the stack
|
||||
* may result in it being garbage collected.
|
||||
*
|
||||
* @return The value previously at the top of the stack.
|
||||
*/
|
||||
extern KrkValue krk_pop(void);
|
||||
|
||||
/**
|
||||
* @brief Peek down from the top of the stack.
|
||||
*
|
||||
* Obtains a value from the current thread's stack without modifying the stack.
|
||||
*
|
||||
* @param distance How far down from the top of the stack to peek (0 = the top)
|
||||
* @return The value from the stack.
|
||||
*/
|
||||
extern KrkValue krk_peek(int distance);
|
||||
|
||||
/**
|
||||
* @brief Swap the top of the stack of the value @p distance slots down.
|
||||
*
|
||||
* Exchanges the values at the top of the stack and @p distance slots from the top
|
||||
* without removing or shuffling anything in between.
|
||||
*
|
||||
* @param distance How from down from the top of the stack to swap (0 = the top)
|
||||
*/
|
||||
extern void krk_swap(int distance);
|
||||
|
||||
/**
|
||||
* @brief Get the name of the type of a value.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Obtains the C string representing the name of the class
|
||||
* associated with the given value. Useful for crafting
|
||||
* exception messages, such as those describing TypeErrors.
|
||||
*
|
||||
* @param value Value to examine
|
||||
* @return Nul-terminated C string of the type of @p value
|
||||
*/
|
||||
extern const char * krk_typeName(KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Attach a native C function to an attribute table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Attaches the given native function pointer to an attribute table
|
||||
* while managing the stack shuffling and boxing of both the name and
|
||||
* the function object. If @p name begins with a '.', the native function
|
||||
* is marked as a method. If @p name begins with a ':', the native function
|
||||
* is marked as a dynamic property.
|
||||
*
|
||||
* @param table Attribute table to attach to, such as @c &someInstance->fields
|
||||
* @param name Nil-terminated C string with the name to assign
|
||||
* @param function Native function pointer to attach
|
||||
* @return A pointer to the object representing the attached function.
|
||||
*/
|
||||
extern KrkNative * krk_defineNative(KrkTable * table, const char * name, NativeFn function);
|
||||
|
||||
/**
|
||||
* @brief Attach a native dynamic property to an attribute table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Mostly the same as @c krk_defineNative, but ensures the creation of a dynamic property.
|
||||
* The intention of this function is to replace uses of defineNative with ":" names,
|
||||
* and replace specialized methods with @c KrkProperty* objects.
|
||||
*
|
||||
* @param table Attribute table to attach to, such as @c &someInstance->fields
|
||||
* @param name Nil-terminated C string with the name to assign
|
||||
* @param func Native function pointer to attach
|
||||
* @return A pointer to the property object created.
|
||||
*/
|
||||
extern KrkNative * krk_defineNativeProperty(KrkTable * table, const char * name, NativeFn func);
|
||||
|
||||
/**
|
||||
* @brief Attach a value to an attribute table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Manages the stack shuffling and boxing of the name string when attaching
|
||||
* a value to an attribute table. Rather than using @c krk_tableSet, this is
|
||||
* the preferred method of supplying fields to objects from C code.
|
||||
*
|
||||
* @param table Attribute table to attach to, such as @c &someInstance->fields
|
||||
* @param name Nil-terminated C string with the name to assign
|
||||
* @param obj Value to attach.
|
||||
*/
|
||||
extern void krk_attachNamedValue(KrkTable * table, const char name[], KrkValue obj);
|
||||
|
||||
/**
|
||||
* @brief Attach an object to an attribute table.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Manages the stack shuffling and boxing of the name string when attaching
|
||||
* an object to an attribute table. Rather than using @c krk_tableSet, this is
|
||||
* the preferred method of supplying fields to objects from C code.
|
||||
*
|
||||
* This is a convenience wrapper around @c krk_attachNamedValue.
|
||||
*
|
||||
* @param table Attribute table to attach to, such as @c &someInstance->fields
|
||||
* @param name Nil-terminated C string with the name to assign
|
||||
* @param obj Object to attach.
|
||||
*/
|
||||
extern void krk_attachNamedObject(KrkTable * table, const char name[], KrkObj * obj);
|
||||
|
||||
/**
|
||||
* @brief Raise an exception.
|
||||
*
|
||||
* Creates an instance of the given exception type, passing a formatted
|
||||
* string to the initializer. All of the core exception types take an option
|
||||
* string value to attach to the exception, but third-party exception types
|
||||
* may have different initializer signatures and need separate initialization.
|
||||
*
|
||||
* The created exception object is attached to the current thread state and
|
||||
* the @c KRK_THREAD_HAS_EXCEPTION flag is set.
|
||||
*
|
||||
* @param type Class pointer for the exception type, eg. @c vm.exceptions->valueError
|
||||
* @param fmt Format string.
|
||||
* @return As a convenience to C extension authors, returns @c None
|
||||
*/
|
||||
extern KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the current thread state.
|
||||
*
|
||||
* Generally equivalent to @c &krk_currentThread, though @c krk_currentThread
|
||||
* itself may be implemented as a macro that calls this function depending
|
||||
* on the platform's thread support.
|
||||
*
|
||||
* @return Pointer to current thread's thread state.
|
||||
*/
|
||||
extern KrkThreadState * krk_getCurrentThread(void);
|
||||
|
||||
/**
|
||||
* @brief Continue VM execution until the next exit trigger.
|
||||
*
|
||||
* Resumes the VM dispatch loop, returning to the caller when
|
||||
* the next exit trigger event happens. Generally, callers will
|
||||
* want to set the current thread's exitOnFrame before calling
|
||||
* @c krk_runNext. Alternatively, see @c krk_callValue which manages
|
||||
* exit triggers automatically when calling function objects.
|
||||
*
|
||||
* @return Value returned by the exit trigger, generally the value
|
||||
* returned by the inner function before the VM returned
|
||||
* to the exit frame.
|
||||
*/
|
||||
extern KrkValue krk_runNext(void);
|
||||
|
||||
/**
|
||||
* @brief Get the class representing a value.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Returns the class object representing the type of a value.
|
||||
* This may be the direct class of an instance, or a pseudoclass
|
||||
* for other value types.
|
||||
*
|
||||
* @param value Reference value to examine.
|
||||
* @return A pointer to the value's type's class object.
|
||||
*/
|
||||
extern KrkClass * krk_getType(KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Determine if a class is an instance or subclass of a given type.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Searches the class hierarchy of the given value to determine if it is
|
||||
* a subtype of @p type. As this chains through the inheritence tree, the
|
||||
* more deeply subclassed @p obj is, the longer it may take to determine
|
||||
* if it is a subtype of @p type. All types should eventually be subtypes
|
||||
* of the @ref object type, so this condition should not be checked. For
|
||||
* some types, convenience macros are available. If you need to check if
|
||||
* @p obj is a specific type, exclusive of subtypes, look at
|
||||
* @c krk_getType() instead of using this function.
|
||||
*
|
||||
* @param obj Value to examine.
|
||||
* @param type Class object to test for membership of.
|
||||
* @return 1 if @p obj is an instance of @p type or of a subclass of @p type
|
||||
*/
|
||||
extern int krk_isInstanceOf(KrkValue obj, KrkClass * type);
|
||||
|
||||
/**
|
||||
* @brief Perform method binding on the stack.
|
||||
* @memberof KrkClass
|
||||
*
|
||||
* Performs attribute lookup from the class @p _class for @p name.
|
||||
* If @p name is not a valid method, the binding fails.
|
||||
* If @p name is a valid method, the method will be retrieved and
|
||||
* bound to the instance on the top of the stack, replacing it
|
||||
* with a @ref BoundMethod object.
|
||||
*
|
||||
* @param _class Class object to resolve methods from.
|
||||
* @param name String object with the name of the method to resolve.
|
||||
* @return 1 if the method has been bound, 0 if binding failed.
|
||||
*/
|
||||
extern int krk_bindMethod(KrkClass * _class, KrkString * name);
|
||||
|
||||
/**
|
||||
* @brief Call a callable value in the current stack context.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Executes the given callable object (function, bound method, object
|
||||
* with a @c \__call__() method, etc.) using @p argCount arguments from the stack.
|
||||
*
|
||||
* @param callee Value referencing a callable object.
|
||||
* @param argCount Arguments to retreive from stack.
|
||||
* @param extra Whether extra arguments below argCount should be
|
||||
* considered as part of this call frame. Generally,
|
||||
* when this is 1, the value below the arguments is
|
||||
* the callable object. Most library users will want
|
||||
* to leave this as 0 when calling normal functions,
|
||||
* bound method objects, or ubound methods when the
|
||||
* instance is included in the arguments already.
|
||||
* @return An indicator of how the result should be obtained:
|
||||
* 1: The VM must be resumed to run managed code.
|
||||
* 2: The callable was a native function and result should be popped now.
|
||||
* Else: The call failed. An exception may have already been set.
|
||||
*/
|
||||
extern int krk_callValue(KrkValue callee, int argCount, int extra);
|
||||
|
||||
/**
|
||||
* @brief Create a list object.
|
||||
* @memberof KrkList
|
||||
*
|
||||
* This is the native function bound to @c listOf
|
||||
*/
|
||||
extern KrkValue krk_list_of(int argc, KrkValue argv[], int hasKw);
|
||||
|
||||
/**
|
||||
* @brief Create a dict object.
|
||||
* @memberof KrkDict
|
||||
*
|
||||
* This is the native function bound to @c dictOf
|
||||
*/
|
||||
extern KrkValue krk_dict_of(int argc, KrkValue argv[], int hasKw);
|
||||
|
||||
/**
|
||||
* @brief Create a tuple object.
|
||||
* @memberof KrkTuple
|
||||
*
|
||||
* This is the native function bound to @c tupleOf
|
||||
*/
|
||||
extern KrkValue krk_tuple_of(int argc, KrkValue argv[], int hasKw);
|
||||
|
||||
/**
|
||||
* @brief Create a set object.
|
||||
* @memberof Set
|
||||
*
|
||||
* This is the native function bound to @c setOf
|
||||
*/
|
||||
extern KrkValue krk_set_of(int argc, KrkValue argv[], int hasKw);
|
||||
|
||||
/**
|
||||
* @brief Call a callable and manage VM state to obtain the return value.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* This is a wrapper around various mechanisms including krk_callValue
|
||||
* intended for use by C extensions to call arbitrary functions without
|
||||
* knowledge of their implementation details. See the notes for
|
||||
* @c krk_callValue 's @c extra paramater for details on how @p isMethod is used.
|
||||
*
|
||||
* @param value Callable object reference.
|
||||
* @param argCount Arguments to collect from the stack.
|
||||
* @param isMethod This should almost always be 0.
|
||||
* @return The return value of the function.
|
||||
*/
|
||||
extern KrkValue krk_callSimple(KrkValue value, int argCount, int isMethod);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for creating new types.
|
||||
* @memberof KrkClass
|
||||
*
|
||||
* Creates a class object, output to @p _class, setting its name to @p name, inheriting
|
||||
* from @p base, and attaching it with its name to the fields table of the given @p module.
|
||||
*
|
||||
* @param module Pointer to an instance for a module to attach to, or @c NULL to skip attaching.
|
||||
* @param _class Output pointer to assign the new class object to.
|
||||
* @param name Name of the new class.
|
||||
* @param base Pointer to class object to inherit from.
|
||||
* @return A pointer to the class object, equivalent to the value assigned to @p _class.
|
||||
*/
|
||||
extern KrkClass * krk_makeClass(KrkInstance * module, KrkClass ** _class, const char * name, KrkClass * base);
|
||||
|
||||
/**
|
||||
* @brief Finalize a class by collecting pointers to core methods.
|
||||
* @memberof KrkClass
|
||||
*
|
||||
* Scans through the methods table of a class object to find special
|
||||
* methods and assign them to the class object's pointer table so they
|
||||
* can be referenced directly without performing hash lookups.
|
||||
*
|
||||
* @param _class Class object to finalize.
|
||||
*/
|
||||
extern void krk_finalizeClass(KrkClass * _class);
|
||||
|
||||
/**
|
||||
* @brief If there is an active exception, print a traceback to @c stderr
|
||||
*
|
||||
* This function is exposed as a convenience for repl developers. Normally,
|
||||
* the VM will call @c krk_dumpTraceback() itself if an exception is unhandled and no
|
||||
* exit trigger is current set. The traceback is obtained from the exception
|
||||
* object. If the exception object does not have a traceback, only the
|
||||
* exception itself will be printed. The traceback printer will attempt to
|
||||
* open source files to print faulting lines and may call into the VM if the
|
||||
* exception object has a managed implementation of @c \__str__.
|
||||
*/
|
||||
extern void krk_dumpTraceback();
|
||||
|
||||
/**
|
||||
* @brief Set up a new module object in the current thread.
|
||||
*
|
||||
* Creates a new instance of the module type and attaches a @c \__builtins__
|
||||
* reference to its fields. The module becomes the current thread's
|
||||
* main module, but is not directly attached to the module table.
|
||||
*
|
||||
* @param name Name of the module, which is assigned to @c \__name__
|
||||
* @return The instance object representing the module.
|
||||
*/
|
||||
extern KrkInstance * krk_startModule(const char * name);
|
||||
|
||||
/**
|
||||
* @brief Obtain a list of properties for an object.
|
||||
*
|
||||
* This is the native function bound to @c object.__dir__
|
||||
*/
|
||||
extern KrkValue krk_dirObject(int argc, KrkValue argv[], int hasKw);
|
||||
|
||||
/**
|
||||
* @brief Load a module from a file with a specified name.
|
||||
*
|
||||
* This is generally called by the import mechanisms to load a single module and
|
||||
* will establish a module context internally to load the new module into, return
|
||||
* a KrkValue representing that module context through the @p moduleOut parameter.
|
||||
*
|
||||
* @param path Dotted path of the module, used for file lookup.
|
||||
* @param moduleOut Receives a value with the module object.
|
||||
* @param runAs Name to attach to @c \__name__ for this module, different from @p path
|
||||
* @return 1 if the module was loaded, 0 if an @ref ImportError occurred.
|
||||
*/
|
||||
extern int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs);
|
||||
|
||||
/**
|
||||
* @brief Load a module by a dotted name.
|
||||
*
|
||||
* Given a package identifier, attempt to the load module into the module table.
|
||||
* This is a thin wrapper around `krk_importModule()`.
|
||||
*
|
||||
* @param name String object of the dot-separated package path to import.
|
||||
* @return 1 if the module was loaded, 0 if an @ref ImportError occurred.
|
||||
*/
|
||||
extern int krk_doRecursiveModuleLoad(KrkString * name);
|
||||
|
||||
/**
|
||||
* @brief Load the dotted name @p name with the final element as @p runAs
|
||||
*
|
||||
* If @p name was imported previously with a name different from @p runAs,
|
||||
* it will be imported again with the new name; this may result in
|
||||
* unexpected behaviour. Generally, @p runAs is used to specify that the
|
||||
* module should be run as `__main__`.
|
||||
*
|
||||
* @param name Dotted path name of a module.
|
||||
* @param runAs Alternative name to attach to @c \__name__ for the module.
|
||||
* @return 1 on success, 0 on failure.
|
||||
*/
|
||||
extern int krk_importModule(KrkString * name, KrkString * runAs);
|
||||
|
||||
/**
|
||||
* @brief Determine the truth of a value.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Determines if a value represents a "falsey" value.
|
||||
* Empty collections, 0-length strings, False, numeric 0,
|
||||
* None, etc. are "falsey". Other values are generally "truthy".
|
||||
*
|
||||
* @param value Value to examine.
|
||||
* @return 1 if falsey, 0 if truthy
|
||||
*/
|
||||
extern int krk_isFalsey(KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Obtain a property of an object by name.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* This is a convenience function that works in essentially the
|
||||
* same way as the OP_GET_PROPERTY instruction.
|
||||
*
|
||||
* @param value Value to examine.
|
||||
* @param name C-string of the property name to query.
|
||||
* @return The requested property, or None with an @ref AttributeError
|
||||
* exception set in the current thread if the attribute was
|
||||
* not found.
|
||||
*/
|
||||
extern KrkValue krk_valueGetAttribute(KrkValue value, char * name);
|
||||
|
||||
/**
|
||||
* @brief See @ref krk_valueGetAttribute
|
||||
*/
|
||||
extern KrkValue krk_valueGetAttribute_default(KrkValue value, char * name, KrkValue defaultVal);
|
||||
|
||||
/**
|
||||
* @brief Set a property of an object by name.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* This is a convenience function that works in essentially the
|
||||
* same way as the OP_SET_PROPERTY instruction.
|
||||
*
|
||||
* @param owner The owner of the property to modify.
|
||||
* @param name C-string of the property name to modify.
|
||||
* @param to The value to assign.
|
||||
* @return The set value, or None with an @ref AttributeError
|
||||
* exception set in the current thread if the object can
|
||||
* not have a property set.
|
||||
*/
|
||||
extern KrkValue krk_valueSetAttribute(KrkValue owner, char * name, KrkValue to);
|
||||
|
||||
/**
|
||||
* @brief Concatenate two strings.
|
||||
*
|
||||
* This is a convenience function which calls @c str.__add__ on the top stack
|
||||
* values. Generally, this should be avoided - use @c StringBuilder instead.
|
||||
*/
|
||||
extern void krk_addObjects(void);
|
||||
|
||||
/*
|
||||
* All of the remaining stuff is internal and shouldn't be used by library users or embedders.
|
||||
* FIXME This stuff needs to be moved to another header! FIXME
|
||||
*/
|
||||
|
||||
extern KrkValue _str___getitem__(int argc, KrkValue argv[], int hasKw);
|
||||
#define krk_string_get _str___getitem__
|
||||
extern KrkValue _str___int__(int argc, KrkValue argv[], int hasKw);
|
||||
#define krk_string_int _str___int__
|
||||
extern KrkValue _str___float__(int argc, KrkValue argv[], int hasKw);
|
||||
#define krk_string_float _str___float__
|
||||
extern KrkValue _str_split(int argc, KrkValue argv[], int hasKw);
|
||||
#define krk_string_split _str_split
|
||||
extern KrkValue _str_format(int argc, KrkValue argv[], int hasKw);
|
||||
#define krk_string_format _str_format
|
||||
|
||||
extern KrkValue krk_dict_nth_key_fast(size_t capacity, KrkTableEntry * entries, size_t index);
|
||||
|
||||
extern void _createAndBind_numericClasses(void);
|
||||
extern void _createAndBind_strClass(void);
|
||||
extern void _createAndBind_listClass(void);
|
||||
extern void _createAndBind_tupleClass(void);
|
||||
extern void _createAndBind_bytesClass(void);
|
||||
extern void _createAndBind_dictClass(void);
|
||||
extern void _createAndBind_functionClass(void);
|
||||
extern void _createAndBind_rangeClass(void);
|
||||
extern void _createAndBind_setClass(void);
|
||||
extern void _createAndBind_builtins(void);
|
||||
extern void _createAndBind_type(void);
|
||||
extern void _createAndBind_exceptions(void);
|
||||
extern void _createAndBind_gcMod(void);
|
||||
extern void _createAndBind_timeMod(void);
|
||||
extern void _createAndBind_osMod(void);
|
||||
extern void _createAndBind_fileioMod(void);
|
||||
#ifdef ENABLE_THREADING
|
||||
extern void _createAndBind_threadsMod(void);
|
||||
#endif
|
||||
|
||||
extern KrkValue krk_operator_lt(KrkValue,KrkValue);
|
||||
extern KrkValue krk_operator_gt(KrkValue,KrkValue);
|
||||
|
||||
extern void _createAndBind_generatorClass(void);
|
||||
extern KrkInstance * krk_buildGenerator(KrkClosure *, KrkValue *, size_t);
|
2
kuroko
2
kuroko
@ -1 +1 @@
|
||||
Subproject commit 34c8d68720ea5ee736b49094b8b1836a267604a9
|
||||
Subproject commit ca7d0dae2ec78a7746b49ecaae1c8836488a811b
|
@ -1186,7 +1186,7 @@ KrkValue krk_module_onload__yutani(void) {
|
||||
Message->allocSize = sizeof(struct MessageClass);
|
||||
Message->_ongcsweep = _message_sweep;
|
||||
/* All the MSG_ constants */
|
||||
#define TYPE(type) krk_attachNamedValue(&Message->fields, "MSG_" #type, INTEGER_VAL(YUTANI_MSG_ ## type))
|
||||
#define TYPE(type) krk_attachNamedValue(&Message->methods, "MSG_" #type, INTEGER_VAL(YUTANI_MSG_ ## type))
|
||||
TYPE(HELLO); TYPE(WINDOW_NEW); TYPE(FLIP); TYPE(KEY_EVENT); TYPE(MOUSE_EVENT);
|
||||
TYPE(WINDOW_MOVE); TYPE(WINDOW_CLOSE); TYPE(WINDOW_SHOW); TYPE(WINDOW_HIDE);
|
||||
TYPE(WINDOW_STACK); TYPE(WINDOW_FOCUS_CHANGE); TYPE(WINDOW_MOUSE_EVENT);
|
||||
@ -1347,7 +1347,7 @@ KrkValue krk_module_onload__yutani(void) {
|
||||
" Calculate the rendered width of the given string when drawn with this font.";
|
||||
krk_defineNative(&YutaniFont->methods, ":size", _font_size);
|
||||
/* Some static values */
|
||||
#define ATTACH_FONT(name) krk_attachNamedValue(&YutaniFont->fields, #name, INTEGER_VAL(SDF_ ## name))
|
||||
#define ATTACH_FONT(name) krk_attachNamedValue(&YutaniFont->methods, #name, INTEGER_VAL(SDF_ ## name))
|
||||
ATTACH_FONT(FONT_THIN);
|
||||
ATTACH_FONT(FONT_BOLD);
|
||||
ATTACH_FONT(FONT_MONO);
|
||||
@ -1387,11 +1387,11 @@ KrkValue krk_module_onload__yutani(void) {
|
||||
krk_finalizeClass(MenuEntrySeparatorClass);
|
||||
|
||||
Decorator = krk_createClass(module, "Decorator", NULL);
|
||||
krk_defineNative(&Decorator->fields, "get_bounds", _decor_get_bounds);
|
||||
krk_defineNative(&Decorator->fields, "render", _decor_render);
|
||||
krk_defineNative(&Decorator->fields, "handle_event", _decor_handle_event);
|
||||
krk_defineNative(&Decorator->fields, "show_default_menu", _decor_show_default_menu);
|
||||
#define ATTACH_CONSTANT(name) krk_attachNamedValue(&Decorator->fields, #name, INTEGER_VAL(name))
|
||||
krk_defineNative(&Decorator->methods, "get_bounds", _decor_get_bounds);
|
||||
krk_defineNative(&Decorator->methods, "render", _decor_render);
|
||||
krk_defineNative(&Decorator->methods, "handle_event", _decor_handle_event);
|
||||
krk_defineNative(&Decorator->methods, "show_default_menu", _decor_show_default_menu);
|
||||
#define ATTACH_CONSTANT(name) krk_attachNamedValue(&Decorator->methods, #name, INTEGER_VAL(name))
|
||||
ATTACH_CONSTANT(DECOR_OTHER);
|
||||
ATTACH_CONSTANT(DECOR_CLOSE);
|
||||
ATTACH_CONSTANT(DECOR_RESIZE);
|
||||
|
@ -37,6 +37,7 @@ class Classifier(object):
|
||||
'<toaru/button.h>': (None, '-ltoaru_button', ['<toaru/graphics.h>','<toaru/sdf.h>', '<toaru/icon_cache.h>']),
|
||||
# Kuroko
|
||||
'<kuroko.h>': ('../../../kuroko/src', '-lkuroko', []),
|
||||
'<kuroko/kuroko.h>': (None, '-lkuroko', []),
|
||||
# OPTIONAL third-party libraries, for extensions / ports
|
||||
'<ft2build.h>': ('freetype2', '-lfreetype', []),
|
||||
'<pixman.h>': ('pixman-1', '-lpixman-1', []),
|
||||
|
Loading…
Reference in New Issue
Block a user