blueloveTH 3 anni fa
parent
commit
26b065c1fb

+ 8 - 1
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
++ 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

+ 1 - 1
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
 

+ 16 - 8
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<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
plugins/godot/godot-cpp

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

+ 16 - 8
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<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
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": {}

+ 13 - 7
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<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);
     }

+ 3 - 1
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);

+ 0 - 0
tests/basic.py → tests/_basic.py


+ 0 - 0
tests/builtin_ty.py → tests/_builtin_ty.py


+ 0 - 0
tests/class.py → tests/_class.py


+ 0 - 0
tests/controlflow.py → tests/_controlflow.py


+ 0 - 0
tests/functions.py → tests/_functions.py


+ 0 - 0
tests/goto.py → tests/_goto.py


+ 0 - 0
tests/json.py → tests/_json.py


+ 0 - 0
tests/listcomp.py → tests/_listcomp.py


+ 0 - 0
tests/math.py → tests/_math.py


+ 0 - 0
tests/multiline.py → tests/_multiline.py


+ 0 - 0
tests/pointer.py → tests/_pointer.py


+ 0 - 0
tests/prime.py → tests/_prime.py


+ 0 - 0
tests/random.py → tests/_random.py


+ 44 - 0
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)

+ 120 - 0
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))