mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 07:00:58 +08:00
python like import statement implemented
This commit is contained in:
parent
dd42fc61ad
commit
57931c5dca
@ -91,6 +91,7 @@ typedef enum {
|
||||
//TK_XOREQ, // ^=
|
||||
|
||||
// Keywords.
|
||||
TK_FROM, // from
|
||||
TK_IMPORT, // import
|
||||
TK_AS, // as
|
||||
TK_DEF, // def
|
||||
@ -152,6 +153,7 @@ typedef struct {
|
||||
|
||||
// List of keywords mapped into their identifiers.
|
||||
static _Keyword _keywords[] = {
|
||||
{ "from", 4, TK_FROM },
|
||||
{ "import", 6, TK_IMPORT },
|
||||
{ "as", 2, TK_AS },
|
||||
{ "def", 3, TK_DEF },
|
||||
@ -928,6 +930,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
|
||||
/* TK_DIVEQ */ NO_RULE, // exprAssignment, PREC_ASSIGNMENT
|
||||
/* TK_SRIGHT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
||||
/* TK_SLEFT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
||||
/* TK_FROM */ NO_RULE,
|
||||
/* TK_IMPORT */ NO_RULE,
|
||||
/* TK_AS */ NO_RULE,
|
||||
/* TK_DEF */ NO_RULE,
|
||||
@ -1214,7 +1217,7 @@ static void exprAttrib(Compiler* compiler, bool can_assign) {
|
||||
|
||||
TokenType assignment = parser->previous.type;
|
||||
if (assignment != TK_EQ) {
|
||||
emitOpcode(compiler, OP_GET_ATTRIB_AOP);
|
||||
emitOpcode(compiler, OP_GET_ATTRIB_KEEP);
|
||||
emitShort(compiler, index);
|
||||
compileExpression(compiler);
|
||||
|
||||
@ -1560,61 +1563,94 @@ static void compileBlockBody(Compiler* compiler, BlockType type) {
|
||||
compilerExitBlock(compiler);
|
||||
}
|
||||
|
||||
static void _compilerImportEntry(Compiler* compiler, bool is_from) {
|
||||
typedef enum {
|
||||
IMPORT_REGULAR, //< Regular import
|
||||
IMPORT_FROM_LIB, //< Import the lib for `from` import.
|
||||
IMPORT_FROM_SYMBOL, //< Entry of a `from` import.
|
||||
// TODO: from os import *
|
||||
} ImportEntryType;
|
||||
|
||||
// Single entry of a comma seperated import statement. The instructions will
|
||||
// import the and assign to the corresponding variables.
|
||||
static void _compilerImportEntry(Compiler* compiler, ImportEntryType ie_type) {
|
||||
|
||||
const char* name = NULL;
|
||||
uint32_t length = 0;
|
||||
int lib = -1; //< Imported library variable index.
|
||||
int entry = -1; //< Imported library variable index.
|
||||
|
||||
if (match(&compiler->parser, TK_NAME)) {
|
||||
name = compiler->parser.previous.start;
|
||||
length = compiler->parser.previous.length;
|
||||
|
||||
uint32_t name_line = compiler->parser.previous.line;
|
||||
lib = compilerAddVariable(compiler, name, length, name_line);
|
||||
|
||||
// >> from os import clock
|
||||
// Here `os` is temporary don't add to variable.
|
||||
if (ie_type != IMPORT_FROM_LIB) {
|
||||
entry = compilerAddVariable(compiler, name, length, name_line);
|
||||
}
|
||||
|
||||
int index = (int)scriptAddName(compiler->script, compiler->vm,
|
||||
name, length);
|
||||
emitOpcode(compiler, OP_IMPORT);
|
||||
emitShort(compiler, index);
|
||||
|
||||
// >> from os import clock
|
||||
// Here clock is not imported but get attribute of os.
|
||||
if (ie_type != IMPORT_FROM_SYMBOL) {
|
||||
emitOpcode(compiler, OP_IMPORT);
|
||||
emitShort(compiler, index); //< Name of the lib.
|
||||
} else {
|
||||
// Don't pop the lib since it'll be used for the next entry.
|
||||
emitOpcode(compiler, OP_GET_ATTRIB_KEEP);
|
||||
emitShort(compiler, index); //< Name of the attrib.
|
||||
}
|
||||
|
||||
} else {
|
||||
TODO; //?
|
||||
//consume(&compiler->parser, TK_STRING, "Expected a name or a string literal"
|
||||
// " after import.");
|
||||
//String* path = (String*)AS_OBJ(compiler->parser.previous.value);
|
||||
//name = path->data;
|
||||
//length = path->length;
|
||||
//uint32_t index = compilerAddConstant(compiler, VAR_OBJ(path));
|
||||
TODO; // import and push the lib to the stack.
|
||||
}
|
||||
|
||||
// >> from os import clock
|
||||
// Here the os is imported and not bound to any variable, just temp.
|
||||
if (ie_type == IMPORT_FROM_LIB) return;
|
||||
|
||||
// Store to the variable.
|
||||
if (match(&compiler->parser, TK_AS)) {
|
||||
consume(&compiler->parser, TK_NAME, "Expected a name after as.");
|
||||
compiler->variables[lib].name = compiler->parser.previous.start;
|
||||
compiler->variables[lib].length = compiler->parser.previous.length;
|
||||
// TODO: validate the name (maybe can't be predefined?).
|
||||
compiler->variables[entry].name = compiler->parser.previous.start;
|
||||
compiler->variables[entry].length = compiler->parser.previous.length;
|
||||
// TODO: add the name to global_names ??
|
||||
}
|
||||
|
||||
emitStoreVariable(compiler, lib, true);
|
||||
emitStoreVariable(compiler, entry, true);
|
||||
emitOpcode(compiler, OP_POP);
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: write doc below.
|
||||
from os import clock as c, path as p
|
||||
import os, json as j, math as m
|
||||
*/
|
||||
// The 'import' statement compilation. It's inspired by the python's import
|
||||
// statement. It could be multiple import libs comma seperated and they can
|
||||
// be aliased with 'as' keyword. Using from keyword it's possible to import
|
||||
// some of the members of the lib.
|
||||
//
|
||||
// example. import lib
|
||||
// import lib1, lib2 as l2
|
||||
// from lib import func1, func2 as f2
|
||||
//
|
||||
static void compileImportStatement(Compiler* compiler, bool is_from) {
|
||||
|
||||
if (is_from) {
|
||||
TODO; // ?
|
||||
_compilerImportEntry(compiler, IMPORT_FROM_LIB);
|
||||
consume(&compiler->parser, TK_IMPORT, "Expected keyword 'import'.");
|
||||
|
||||
do {
|
||||
_compilerImportEntry(compiler, IMPORT_FROM_SYMBOL);
|
||||
} while (match(&compiler->parser, TK_COMMA));
|
||||
|
||||
// Done getting all the attributes, now pop the lib from the stack.
|
||||
emitOpcode(compiler, OP_POP);
|
||||
|
||||
} else {
|
||||
bool skip_lines = false;
|
||||
do {
|
||||
if (skip_lines) skipNewLines(&compiler->parser);
|
||||
_compilerImportEntry(compiler, is_from);
|
||||
skip_lines = true;
|
||||
//skipNewLines(&compiler->parser);
|
||||
_compilerImportEntry(compiler, IMPORT_REGULAR);
|
||||
} while (match(&compiler->parser, TK_COMMA));
|
||||
}
|
||||
|
||||
@ -1853,9 +1889,8 @@ bool compile(PKVM* vm, Script* script, const char* source) {
|
||||
} else if (match(parser, TK_DEF)) {
|
||||
compileFunction(&compiler, FN_SCRIPT);
|
||||
|
||||
// TODO: implement from keyword.
|
||||
//} else if (match(parser, TK_FROM)) {
|
||||
// compileImportStatement(&compiler, true);
|
||||
} else if (match(parser, TK_FROM)) {
|
||||
compileImportStatement(&compiler, true);
|
||||
|
||||
} else if (match(parser, TK_IMPORT)) {
|
||||
compileImportStatement(&compiler, false);
|
||||
|
25
src/core.c
25
src/core.c
@ -184,27 +184,11 @@ void corePrint(PKVM* vm) {
|
||||
vm->config.write_fn(vm, "\n");
|
||||
}
|
||||
|
||||
//void coreImport(PKVM* vm) {
|
||||
// Var arg1 = vm->fiber->ret[1];
|
||||
// if (!IS_OBJ(arg1) || AS_OBJ(arg1)->type != OBJ_STRING) {
|
||||
// pkSetRuntimeError(vm, "Expected a String argument.");
|
||||
// }
|
||||
//
|
||||
// String* path = (String*)AS_OBJ(arg1);
|
||||
// if (path->length > 4 && strncmp(path->data, "std:", 4) == 0) {
|
||||
// Script* scr = vmGetStdScript(vm, path->data + 4);
|
||||
// ASSERT(scr != NULL, OOPS);
|
||||
// RET(VAR_OBJ(scr));
|
||||
// }
|
||||
//
|
||||
// TODO;
|
||||
//}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* STD METHODS */
|
||||
/*****************************************************************************/
|
||||
|
||||
// std:list Methods.
|
||||
// 'list' library methods.
|
||||
void stdListSort(PKVM* vm) {
|
||||
Var list = ARG(1);
|
||||
if (!IS_OBJ(list) || AS_OBJ(list)->type != OBJ_LIST) {
|
||||
@ -216,7 +200,7 @@ void stdListSort(PKVM* vm) {
|
||||
RET(list);
|
||||
}
|
||||
|
||||
// std:os Methods.
|
||||
// 'os' library methods.
|
||||
void stdOsClock(PKVM* vm) {
|
||||
RET(VAR_NUM((double)clock() / CLOCKS_PER_SEC));
|
||||
}
|
||||
@ -249,10 +233,6 @@ void initializeCore(PKVM* vm) {
|
||||
|
||||
INITALIZE_BUILTIN_FN("to_string", coreToString, 1);
|
||||
INITALIZE_BUILTIN_FN("print", corePrint, -1);
|
||||
//INITALIZE_BUILTIN_FN("import", coreImport, 1);
|
||||
|
||||
// Sentinal to mark the end of the array.
|
||||
//initializeBuiltinFN(vm, &builtins[i], NULL, 0, 0, NULL);
|
||||
|
||||
// Make STD scripts.
|
||||
Script* std; // A temporary pointer to the current std script.
|
||||
@ -334,7 +314,6 @@ Var varAdd(PKVM* vm, Var v1, Var v2) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vm->fiber->error = stringFormat(vm, "Unsupported operand types for operator '+' "
|
||||
"$ and $", varTypeName(v1), varTypeName(v2));
|
||||
|
||||
|
@ -208,7 +208,7 @@ void dumpInstructions(PKVM* vm, Function* func) {
|
||||
case OP_RETURN: NO_ARGS(); break;
|
||||
|
||||
case OP_GET_ATTRIB:
|
||||
case OP_GET_ATTRIB_AOP:
|
||||
case OP_GET_ATTRIB_KEEP:
|
||||
case OP_SET_ATTRIB:
|
||||
SHORT_ARG();
|
||||
break;
|
||||
|
@ -146,10 +146,9 @@ OPCODE(RETURN, 0, -1)
|
||||
// param: 2 byte attrib name index.
|
||||
OPCODE(GET_ATTRIB, 2, 0)
|
||||
|
||||
// Get attribute to perform assignment operation before store it, so don't
|
||||
// pop the var.
|
||||
// It'll keep the instance on the stack and push the attribute on the stack.
|
||||
// param: 2 byte attrib name index.
|
||||
OPCODE(GET_ATTRIB_AOP, 2, 1)
|
||||
OPCODE(GET_ATTRIB_KEEP, 2, 1)
|
||||
|
||||
// Pop var and value update the attribute push result.
|
||||
// param: 2 byte attrib name index.
|
||||
|
4
src/vm.c
4
src/vm.c
@ -720,9 +720,9 @@ PKInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(GET_ATTRIB_AOP):
|
||||
OPCODE(GET_ATTRIB_KEEP):
|
||||
{
|
||||
Var on = *(vm->fiber->sp - 1);
|
||||
Var on = PEEK();
|
||||
String* name = script->names.data[READ_SHORT()];
|
||||
PUSH(varGetAttrib(vm, on, name));
|
||||
DISPATCH();
|
||||
|
@ -1,15 +1,15 @@
|
||||
|
||||
import os
|
||||
from os import clock
|
||||
|
||||
def fib(n)
|
||||
if n < 2 do return 1 end
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
end
|
||||
|
||||
start = os.clock()
|
||||
start = clock()
|
||||
for i in 0..10
|
||||
print(fib(28))
|
||||
end
|
||||
|
||||
print('elapsed:', os.clock() - start, 's')
|
||||
print('elapsed:', clock() - start, 's')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user