add with and from import

This commit is contained in:
blueloveTH 2022-12-01 13:07:55 +08:00
parent 5a2d389c22
commit 3d84156a19
8 changed files with 91 additions and 9 deletions

View File

@ -664,7 +664,7 @@ __LISTCOMP:
return tkmodule; return tkmodule;
} }
// import module1 [as alias1 [, module2 [as alias2 ...]] // import a as b
void compileRegularImport() { void compileRegularImport() {
do { do {
Token tkmodule = compileImportPath(); Token tkmodule = compileImportPath();
@ -678,6 +678,25 @@ __LISTCOMP:
consumeEndStatement(); consumeEndStatement();
} }
// from a import b as c, d as e
void compileFromImport() {
Token tkmodule = compileImportPath();
consume(TK("import"));
do {
consume(TK("@id"));
Token tkname = parser->previous;
int index = getCode()->addName(tkname.str(), NAME_GLOBAL);
emitCode(OP_BUILD_ATTR_PTR, index);
if (match(TK("as"))) {
consume(TK("@id"));
tkname = parser->previous;
}
index = getCode()->addName(tkname.str(), NAME_GLOBAL);
emitCode(OP_STORE_NAME_PTR, index);
} while (match(TK(",")));
consumeEndStatement();
}
void parsePrecedence(Precedence precedence) { void parsePrecedence(Precedence precedence) {
lexToken(); lexToken();
GrammarFn prefix = rules[parser->previous.type].prefix; GrammarFn prefix = rules[parser->previous.type].prefix;
@ -786,6 +805,21 @@ __LISTCOMP:
EXPR(); EXPR();
emitCode(OP_ASSERT); emitCode(OP_ASSERT);
consumeEndStatement(); consumeEndStatement();
} else if(match(TK("with"))){
EXPR();
consume(TK("as"));
consume(TK("@id"));
Token tkname = parser->previous;
int index = getCode()->addName(
tkname.str(),
codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
);
emitCode(OP_STORE_NAME_PTR, index);
emitCode(OP_LOAD_NAME_PTR, index);
emitCode(OP_WITH_ENTER);
compileBlockBody();
emitCode(OP_LOAD_NAME_PTR, index);
emitCode(OP_WITH_EXIT);
} else if(match(TK("label"))){ } else if(match(TK("label"))){
if(mode() != EXEC_MODE) syntaxError("'label' is only available in EXEC_MODE"); if(mode() != EXEC_MODE) syntaxError("'label' is only available in EXEC_MODE");
consume(TK(".")); consume(TK("@id")); consume(TK(".")); consume(TK("@id"));
@ -926,6 +960,8 @@ __LISTCOMP:
compileFunction(); compileFunction();
} else if (match(TK("import"))) { } else if (match(TK("import"))) {
compileRegularImport(); compileRegularImport();
} else if (match(TK("from"))) {
compileFromImport();
} else { } else {
compileStatement(); compileStatement();
} }

View File

@ -10,7 +10,7 @@ const _Int _Int_MAX_NEG = -9223372036854775807LL;
const _Float _FLOAT_INF_POS = INFINITY; const _Float _FLOAT_INF_POS = INFINITY;
const _Float _FLOAT_INF_NEG = -INFINITY; const _Float _FLOAT_INF_NEG = -INFINITY;
#define PK_VERSION "0.3.5" #define PK_VERSION "0.3.6"
class CodeObject; class CodeObject;
class BasePointer; class BasePointer;

View File

@ -63,4 +63,7 @@ OPCODE(GOTO)
OPCODE(UNARY_REF) // for & OPCODE(UNARY_REF) // for &
OPCODE(UNARY_DEREF) // for * OPCODE(UNARY_DEREF) // for *
OPCODE(WITH_ENTER)
OPCODE(WITH_EXIT)
#endif #endif

View File

@ -12,7 +12,7 @@ constexpr const char* __TOKENS[] = {
"==", "!=", ">=", "<=", "==", "!=", ">=", "<=",
"+=", "-=", "*=", "/=", "//=", "+=", "-=", "*=", "/=", "//=",
/** KW_BEGIN **/ /** KW_BEGIN **/
"class", "import", "as", "def", "lambda", "pass", "del", "class", "import", "as", "def", "lambda", "pass", "del", "from", "with",
"None", "in", "is", "and", "or", "not", "True", "False", "global", "None", "in", "is", "and", "or", "not", "True", "False", "global",
"goto", "label", // extended keywords, not available in cpython "goto", "label", // extended keywords, not available in cpython
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise", "while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise",

View File

@ -404,11 +404,18 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindMethod("str", "join", [](VM* vm, const pkpy::ArgList& args) { _vm->bindMethod("str", "join", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 2, true); vm->__checkArgSize(args, 2, true);
const _Str& _self = vm->PyStr_AS_C(args[0]); const _Str& _self = vm->PyStr_AS_C(args[0]);
const PyVarList& _list = vm->PyList_AS_C(args[1]); PyVarList* _list;
if(args[1]->isType(vm->_tp_list)){
_list = &vm->PyList_AS_C(args[1]);
}else if(args[1]->isType(vm->_tp_tuple)){
_list = &vm->PyTuple_AS_C(args[1]);
}else{
vm->typeError("can only join a list or tuple");
}
_StrStream ss; _StrStream ss;
for(int i = 0; i < _list.size(); i++){ for(int i = 0; i < _list->size(); i++){
if(i > 0) ss << _self; if(i > 0) ss << _self;
ss << vm->PyStr_AS_C(vm->asStr(_list[i])); ss << vm->PyStr_AS_C(vm->asStr(_list->operator[](i)));
} }
return vm->PyStr(ss.str()); return vm->PyStr(ss.str());
}); });

View File

@ -345,6 +345,18 @@ protected:
frame->push(it->second); frame->push(it->second);
} }
} break; } break;
case OP_WITH_ENTER:
{
PyVar obj = frame->popValue(this);
PyVar enter_fn = getAttr(obj, "__enter__"_c);
call(enter_fn, {});
} break;
case OP_WITH_EXIT:
{
PyVar obj = frame->popValue(this);
PyVar exit_fn = getAttr(obj, "__exit__"_c);
call(exit_fn, {});
} break;
default: default:
systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented"); systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
break; break;

View File

@ -48,6 +48,10 @@ seq = ["r","u","n","o","o","b"]
assert s1.join( seq ) == "r-u-n-o-o-b" assert s1.join( seq ) == "r-u-n-o-o-b"
assert s2.join( seq ) == "runoob" assert s2.join( seq ) == "runoob"
def test(*seq):
return s1.join(seq)
assert test("r", "u", "n", "o", "o", "b") == "r-u-n-o-o-b"
##num = 6 ##num = 6
##assert str(num) == '6' TypeError: 'str' object is not callable ##assert str(num) == '6' TypeError: 'str' object is not callable

View File

@ -1,6 +1,26 @@
import random import random as r, sys as s
for _ in range(100): for _ in range(100):
i = random.randint(1, 10) i = r.randint(1, 10)
assert i <= 10 assert i <= 10
assert i >= 1 assert i >= 1
from sys import version as v
assert type(v) is str
class Context:
def __init__(self):
self.x = 0
def __enter__(self):
self.x = 1
def __exit__(self):
self.x = 2
with Context() as c:
assert c.x == 1
assert c.x == 2