not exactly how modules work in Python, but, uh, good enough for us for now

This commit is contained in:
K. Lange 2020-12-27 18:55:52 +09:00
parent 0ca0564cd0
commit 1f754ebc01
12 changed files with 90 additions and 29 deletions

View File

@ -58,6 +58,8 @@ typedef enum {
OP_GET_PROPERTY_LONG,
OP_METHOD,
OP_METHOD_LONG,
OP_IMPORT,
OP_IMPORT_LONG,
} KrkOpCode;
/**

View File

@ -657,6 +657,14 @@ static void returnStatement() {
}
}
static void importStatement() {
consume(TOKEN_IDENTIFIER, "Expected module name");
declareVariable();
size_t ind = identifierConstant(&parser.previous);
EMIT_CONSTANT_OP(OP_IMPORT, ind);
defineVariable(ind);
}
static void statement() {
if (check(TOKEN_EOL)) {
return; /* Meaningless blank line */
@ -680,6 +688,8 @@ static void statement() {
forStatement();
} else if (match(TOKEN_RETURN)) {
returnStatement();
} else if (match(TOKEN_IMPORT)) {
importStatement();
} else {
expressionStatement();
}
@ -951,11 +961,13 @@ static ParseRule * getRule(KrkTokenType type) {
return &rules[type];
}
KrkFunction * krk_compile(const char * src) {
KrkFunction * krk_compile(const char * src, int newScope) {
krk_initScanner(src);
Compiler compiler;
initCompiler(&compiler, TYPE_MODULE);
if (newScope) beginScope();
parser.hadError = 0;
parser.panicMode = 0;

View File

@ -2,5 +2,5 @@
#include "object.h"
extern KrkFunction * krk_compile(const char * src);
extern KrkFunction * krk_compile(const char * src, int newScope);
extern void krk_markCompilerRoots(void);

View File

@ -80,6 +80,7 @@ size_t krk_disassembleInstruction(KrkChunk * chunk, size_t offset) {
CONSTANT(OP_SET_PROPERTY, (void)0)
CONSTANT(OP_METHOD, (void)0)
CONSTANT(OP_CLOSURE, CLOSURE_MORE)
CONSTANT(OP_IMPORT, (void)0)
OPERANDL(OP_SET_LOCAL)
OPERANDL(OP_GET_LOCAL)
OPERANDL(OP_SET_UPVALUE)

View File

@ -8,21 +8,11 @@
int main(int argc, char * argv[]) {
krk_initVM();
FILE * f = fopen("test.krk","r");
if (!f) return 1;
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
fseek(f, 0, SEEK_SET);
char * buf = malloc(size+1);
fread(buf, 1, size, f);
fclose(f);
buf[size] = '\0';
krk_interpret(buf);
KrkValue result = krk_runfile("test.krk",0);
krk_freeVM();
free(buf);
if (IS_INTEGER(result)) return AS_INTEGER(result);
return 0;
}

View File

@ -61,6 +61,7 @@ KrkString * copyString(const char * chars, size_t length) {
return allocateString(heapChars, length, hash);
}
#define NAME(obj) ((obj)->name ? obj->name->chars : "(unnamed)")
void krk_printObject(FILE * f, KrkValue value) {
switch (OBJECT_TYPE(value)) {
case OBJ_STRING:
@ -68,25 +69,25 @@ void krk_printObject(FILE * f, KrkValue value) {
break;
case OBJ_FUNCTION:
if (AS_FUNCTION(value)->name == NULL) fprintf(f, "<module>");
else fprintf(f, "<def %s>", AS_FUNCTION(value)->name->chars);
else fprintf(f, "<def %s>", NAME(AS_FUNCTION(value)));
break;
case OBJ_NATIVE:
fprintf(f, "<native bind>");
break;
case OBJ_CLOSURE:
fprintf(f, "<closure <def %s>>", AS_CLOSURE(value)->function->name->chars);
fprintf(f, "<closure <def %s>>", NAME(AS_CLOSURE(value)->function));
break;
case OBJ_UPVALUE:
fprintf(f, "<upvalue>");
break;
case OBJ_CLASS:
fprintf(f, "<class %s>", AS_CLASS(value)->name->chars);
fprintf(f, "<class %s>", NAME(AS_CLASS(value)));
break;
case OBJ_INSTANCE:
fprintf(f, "<instance of %s>", AS_INSTANCE(value)->_class->name->chars);
fprintf(f, "<instance of %s>", NAME(AS_INSTANCE(value)->_class));
break;
case OBJ_BOUND_METHOD:
fprintf(f, "<bound <def %s>>", AS_BOUND_METHOD(value)->method->function->name->chars);
fprintf(f, "<bound <def %s>>", NAME(AS_BOUND_METHOD(value)->method->function));
break;
}
}

View File

@ -183,6 +183,7 @@ static KrkTokenType identifierType() {
case 'i': if (MORE(1)) switch (scanner.start[1]) {
case 'f': return checkKeyword(2, "", TOKEN_IF);
case 'n': return checkKeyword(2, "", TOKEN_IN);
case 'm': return checkKeyword(2, "port", TOKEN_IMPORT);
} break;
case 'l': return checkKeyword(1, "et", TOKEN_LET);
case 'n': return checkKeyword(1, "ot", TOKEN_NOT);

View File

@ -22,6 +22,7 @@ typedef enum {
TOKEN_FALSE, /* False */
TOKEN_FOR, /* for */
TOKEN_IF, /* if */
TOKEN_IMPORT,/* import */
TOKEN_IN, /* in */
TOKEN_LET, /* let */
TOKEN_NONE, /* None */

11
system.krk Normal file
View File

@ -0,0 +1,11 @@
# This is a module
class SystemModule:
let module = SystemModule()
module.sleep = __krk_builtin_sleep
print "You imported the system module."
print "It has a module: " + module
print "Which has a function: " + module.sleep
return module

View File

@ -1,3 +1,4 @@
import system
# You may want to look at this in an editor with the syntax highlighting
# set to Python. Not even bim has a highlighter for Kuroko yet.
@ -59,10 +60,6 @@ print "The function call returned: " + result
# figured something with arguments would be more useful? The purpose of this
# language is to be used for writing syntax highlighters, configs, and also
# plugins for bim, so native bindings are going to be very important.
class SystemModule: # Blank class is supported, and basically makes a struct?
let system = SystemModule()
system.sleep = __krk_builtin_sleep
result = system.sleep(0.1)
print "Call to sleep returned: " + result

50
vm.c
View File

@ -363,6 +363,9 @@ static KrkValue run() {
return result;
}
vm.stackTop = frame->slots;
if (vm.frameCount == vm.exitOnFrame) {
return result;
}
krk_push(result);
frame = &vm.frames[vm.frameCount - 1];
break;
@ -430,6 +433,25 @@ static KrkValue run() {
}
break;
}
case OP_IMPORT_LONG:
case OP_IMPORT: {
KrkString * name = READ_STRING((opcode == OP_IMPORT ? 1 : 3));
KrkValue module;
if (!krk_tableGet(&vm.modules, OBJECT_VAL(name), &module)) {
/* Try to open it */
char tmp[256];
sprintf(tmp, "%s.krk", name->chars);
vm.exitOnFrame = vm.frameCount;
module = krk_runfile(tmp,1);
vm.exitOnFrame = -1;
if (!IS_OBJECT(module)) {
runtimeError("Failed to import module - expected to receive an object, but got a %s instead.", typeName(module));
}
krk_tableSet(&vm.modules, OBJECT_VAL(name), module);
}
krk_push(module);
break;
}
case OP_GET_LOCAL_LONG:
case OP_GET_LOCAL: {
uint32_t slot = readBytes(frame, (opcode == OP_GET_LOCAL ? 1 : 3));
@ -553,8 +575,8 @@ static KrkValue run() {
#undef READ_BYTE
}
int krk_interpret(const char * src) {
KrkFunction * function = krk_compile(src);
KrkValue krk_interpret(const char * src, int newScope) {
KrkFunction * function = krk_compile(src, newScope);
krk_push(OBJECT_VAL(function));
KrkClosure * closure = newClosure(function);
@ -563,6 +585,26 @@ int krk_interpret(const char * src) {
krk_push(OBJECT_VAL(closure));
callValue(OBJECT_VAL(closure), 0);
KrkValue result = run();
return IS_NONE(result);
return run();
}
KrkValue krk_runfile(const char * fileName, int newScope) {
FILE * f = fopen(fileName,"r");
if (!f) return NONE_VAL();
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
fseek(f, 0, SEEK_SET);
char * buf = malloc(size+1);
fread(buf, 1, size, f);
fclose(f);
buf[size] = '\0';
KrkValue result = krk_interpret(buf, newScope);
free(buf);
return result;
}

5
vm.h
View File

@ -21,6 +21,7 @@ typedef struct {
KrkValue * stackTop;
KrkTable globals;
KrkTable strings;
KrkTable modules;
KrkString * __init__;
KrkUpvalue * openUpvalues;
KrkObj * objects;
@ -28,6 +29,7 @@ typedef struct {
size_t nextGC;
size_t grayCount;
size_t grayCapacity;
size_t exitOnFrame;
KrkObj** grayStack;
} KrkVM;
@ -35,7 +37,8 @@ extern KrkVM vm;
extern void krk_initVM(void);
extern void krk_freeVM(void);
extern int krk_interpret(const char * src);
extern KrkValue krk_interpret(const char * src, int newScope);
extern KrkValue krk_runfile(const char * fileName, int newScope);
extern void krk_push(KrkValue value);
extern KrkValue krk_pop(void);
extern const char * typeName(KrkValue value);