diff --git a/plugins/flutter/CHANGELOG.md b/plugins/flutter/CHANGELOG.md index a2aabf54..82b769c8 100644 --- a/plugins/flutter/CHANGELOG.md +++ b/plugins/flutter/CHANGELOG.md @@ -8,4 +8,11 @@ The initial version. Hello, world! + Support hex integer literal `0xFFFF` + Fix some bugs + Add `list.pop` and `reversed` builtin function -+ Optimize `dict` performance \ No newline at end of file ++ 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 \ No newline at end of file diff --git a/plugins/flutter/pubspec.yaml b/plugins/flutter/pubspec.yaml index 574b6716..c97534b3 100644 --- a/plugins/flutter/pubspec.yaml +++ b/plugins/flutter/pubspec.yaml @@ -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 diff --git a/plugins/flutter/src/pocketpy.h b/plugins/flutter/src/pocketpy.h index 53386107..1ef41d29 100644 --- a/plugins/flutter/src/pocketpy.h +++ b/plugins/flutter/src/pocketpy.h @@ -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(); func->name = ""; if(!match(TK(":"))){ - __compileFunctionArgs(func); + __compileFunctionArgs(func, false); consume(TK(":")); } func->code = pkpy::make_shared(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(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); } diff --git a/plugins/godot/godot-cpp b/plugins/godot/godot-cpp index f0c35d53..81b5fc7f 160000 --- a/plugins/godot/godot-cpp +++ b/plugins/godot/godot-cpp @@ -1 +1 @@ -Subproject commit f0c35d535dca99b31b15100f82f48bc1becbca45 +Subproject commit 81b5fc7f112d83abc6fd93824397017e3d837921 diff --git a/plugins/unity/com.bl.pocketpy/Plugins/iOS/pocketpy.h b/plugins/unity/com.bl.pocketpy/Plugins/iOS/pocketpy.h index 53386107..1ef41d29 100644 --- a/plugins/unity/com.bl.pocketpy/Plugins/iOS/pocketpy.h +++ b/plugins/unity/com.bl.pocketpy/Plugins/iOS/pocketpy.h @@ -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(); func->name = ""; if(!match(TK(":"))){ - __compileFunctionArgs(func); + __compileFunctionArgs(func, false); consume(TK(":")); } func->code = pkpy::make_shared(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(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); } diff --git a/plugins/unity/com.bl.pocketpy/package.json b/plugins/unity/com.bl.pocketpy/package.json index ba13a8f1..331671e8 100644 --- a/plugins/unity/com.bl.pocketpy/package.json +++ b/plugins/unity/com.bl.pocketpy/package.json @@ -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": {} diff --git a/src/compiler.h b/src/compiler.h index 84feae20..6144b701 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -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(); func->name = ""; if(!match(TK(":"))){ - __compileFunctionArgs(func); + __compileFunctionArgs(func, false); consume(TK(":")); } func->code = pkpy::make_shared(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(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); } diff --git a/src/parser.h b/src/parser.h index 73045866..2d69f5b8 100644 --- a/src/parser.h +++ b/src/parser.h @@ -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); diff --git a/tests/basic.py b/tests/_basic.py similarity index 100% rename from tests/basic.py rename to tests/_basic.py diff --git a/tests/builtin_ty.py b/tests/_builtin_ty.py similarity index 100% rename from tests/builtin_ty.py rename to tests/_builtin_ty.py diff --git a/tests/class.py b/tests/_class.py similarity index 100% rename from tests/class.py rename to tests/_class.py diff --git a/tests/controlflow.py b/tests/_controlflow.py similarity index 100% rename from tests/controlflow.py rename to tests/_controlflow.py diff --git a/tests/functions.py b/tests/_functions.py similarity index 100% rename from tests/functions.py rename to tests/_functions.py diff --git a/tests/goto.py b/tests/_goto.py similarity index 100% rename from tests/goto.py rename to tests/_goto.py diff --git a/tests/json.py b/tests/_json.py similarity index 100% rename from tests/json.py rename to tests/_json.py diff --git a/tests/listcomp.py b/tests/_listcomp.py similarity index 100% rename from tests/listcomp.py rename to tests/_listcomp.py diff --git a/tests/math.py b/tests/_math.py similarity index 100% rename from tests/math.py rename to tests/_math.py diff --git a/tests/multiline.py b/tests/_multiline.py similarity index 100% rename from tests/multiline.py rename to tests/_multiline.py diff --git a/tests/pointer.py b/tests/_pointer.py similarity index 100% rename from tests/pointer.py rename to tests/_pointer.py diff --git a/tests/prime.py b/tests/_prime.py similarity index 100% rename from tests/prime.py rename to tests/_prime.py diff --git a/tests/random.py b/tests/_random.py similarity index 100% rename from tests/random.py rename to tests/_random.py diff --git a/tests/_typehints.py b/tests/_typehints.py new file mode 100644 index 00000000..4e262317 --- /dev/null +++ b/tests/_typehints.py @@ -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) \ No newline at end of file diff --git a/tests/dna.py b/tests/dna.py new file mode 100644 index 00000000..fbdc93c9 --- /dev/null +++ b/tests/dna.py @@ -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是由若干(0,1)之间的浮点数组成的数组,这些浮点数的和为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)) \ No newline at end of file