mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
...
This commit is contained in:
parent
cdbd884398
commit
06068ab3e0
@ -1,11 +1,9 @@
|
|||||||
---
|
---
|
||||||
icon: dot
|
icon: dot
|
||||||
order: 100
|
|
||||||
title: Basic Features
|
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 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.
|
The features marked with `YES` are supported, and the features marked with `NO` are not supported.
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@ icon: dot
|
|||||||
title: Goto Statement
|
title: Goto Statement
|
||||||
---
|
---
|
||||||
|
|
||||||
# goto/label
|
|
||||||
|
|
||||||
pkpy supports `goto` and `label` just like C. You are allowed to change the control flow unconditionally.
|
pkpy supports `goto` and `label` just like C. You are allowed to change the control flow unconditionally.
|
||||||
|
|
||||||
## Syntax
|
## 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.
|
Labels are named a dot `.` and an identifier.
|
||||||
|
|
||||||
```
|
```
|
||||||
goto .<identifier>
|
$goto <identifier>
|
||||||
label .<identifier>
|
$label <identifier>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
@ -22,7 +20,7 @@ label .<identifier>
|
|||||||
for i in range(10):
|
for i in range(10):
|
||||||
for j in range(10):
|
for j in range(10):
|
||||||
for k in range(10):
|
for k in range(10):
|
||||||
goto .exit
|
$goto exit
|
||||||
|
|
||||||
label .exit
|
$label exit
|
||||||
```
|
```
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import sys as _sys
|
||||||
|
|
||||||
def print(*args, sep=' ', end='\n'):
|
def print(*args, sep=' ', end='\n'):
|
||||||
s = sep.join([str(i) for i in args])
|
s = sep.join([str(i) for i in args])
|
||||||
__sys_stdout_write(s + end)
|
_sys.stdout.write(s + end)
|
||||||
|
|
||||||
def round(x, ndigits=0):
|
def round(x, ndigits=0):
|
||||||
assert ndigits >= 0
|
assert ndigits >= 0
|
||||||
|
@ -501,7 +501,7 @@ __NEXT_STEP:;
|
|||||||
TOP()->attr().set(_name, _0);
|
TOP()->attr().set(_name, _0);
|
||||||
DISPATCH();
|
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)
|
TARGET(WITH_ENTER)
|
||||||
call_method(POPX(), __enter__);
|
call_method(POPX(), __enter__);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
@ -795,17 +795,16 @@ __SUBSCR_END:
|
|||||||
ctx()->emit(OP_WITH_EXIT, BC_NOARG, prev().line);
|
ctx()->emit(OP_WITH_EXIT, BC_NOARG, prev().line);
|
||||||
} break;
|
} 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");
|
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());
|
bool ok = ctx()->add_label(prev().str());
|
||||||
if(!ok) SyntaxError("label " + prev().str().escape() + " already exists");
|
if(!ok) SyntaxError("label " + prev().str().escape() + " already exists");
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK("goto"):
|
case TK("$goto"):
|
||||||
if(mode()!=EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
|
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);
|
ctx()->emit(OP_GOTO, StrName(prev().str()).index, prev().line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
|
26
src/lexer.h
26
src/lexer.h
@ -21,10 +21,11 @@ constexpr const char* kTokens[] = {
|
|||||||
/*****************************************/
|
/*****************************************/
|
||||||
".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}",
|
".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}",
|
||||||
"**", "=", ">", "<", "...", "->", "?", "@", "==", "!=", ">=", "<=",
|
"**", "=", ">", "<", "...", "->", "?", "@", "==", "!=", ">=", "<=",
|
||||||
|
/** SPEC_BEGIN **/
|
||||||
|
"$goto", "$label",
|
||||||
/** KW_BEGIN **/
|
/** KW_BEGIN **/
|
||||||
"class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "yield",
|
"class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "yield",
|
||||||
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
|
"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"
|
"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++;}
|
while(*i && *j && *i == *j) { i++; j++;}
|
||||||
if(*i == *j) return k;
|
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;
|
return 255;
|
||||||
#else
|
|
||||||
FATAL_ERROR();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TK_STR(t) kTokens[t]
|
#define TK_STR(t) kTokens[t]
|
||||||
@ -125,6 +120,13 @@ struct Lexer {
|
|||||||
return true;
|
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 eat_spaces(){
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (true) {
|
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 ']': 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;
|
case '&': add_token_2('=', TK("&"), TK("&=")); return true;
|
||||||
case '|': add_token_2('=', TK("|"), TK("|=")); return true;
|
case '|': add_token_2('=', TK("|"), TK("|=")); return true;
|
||||||
|
@ -72,11 +72,6 @@ inline void init_builtins(VM* _vm) {
|
|||||||
#undef BIND_NUM_ARITH_OPT
|
#undef BIND_NUM_ARITH_OPT
|
||||||
#undef BIND_NUM_LOGICAL_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->bind_builtin_func<2>("super", [](VM* vm, ArgsView args) {
|
||||||
vm->check_non_tagged_type(args[0], vm->tp_type);
|
vm->check_non_tagged_type(args[0], vm->tp_type);
|
||||||
Type type = OBJ_GET(Type, args[0]);
|
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){
|
inline void add_module_sys(VM* vm){
|
||||||
PyObject* mod = vm->new_module("sys");
|
PyObject* mod = vm->new_module("sys");
|
||||||
vm->setattr(mod, "version", VAR(PK_VERSION));
|
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){
|
inline void add_module_json(VM* vm){
|
||||||
|
@ -2,9 +2,9 @@ a = []
|
|||||||
|
|
||||||
for i in range(10): # [0]
|
for i in range(10): # [0]
|
||||||
for j in range(10): # [0-0]
|
for j in range(10): # [0-0]
|
||||||
goto .test
|
$goto test
|
||||||
print(2)
|
print(2)
|
||||||
label .test
|
$label test
|
||||||
a.append(i)
|
a.append(i)
|
||||||
for k in range(5): # [0-1]
|
for k in range(5): # [0-1]
|
||||||
for t in range(7): # [0-1-0]
|
for t in range(7): # [0-1-0]
|
||||||
@ -16,7 +16,7 @@ b = False
|
|||||||
|
|
||||||
for i in range(10): # [1]
|
for i in range(10): # [1]
|
||||||
for j in range(10): # [1-0]
|
for j in range(10): # [1-0]
|
||||||
goto .out
|
$goto out
|
||||||
b = True
|
b = True
|
||||||
label .out
|
$label out
|
||||||
assert not b
|
assert not b
|
Loading…
x
Reference in New Issue
Block a user