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_GET_PROPERTY_LONG,
OP_METHOD, OP_METHOD,
OP_METHOD_LONG, OP_METHOD_LONG,
OP_IMPORT,
OP_IMPORT_LONG,
} KrkOpCode; } 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() { static void statement() {
if (check(TOKEN_EOL)) { if (check(TOKEN_EOL)) {
return; /* Meaningless blank line */ return; /* Meaningless blank line */
@ -680,6 +688,8 @@ static void statement() {
forStatement(); forStatement();
} else if (match(TOKEN_RETURN)) { } else if (match(TOKEN_RETURN)) {
returnStatement(); returnStatement();
} else if (match(TOKEN_IMPORT)) {
importStatement();
} else { } else {
expressionStatement(); expressionStatement();
} }
@ -951,11 +961,13 @@ static ParseRule * getRule(KrkTokenType type) {
return &rules[type]; return &rules[type];
} }
KrkFunction * krk_compile(const char * src) { KrkFunction * krk_compile(const char * src, int newScope) {
krk_initScanner(src); krk_initScanner(src);
Compiler compiler; Compiler compiler;
initCompiler(&compiler, TYPE_MODULE); initCompiler(&compiler, TYPE_MODULE);
if (newScope) beginScope();
parser.hadError = 0; parser.hadError = 0;
parser.panicMode = 0; parser.panicMode = 0;

View File

@ -2,5 +2,5 @@
#include "object.h" #include "object.h"
extern KrkFunction * krk_compile(const char * src); extern KrkFunction * krk_compile(const char * src, int newScope);
extern void krk_markCompilerRoots(void); 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_SET_PROPERTY, (void)0)
CONSTANT(OP_METHOD, (void)0) CONSTANT(OP_METHOD, (void)0)
CONSTANT(OP_CLOSURE, CLOSURE_MORE) CONSTANT(OP_CLOSURE, CLOSURE_MORE)
CONSTANT(OP_IMPORT, (void)0)
OPERANDL(OP_SET_LOCAL) OPERANDL(OP_SET_LOCAL)
OPERANDL(OP_GET_LOCAL) OPERANDL(OP_GET_LOCAL)
OPERANDL(OP_SET_UPVALUE) OPERANDL(OP_SET_UPVALUE)

View File

@ -8,21 +8,11 @@
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
krk_initVM(); krk_initVM();
FILE * f = fopen("test.krk","r"); KrkValue result = krk_runfile("test.krk",0);
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);
krk_freeVM(); krk_freeVM();
free(buf); if (IS_INTEGER(result)) return AS_INTEGER(result);
return 0; return 0;
} }

View File

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

View File

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

View File

@ -22,6 +22,7 @@ typedef enum {
TOKEN_FALSE, /* False */ TOKEN_FALSE, /* False */
TOKEN_FOR, /* for */ TOKEN_FOR, /* for */
TOKEN_IF, /* if */ TOKEN_IF, /* if */
TOKEN_IMPORT,/* import */
TOKEN_IN, /* in */ TOKEN_IN, /* in */
TOKEN_LET, /* let */ TOKEN_LET, /* let */
TOKEN_NONE, /* None */ 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 # 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. # 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 # figured something with arguments would be more useful? The purpose of this
# language is to be used for writing syntax highlighters, configs, and also # language is to be used for writing syntax highlighters, configs, and also
# plugins for bim, so native bindings are going to be very important. # 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) result = system.sleep(0.1)
print "Call to sleep returned: " + result print "Call to sleep returned: " + result

50
vm.c
View File

@ -363,6 +363,9 @@ static KrkValue run() {
return result; return result;
} }
vm.stackTop = frame->slots; vm.stackTop = frame->slots;
if (vm.frameCount == vm.exitOnFrame) {
return result;
}
krk_push(result); krk_push(result);
frame = &vm.frames[vm.frameCount - 1]; frame = &vm.frames[vm.frameCount - 1];
break; break;
@ -430,6 +433,25 @@ static KrkValue run() {
} }
break; 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_LONG:
case OP_GET_LOCAL: { case OP_GET_LOCAL: {
uint32_t slot = readBytes(frame, (opcode == OP_GET_LOCAL ? 1 : 3)); uint32_t slot = readBytes(frame, (opcode == OP_GET_LOCAL ? 1 : 3));
@ -553,8 +575,8 @@ static KrkValue run() {
#undef READ_BYTE #undef READ_BYTE
} }
int krk_interpret(const char * src) { KrkValue krk_interpret(const char * src, int newScope) {
KrkFunction * function = krk_compile(src); KrkFunction * function = krk_compile(src, newScope);
krk_push(OBJECT_VAL(function)); krk_push(OBJECT_VAL(function));
KrkClosure * closure = newClosure(function); KrkClosure * closure = newClosure(function);
@ -563,6 +585,26 @@ int krk_interpret(const char * src) {
krk_push(OBJECT_VAL(closure)); krk_push(OBJECT_VAL(closure));
callValue(OBJECT_VAL(closure), 0); callValue(OBJECT_VAL(closure), 0);
KrkValue result = run(); return run();
return IS_NONE(result);
} }
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; KrkValue * stackTop;
KrkTable globals; KrkTable globals;
KrkTable strings; KrkTable strings;
KrkTable modules;
KrkString * __init__; KrkString * __init__;
KrkUpvalue * openUpvalues; KrkUpvalue * openUpvalues;
KrkObj * objects; KrkObj * objects;
@ -28,6 +29,7 @@ typedef struct {
size_t nextGC; size_t nextGC;
size_t grayCount; size_t grayCount;
size_t grayCapacity; size_t grayCapacity;
size_t exitOnFrame;
KrkObj** grayStack; KrkObj** grayStack;
} KrkVM; } KrkVM;
@ -35,7 +37,8 @@ extern KrkVM vm;
extern void krk_initVM(void); extern void krk_initVM(void);
extern void krk_freeVM(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 void krk_push(KrkValue value);
extern KrkValue krk_pop(void); extern KrkValue krk_pop(void);
extern const char * typeName(KrkValue value); extern const char * typeName(KrkValue value);