This commit is contained in:
blueloveTH 2023-05-03 21:43:37 +08:00
parent cdbd884398
commit 06068ab3e0
8 changed files with 51 additions and 32 deletions

View File

@ -1,11 +1,9 @@
---
icon: dot
order: 100
title: Basic Features
order: 100
---
# basic
The following table shows the basic features of pkpy with respect to [cpython](https://github.com/python/cpython).
The features marked with `YES` are supported, and the features marked with `NO` are not supported.

View File

@ -3,8 +3,6 @@ icon: dot
title: Goto Statement
---
# goto/label
pkpy supports `goto` and `label` just like C. You are allowed to change the control flow unconditionally.
## Syntax
@ -12,8 +10,8 @@ pkpy supports `goto` and `label` just like C. You are allowed to change the cont
Labels are named a dot `.` and an identifier.
```
goto .<identifier>
label .<identifier>
$goto <identifier>
$label <identifier>
```
## Example
@ -22,7 +20,7 @@ label .<identifier>
for i in range(10):
for j in range(10):
for k in range(10):
goto .exit
$goto exit
label .exit
$label exit
```

View File

@ -1,6 +1,8 @@
import sys as _sys
def print(*args, sep=' ', end='\n'):
s = sep.join([str(i) for i in args])
__sys_stdout_write(s + end)
_sys.stdout.write(s + end)
def round(x, ndigits=0):
assert ndigits >= 0

View File

@ -501,7 +501,7 @@ __NEXT_STEP:;
TOP()->attr().set(_name, _0);
DISPATCH();
/*****************************************/
// // TODO: using "goto" inside with block may cause __exit__ not called
// TODO: using "goto" inside with block may cause __exit__ not called
TARGET(WITH_ENTER)
call_method(POPX(), __enter__);
DISPATCH();

View File

@ -795,17 +795,16 @@ __SUBSCR_END:
ctx()->emit(OP_WITH_EXIT, BC_NOARG, prev().line);
} break;
/*************************************************/
// TODO: refactor goto/label use special $ syntax
case TK("label"): {
case TK("$label"): {
if(mode()!=EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE");
consume(TK(".")); consume(TK("@id"));
consume(TK("@id"));
bool ok = ctx()->add_label(prev().str());
if(!ok) SyntaxError("label " + prev().str().escape() + " already exists");
consume_end_stmt();
} break;
case TK("goto"):
case TK("$goto"):
if(mode()!=EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
consume(TK(".")); consume(TK("@id"));
consume(TK("@id"));
ctx()->emit(OP_GOTO, StrName(prev().str()).index, prev().line);
consume_end_stmt();
break;

View File

@ -21,10 +21,11 @@ constexpr const char* kTokens[] = {
/*****************************************/
".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}",
"**", "=", ">", "<", "...", "->", "?", "@", "==", "!=", ">=", "<=",
/** SPEC_BEGIN **/
"$goto", "$label",
/** KW_BEGIN **/
"class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "yield",
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
"goto", "label", // extended keywords, not available in cpython
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise"
};
@ -38,13 +39,7 @@ constexpr TokenIndex TK(const char token[]) {
while(*i && *j && *i == *j) { i++; j++;}
if(*i == *j) return k;
}
#ifdef __GNUC__
// for old version of gcc, it is not smart enough to ignore FATAL_ERROR()
// so we must do a normal return
return 255;
#else
FATAL_ERROR();
#endif
}
#define TK_STR(t) kTokens[t]
@ -125,6 +120,13 @@ struct Lexer {
return true;
}
bool match_string(const char* s){
int s_len = strlen(s);
bool ok = strncmp(curr_char, s, s_len) == 0;
if(ok) for(int i=0; i<s_len; i++) eatchar_include_newline();
return ok;
}
int eat_spaces(){
int count = 0;
while (true) {
@ -381,6 +383,16 @@ struct Lexer {
case '[': add_token(TK("[")); return true;
case ']': add_token(TK("]")); return true;
case '@': add_token(TK("@")); return true;
case '$': {
for(int i=TK("$goto"); i<=TK("$label"); i++){
// +1 to skip the '$'
if(match_string(TK_STR(i) + 1)){
add_token((TokenIndex)i);
return true;
}
}
SyntaxError("invalid special token");
}
case '%': add_token_2('=', TK("%"), TK("%=")); return true;
case '&': add_token_2('=', TK("&"), TK("&=")); return true;
case '|': add_token_2('=', TK("|"), TK("|=")); return true;

View File

@ -72,11 +72,6 @@ inline void init_builtins(VM* _vm) {
#undef BIND_NUM_ARITH_OPT
#undef BIND_NUM_LOGICAL_OPT
_vm->bind_builtin_func<1>("__sys_stdout_write", [](VM* vm, ArgsView args) {
(*vm->_stdout) << CAST(Str&, args[0]);
return vm->None;
});
_vm->bind_builtin_func<2>("super", [](VM* vm, ArgsView args) {
vm->check_non_tagged_type(args[0], vm->tp_type);
Type type = OBJ_GET(Type, args[0]);
@ -768,6 +763,21 @@ inline void add_module_time(VM* vm){
inline void add_module_sys(VM* vm){
PyObject* mod = vm->new_module("sys");
vm->setattr(mod, "version", VAR(PK_VERSION));
PyObject* stdout = vm->heap.gcnew<DummyInstance>(vm->tp_object, {});
PyObject* stderr = vm->heap.gcnew<DummyInstance>(vm->tp_object, {});
vm->setattr(mod, "stdout", stdout);
vm->setattr(mod, "stderr", stderr);
vm->bind_func<1>(stdout, "write", [](VM* vm, ArgsView args) {
(*vm->_stdout) << CAST(Str&, args[0]).sv();
return vm->None;
});
vm->bind_func<1>(stderr, "write", [](VM* vm, ArgsView args) {
(*vm->_stderr) << CAST(Str&, args[0]).sv();
return vm->None;
});
}
inline void add_module_json(VM* vm){

View File

@ -2,9 +2,9 @@ a = []
for i in range(10): # [0]
for j in range(10): # [0-0]
goto .test
$goto test
print(2)
label .test
$label test
a.append(i)
for k in range(5): # [0-1]
for t in range(7): # [0-1-0]
@ -16,7 +16,7 @@ b = False
for i in range(10): # [1]
for j in range(10): # [1-0]
goto .out
$goto out
b = True
label .out
$label out
assert not b