This commit is contained in:
blueloveTH 2022-12-10 02:51:14 +08:00
parent 8bc04389c8
commit 26b065c1fb
23 changed files with 223 additions and 28 deletions

View File

@ -9,3 +9,10 @@ The initial version. Hello, world!
+ Fix some bugs
+ Add `list.pop` and `reversed` builtin function
+ Optimize `dict` performance
## 0.4.8+2
+ Fix a bug of `bool`
+ Support type hints
+ Fix a bug about comment and indentation
+ Fix a bug about compile error line number

View File

@ -1,6 +1,6 @@
name: pocketpy
description: A lightweight Python interpreter for game engines.
version: 0.4.8+1
version: 0.4.8+2
homepage: https://pocketpy.dev
repository: https://github.com/blueloveth/pocketpy

View File

@ -3255,7 +3255,7 @@ struct Parser {
int count = 0;
while (true) {
switch (peekChar()) {
case ' ': count++; break;
case ' ' : count+=1; break;
case '\t': count+=4; break;
default: return count;
}
@ -3266,6 +3266,8 @@ struct Parser {
bool eatIndentation(){
if(brackets_level_0 > 0 || brackets_level_1 > 0 || brackets_level_2 > 0) return true;
int spaces = eatSpaces();
if(peekChar() == '#') skipLineComment();
if(peekChar() == '\0' || peekChar() == '\n') return true;
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
if(spaces > indents.top()){
indents.push(spaces);
@ -5236,7 +5238,7 @@ public:
parser->previous = parser->current;
parser->current = parser->nextToken();
//_Str _info = parser->current.info(); printf("%s\n", (const char*)_info);
//_Str _info = parser->current.info(); std::cout << _info << '[' << parser->current_line << ']' << std::endl;
while (parser->peekChar() != '\0') {
parser->token_start = parser->current_char;
@ -5311,7 +5313,7 @@ public:
case '\r': break; // just ignore '\r'
case ' ': case '\t': parser->eatSpaces(); break;
case '\n': {
parser->setNextToken(TK("@eol")); while(parser->matchChar('\n'));
parser->setNextToken(TK("@eol"));
if(!parser->eatIndentation()) indentationError("unindent does not match any outer indentation level");
return;
}
@ -5324,7 +5326,7 @@ public:
eatNumber();
} else if (parser->isNameStart(c)) {
int ret = parser->eatName();
if(ret!=0) syntaxError("identifier is illegal, err " + std::to_string(ret));
if(ret!=0) syntaxError("@id is illegal, err " + std::to_string(ret));
} else {
syntaxError("unknown character: " + std::string(1, c));
}
@ -5427,7 +5429,7 @@ public:
_Func func = pkpy::make_shared<Function>();
func->name = "<lambda>";
if(!match(TK(":"))){
__compileFunctionArgs(func);
__compileFunctionArgs(func, false);
consume(TK(":"));
}
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
@ -5962,7 +5964,7 @@ __LISTCOMP:
emitCode(OP_BUILD_CLASS, clsNameIdx);
}
void __compileFunctionArgs(_Func func){
void __compileFunctionArgs(_Func func, bool enableTypeHints){
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
do {
if(state == 3) syntaxError("**kwargs should be the last argument");
@ -5979,6 +5981,9 @@ __LISTCOMP:
const _Str& name = parser->previous.str();
if(func->hasName(name)) syntaxError("duplicate argument name");
// eat type hints
if(enableTypeHints && match(TK(":"))) consume(TK("@id"));
if(state == 0 && peek() == TK("=")) state = 2;
switch (state)
@ -6009,10 +6014,13 @@ __LISTCOMP:
func->name = parser->previous.str();
if (match(TK("(")) && !match(TK(")"))) {
__compileFunctionArgs(func);
__compileFunctionArgs(func, true);
consume(TK(")"));
}
// eat type hints
if(match(TK("->"))) consume(TK("@id"));
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
this->codes.push(func->code);
compileBlockBody();
@ -6082,7 +6090,7 @@ __LISTCOMP:
/***** Error Reporter *****/
_Str getLineSnapshot(){
int lineno = parser->current_line;
int lineno = parser->current.line;
if(parser->peekChar() == '\n') lineno--;
return parser->src->snapshot(lineno);
}

@ -1 +1 @@
Subproject commit f0c35d535dca99b31b15100f82f48bc1becbca45
Subproject commit 81b5fc7f112d83abc6fd93824397017e3d837921

View File

@ -3255,7 +3255,7 @@ struct Parser {
int count = 0;
while (true) {
switch (peekChar()) {
case ' ': count++; break;
case ' ' : count+=1; break;
case '\t': count+=4; break;
default: return count;
}
@ -3266,6 +3266,8 @@ struct Parser {
bool eatIndentation(){
if(brackets_level_0 > 0 || brackets_level_1 > 0 || brackets_level_2 > 0) return true;
int spaces = eatSpaces();
if(peekChar() == '#') skipLineComment();
if(peekChar() == '\0' || peekChar() == '\n') return true;
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
if(spaces > indents.top()){
indents.push(spaces);
@ -5236,7 +5238,7 @@ public:
parser->previous = parser->current;
parser->current = parser->nextToken();
//_Str _info = parser->current.info(); printf("%s\n", (const char*)_info);
//_Str _info = parser->current.info(); std::cout << _info << '[' << parser->current_line << ']' << std::endl;
while (parser->peekChar() != '\0') {
parser->token_start = parser->current_char;
@ -5311,7 +5313,7 @@ public:
case '\r': break; // just ignore '\r'
case ' ': case '\t': parser->eatSpaces(); break;
case '\n': {
parser->setNextToken(TK("@eol")); while(parser->matchChar('\n'));
parser->setNextToken(TK("@eol"));
if(!parser->eatIndentation()) indentationError("unindent does not match any outer indentation level");
return;
}
@ -5324,7 +5326,7 @@ public:
eatNumber();
} else if (parser->isNameStart(c)) {
int ret = parser->eatName();
if(ret!=0) syntaxError("identifier is illegal, err " + std::to_string(ret));
if(ret!=0) syntaxError("@id is illegal, err " + std::to_string(ret));
} else {
syntaxError("unknown character: " + std::string(1, c));
}
@ -5427,7 +5429,7 @@ public:
_Func func = pkpy::make_shared<Function>();
func->name = "<lambda>";
if(!match(TK(":"))){
__compileFunctionArgs(func);
__compileFunctionArgs(func, false);
consume(TK(":"));
}
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
@ -5962,7 +5964,7 @@ __LISTCOMP:
emitCode(OP_BUILD_CLASS, clsNameIdx);
}
void __compileFunctionArgs(_Func func){
void __compileFunctionArgs(_Func func, bool enableTypeHints){
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
do {
if(state == 3) syntaxError("**kwargs should be the last argument");
@ -5979,6 +5981,9 @@ __LISTCOMP:
const _Str& name = parser->previous.str();
if(func->hasName(name)) syntaxError("duplicate argument name");
// eat type hints
if(enableTypeHints && match(TK(":"))) consume(TK("@id"));
if(state == 0 && peek() == TK("=")) state = 2;
switch (state)
@ -6009,10 +6014,13 @@ __LISTCOMP:
func->name = parser->previous.str();
if (match(TK("(")) && !match(TK(")"))) {
__compileFunctionArgs(func);
__compileFunctionArgs(func, true);
consume(TK(")"));
}
// eat type hints
if(match(TK("->"))) consume(TK("@id"));
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
this->codes.push(func->code);
compileBlockBody();
@ -6082,7 +6090,7 @@ __LISTCOMP:
/***** Error Reporter *****/
_Str getLineSnapshot(){
int lineno = parser->current_line;
int lineno = parser->current.line;
if(parser->peekChar() == '\n') lineno--;
return parser->src->snapshot(lineno);
}

View File

@ -1,7 +1,7 @@
{
"name": "com.bl.pocketpy",
"displayName": "PocketPy",
"version": "0.4.7",
"version": "0.4.8",
"unity": "2020.3",
"description": "A lightweight Python interpreter for game engines.",
"dependencies": {}

View File

@ -175,7 +175,7 @@ public:
parser->previous = parser->current;
parser->current = parser->nextToken();
//_Str _info = parser->current.info(); printf("%s\n", (const char*)_info);
//_Str _info = parser->current.info(); std::cout << _info << '[' << parser->current_line << ']' << std::endl;
while (parser->peekChar() != '\0') {
parser->token_start = parser->current_char;
@ -250,7 +250,7 @@ public:
case '\r': break; // just ignore '\r'
case ' ': case '\t': parser->eatSpaces(); break;
case '\n': {
parser->setNextToken(TK("@eol")); while(parser->matchChar('\n'));
parser->setNextToken(TK("@eol"));
if(!parser->eatIndentation()) indentationError("unindent does not match any outer indentation level");
return;
}
@ -263,7 +263,7 @@ public:
eatNumber();
} else if (parser->isNameStart(c)) {
int ret = parser->eatName();
if(ret!=0) syntaxError("identifier is illegal, err " + std::to_string(ret));
if(ret!=0) syntaxError("@id is illegal, err " + std::to_string(ret));
} else {
syntaxError("unknown character: " + std::string(1, c));
}
@ -366,7 +366,7 @@ public:
_Func func = pkpy::make_shared<Function>();
func->name = "<lambda>";
if(!match(TK(":"))){
__compileFunctionArgs(func);
__compileFunctionArgs(func, false);
consume(TK(":"));
}
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
@ -901,7 +901,7 @@ __LISTCOMP:
emitCode(OP_BUILD_CLASS, clsNameIdx);
}
void __compileFunctionArgs(_Func func){
void __compileFunctionArgs(_Func func, bool enableTypeHints){
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
do {
if(state == 3) syntaxError("**kwargs should be the last argument");
@ -918,6 +918,9 @@ __LISTCOMP:
const _Str& name = parser->previous.str();
if(func->hasName(name)) syntaxError("duplicate argument name");
// eat type hints
if(enableTypeHints && match(TK(":"))) consume(TK("@id"));
if(state == 0 && peek() == TK("=")) state = 2;
switch (state)
@ -948,10 +951,13 @@ __LISTCOMP:
func->name = parser->previous.str();
if (match(TK("(")) && !match(TK(")"))) {
__compileFunctionArgs(func);
__compileFunctionArgs(func, true);
consume(TK(")"));
}
// eat type hints
if(match(TK("->"))) consume(TK("@id"));
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
this->codes.push(func->code);
compileBlockBody();
@ -1021,7 +1027,7 @@ __LISTCOMP:
/***** Error Reporter *****/
_Str getLineSnapshot(){
int lineno = parser->current_line;
int lineno = parser->current.line;
if(parser->peekChar() == '\n') lineno--;
return parser->src->snapshot(lineno);
}

View File

@ -133,7 +133,7 @@ struct Parser {
int count = 0;
while (true) {
switch (peekChar()) {
case ' ': count++; break;
case ' ' : count+=1; break;
case '\t': count+=4; break;
default: return count;
}
@ -144,6 +144,8 @@ struct Parser {
bool eatIndentation(){
if(brackets_level_0 > 0 || brackets_level_1 > 0 || brackets_level_2 > 0) return true;
int spaces = eatSpaces();
if(peekChar() == '#') skipLineComment();
if(peekChar() == '\0' || peekChar() == '\n') return true;
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
if(spaces > indents.top()){
indents.push(spaces);

44
tests/_typehints.py Normal file
View File

@ -0,0 +1,44 @@
# test type hints
def f(x: int) -> int:
return x + 1
def g(x: int, y: int) -> int:
return x + y
def h(x: int, y):
return x + y
def i(x, y: int):
return x + y
# test type hints with default values
def f(x: int = 1) -> int:
return x + 1
def g(x: int = 1, y: int = 2) -> int:
return x + y
def h(x: int = 1, y = 2):
return x + y
def i(x = 1, y: int = 2):
return x + y
# test type hints with *args
def f(x: int, *args) -> int:
return x + len(args)
def g(x: int, y: int, *args) -> int:
return x + y + len(args)
def h(x: int, y, *args):
return x + y + len(args)
def i(x, y: int, *args):
return x + y + len(args)
def j(x, y: int, *args: str) -> int:
return x + y + len(args)

120
tests/dna.py Normal file
View File

@ -0,0 +1,120 @@
import random
import builtins
builtins.print = lambda *x: None
def f(x):
return -x**2+10
def create_init_DNA():
# out: DNA
ret = random.randint(-100,100)
return int_to_bin(ret)
def int_to_bin(x):
# in: int_DNA
# out: DNA
ret = []
if x >= 0:
ret.append(0)
else:
ret.append(1)
x = -x
for i in [4096,2048,1024,512,256,128,64,32,16,8,4,2,1] :
if x>=i :
ret.append(1)
x -= i
else :
ret.append(0)
return ret
def bin_to_int(x):
# in: DNA
# out: int_DNA
ret = 0
new_x = x[:]
flag = -(new_x[0]*2-1)
mul = 1
new_x = reversed(new_x)
new_x.pop()
for i in new_x :
ret += flag * i * mul
mul *= 2
return ret
def reversed(x):
ret = []
for i in range(0,len(x)):
ret.append(x[-i-1])
return ret
def create_DNAs(num):
# in: int
# out: DNAs
ret = []
for i in range(num):
ret.append(create_init_DNA())
return ret
def bins_to_ints(x):
# in: DNAs
# out: int_DNAs
ret = []
for i in x:
ret.append(bin_to_int(i))
return ret
def create_probabilitys(x):
# in: DNAs
# out: probabilitys
scores = survival_scores(x)
mid = []
ret = []
sum = 0
for i in scores:
sum+=i
for i in scores:
mid.append(1/(i/sum))
sum = 0
for i in mid:
sum+=i
for i in mid:
ret.append(i/sum)
return ret
def survival_scores(x):
# in: DNAs
# out: survival_scores
ret = []
for i in x:
ret.append(f(bin_to_int(i)))
return ret
def choose_DNA(DNAs,probabilitys):
# in: DNAs,probabilitys
# out: DNA
# probabilitys是由若干(01)之间的浮点数组成的数组这些浮点数的和为1
i = 0 # i记录取出元素的位置
ran = random.random()
# a=0
for max in probabilitys :
if i != 0 :
min = probabilitys[i-1]
else :
min = 0
if ran < max and ran >= min :
return DNAs[i]
def next_gen_DNAs(DNAs,num=None):
num = num or len(DNAs)
ret = []
for i in range(num) :
ret.append(choose_DNA(DNAs,create_probabilitys(DNAs)))
a = create_DNAs(10)
print(a)
print(bins_to_ints(a))
print(survival_scores(a))
print(create_probabilitys(a))