blueloveTH 3 лет назад
Родитель
Сommit
229a836444

+ 3 - 2
plugins/flutter/CHANGELOG.md

@@ -17,6 +17,7 @@ The initial version. Hello, world!
 + Fix a bug about comment and indentation
 + Fix a bug about compile error line number
 
-## 0.4.8+3
+## 0.4.8+4
 
-+ Downgrade to `sdk>=2.17.0`
++ Downgrade to `sdk>=2.17.0`
++ Fix some bugs about compile error

+ 1 - 1
plugins/flutter/pubspec.yaml

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

+ 47 - 30
plugins/flutter/src/pocketpy.h

@@ -2904,14 +2904,14 @@ struct SourceMetadata {
     std::vector<const char*> lineStarts;
     CompileMode mode;
 
-    _Str getLine(int lineno) const {
-        if(lineno == -1) return "<?>";
+    std::pair<const char*,const char*> getLine(int lineno) const {
+        if(lineno == -1) return {nullptr, nullptr};
         lineno -= 1;
         if(lineno < 0) lineno = 0;
         const char* _start = lineStarts.at(lineno);
         const char* i = _start;
         while(*i != '\n' && *i != '\0') i++;
-        return _Str(_start, i-_start);
+        return {_start, i};
     }
 
     SourceMetadata(const char* source, _Str filename, CompileMode mode) {
@@ -2924,12 +2924,24 @@ struct SourceMetadata {
         this->mode = mode;
     }
 
-    _Str snapshot(int lineno){
+    _Str snapshot(int lineno, const char* cursor=nullptr){
         _StrStream ss;
         ss << "  " << "File \"" << filename << "\", line " << lineno << '\n';
-        _Str line = getLine(lineno).__lstrip();
-        if(line.empty()) line = "<?>";
+        std::pair<const char*,const char*> pair = getLine(lineno);
+        _Str line = "<?>";
+        int removedSpaces = 0;
+        if(pair.first && pair.second){
+            line = _Str(pair.first, pair.second-pair.first).__lstrip();
+            removedSpaces = pair.second - pair.first - line.size();
+            if(line.empty()) line = "<?>";
+        }
         ss << "    " << line << '\n';
+        if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second){
+            int column = cursor - pair.first - removedSpaces;
+            if(column >= 0){
+                ss << "    " << std::string(column, ' ') << "^\n";
+            }
+        }
         return ss.str();
     }
 
@@ -3301,12 +3313,6 @@ struct Parser {
         return c;
     }
 
-    inline bool isNameStart(char c){
-        if(isalpha(c) || c=='_') return true;
-        if(!isascii(c)) return true;
-        return false;
-    }
-
     int eatName() {
         current_char--;
         while(true){
@@ -5090,6 +5096,7 @@ public:
     std::stack<_Code> codes;
     std::stack<Loop> loops;
     bool isCompilingClass = false;
+    int lexingCnt = 0;
     VM* vm;
 
     emhash8::HashMap<_TokenType, GrammarRule> rules;
@@ -5233,8 +5240,14 @@ public:
         } 
     }
 
+    void lexToken(){
+        lexingCnt++;
+        _lexToken();
+        lexingCnt--;
+    }
+
     // Lex the next token and set it as the next token.
-    void lexToken() {
+    void _lexToken() {
         parser->previous = parser->current;
         parser->current = parser->nextToken();
 
@@ -5324,11 +5337,17 @@ public:
                     }
                     if (isdigit(c)) {
                         eatNumber();
-                    } else if (parser->isNameStart(c)) {
-                        int ret = parser->eatName();
-                        if(ret!=0) syntaxError("@id is illegal, err " + std::to_string(ret));
-                    } else {
-                        syntaxError("unknown character: " + std::string(1, c));
+                        return;
+                    }
+                    
+                    switch (parser->eatName())
+                    {
+                        case 0: break;
+                        case 1: syntaxError("invalid char: " + std::string(1, c));
+                        case 2: syntaxError("invalid utf8 sequence: " + std::string(1, c));
+                        case 3: syntaxError("@id contains invalid char"); break;
+                        case 4: syntaxError("invalid JSON token"); break;
+                        default: UNREACHABLE();
                     }
                     return;
                 }
@@ -6091,21 +6110,19 @@ __LISTCOMP:
     /***** Error Reporter *****/
     _Str getLineSnapshot(){
         int lineno = parser->current.line;
+        const char* cursor = parser->current.start;
+        // if error occurs in lexing, lineno should be `parser->current_line`
+        if(lexingCnt > 0){
+            lineno = parser->current_line;
+            cursor = parser->current_char;
+        }
         if(parser->peekChar() == '\n') lineno--;
-        return parser->src->snapshot(lineno);
-    }
-
-    void syntaxError(_Str msg){
-        throw CompileError("SyntaxError", msg, getLineSnapshot());
-    }
-
-    void indentationError(_Str msg){
-        throw CompileError("IndentationError", msg, getLineSnapshot());
+        return parser->src->snapshot(lineno, cursor);
     }
 
-    void unexpectedError(_Str msg){
-        throw CompileError("UnexpectedError", msg, getLineSnapshot());
-    }
+    void syntaxError(_Str msg){ throw CompileError("SyntaxError", msg, getLineSnapshot()); }
+    void indentationError(_Str msg){ throw CompileError("IndentationError", msg, getLineSnapshot()); }
+    void unexpectedError(_Str msg){ throw CompileError("UnexpectedError", msg, getLineSnapshot()); }
 };
 
 _Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE, bool noThrow=true) {

+ 1 - 1
plugins/godot/godot-cpp

@@ -1 +1 @@
-Subproject commit 70637fe5198a3dc5d130781987b3cf2b46de3efc
+Subproject commit c645191b67d056996ee4d0d6a387758c16edf7e2

+ 47 - 30
plugins/unity/com.bl.pocketpy/Plugins/iOS/pocketpy.h

@@ -2904,14 +2904,14 @@ struct SourceMetadata {
     std::vector<const char*> lineStarts;
     CompileMode mode;
 
-    _Str getLine(int lineno) const {
-        if(lineno == -1) return "<?>";
+    std::pair<const char*,const char*> getLine(int lineno) const {
+        if(lineno == -1) return {nullptr, nullptr};
         lineno -= 1;
         if(lineno < 0) lineno = 0;
         const char* _start = lineStarts.at(lineno);
         const char* i = _start;
         while(*i != '\n' && *i != '\0') i++;
-        return _Str(_start, i-_start);
+        return {_start, i};
     }
 
     SourceMetadata(const char* source, _Str filename, CompileMode mode) {
@@ -2924,12 +2924,24 @@ struct SourceMetadata {
         this->mode = mode;
     }
 
-    _Str snapshot(int lineno){
+    _Str snapshot(int lineno, const char* cursor=nullptr){
         _StrStream ss;
         ss << "  " << "File \"" << filename << "\", line " << lineno << '\n';
-        _Str line = getLine(lineno).__lstrip();
-        if(line.empty()) line = "<?>";
+        std::pair<const char*,const char*> pair = getLine(lineno);
+        _Str line = "<?>";
+        int removedSpaces = 0;
+        if(pair.first && pair.second){
+            line = _Str(pair.first, pair.second-pair.first).__lstrip();
+            removedSpaces = pair.second - pair.first - line.size();
+            if(line.empty()) line = "<?>";
+        }
         ss << "    " << line << '\n';
+        if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second){
+            int column = cursor - pair.first - removedSpaces;
+            if(column >= 0){
+                ss << "    " << std::string(column, ' ') << "^\n";
+            }
+        }
         return ss.str();
     }
 
@@ -3301,12 +3313,6 @@ struct Parser {
         return c;
     }
 
-    inline bool isNameStart(char c){
-        if(isalpha(c) || c=='_') return true;
-        if(!isascii(c)) return true;
-        return false;
-    }
-
     int eatName() {
         current_char--;
         while(true){
@@ -5090,6 +5096,7 @@ public:
     std::stack<_Code> codes;
     std::stack<Loop> loops;
     bool isCompilingClass = false;
+    int lexingCnt = 0;
     VM* vm;
 
     emhash8::HashMap<_TokenType, GrammarRule> rules;
@@ -5233,8 +5240,14 @@ public:
         } 
     }
 
+    void lexToken(){
+        lexingCnt++;
+        _lexToken();
+        lexingCnt--;
+    }
+
     // Lex the next token and set it as the next token.
-    void lexToken() {
+    void _lexToken() {
         parser->previous = parser->current;
         parser->current = parser->nextToken();
 
@@ -5324,11 +5337,17 @@ public:
                     }
                     if (isdigit(c)) {
                         eatNumber();
-                    } else if (parser->isNameStart(c)) {
-                        int ret = parser->eatName();
-                        if(ret!=0) syntaxError("@id is illegal, err " + std::to_string(ret));
-                    } else {
-                        syntaxError("unknown character: " + std::string(1, c));
+                        return;
+                    }
+                    
+                    switch (parser->eatName())
+                    {
+                        case 0: break;
+                        case 1: syntaxError("invalid char: " + std::string(1, c));
+                        case 2: syntaxError("invalid utf8 sequence: " + std::string(1, c));
+                        case 3: syntaxError("@id contains invalid char"); break;
+                        case 4: syntaxError("invalid JSON token"); break;
+                        default: UNREACHABLE();
                     }
                     return;
                 }
@@ -6091,21 +6110,19 @@ __LISTCOMP:
     /***** Error Reporter *****/
     _Str getLineSnapshot(){
         int lineno = parser->current.line;
+        const char* cursor = parser->current.start;
+        // if error occurs in lexing, lineno should be `parser->current_line`
+        if(lexingCnt > 0){
+            lineno = parser->current_line;
+            cursor = parser->current_char;
+        }
         if(parser->peekChar() == '\n') lineno--;
-        return parser->src->snapshot(lineno);
-    }
-
-    void syntaxError(_Str msg){
-        throw CompileError("SyntaxError", msg, getLineSnapshot());
-    }
-
-    void indentationError(_Str msg){
-        throw CompileError("IndentationError", msg, getLineSnapshot());
+        return parser->src->snapshot(lineno, cursor);
     }
 
-    void unexpectedError(_Str msg){
-        throw CompileError("UnexpectedError", msg, getLineSnapshot());
-    }
+    void syntaxError(_Str msg){ throw CompileError("SyntaxError", msg, getLineSnapshot()); }
+    void indentationError(_Str msg){ throw CompileError("IndentationError", msg, getLineSnapshot()); }
+    void unexpectedError(_Str msg){ throw CompileError("UnexpectedError", msg, getLineSnapshot()); }
 };
 
 _Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE, bool noThrow=true) {

+ 29 - 18
src/compiler.h

@@ -27,6 +27,7 @@ public:
     std::stack<_Code> codes;
     std::stack<Loop> loops;
     bool isCompilingClass = false;
+    int lexingCnt = 0;
     VM* vm;
 
     emhash8::HashMap<_TokenType, GrammarRule> rules;
@@ -170,8 +171,14 @@ public:
         } 
     }
 
+    void lexToken(){
+        lexingCnt++;
+        _lexToken();
+        lexingCnt--;
+    }
+
     // Lex the next token and set it as the next token.
-    void lexToken() {
+    void _lexToken() {
         parser->previous = parser->current;
         parser->current = parser->nextToken();
 
@@ -261,11 +268,17 @@ public:
                     }
                     if (isdigit(c)) {
                         eatNumber();
-                    } else if (parser->isNameStart(c)) {
-                        int ret = parser->eatName();
-                        if(ret!=0) syntaxError("@id is illegal, err " + std::to_string(ret));
-                    } else {
-                        syntaxError("unknown character: " + std::string(1, c));
+                        return;
+                    }
+                    
+                    switch (parser->eatName())
+                    {
+                        case 0: break;
+                        case 1: syntaxError("invalid char: " + std::string(1, c));
+                        case 2: syntaxError("invalid utf8 sequence: " + std::string(1, c));
+                        case 3: syntaxError("@id contains invalid char"); break;
+                        case 4: syntaxError("invalid JSON token"); break;
+                        default: UNREACHABLE();
                     }
                     return;
                 }
@@ -1028,21 +1041,19 @@ __LISTCOMP:
     /***** Error Reporter *****/
     _Str getLineSnapshot(){
         int lineno = parser->current.line;
+        const char* cursor = parser->current.start;
+        // if error occurs in lexing, lineno should be `parser->current_line`
+        if(lexingCnt > 0){
+            lineno = parser->current_line;
+            cursor = parser->current_char;
+        }
         if(parser->peekChar() == '\n') lineno--;
-        return parser->src->snapshot(lineno);
+        return parser->src->snapshot(lineno, cursor);
     }
 
-    void syntaxError(_Str msg){
-        throw CompileError("SyntaxError", msg, getLineSnapshot());
-    }
-
-    void indentationError(_Str msg){
-        throw CompileError("IndentationError", msg, getLineSnapshot());
-    }
-
-    void unexpectedError(_Str msg){
-        throw CompileError("UnexpectedError", msg, getLineSnapshot());
-    }
+    void syntaxError(_Str msg){ throw CompileError("SyntaxError", msg, getLineSnapshot()); }
+    void indentationError(_Str msg){ throw CompileError("IndentationError", msg, getLineSnapshot()); }
+    void unexpectedError(_Str msg){ throw CompileError("UnexpectedError", msg, getLineSnapshot()); }
 };
 
 _Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE, bool noThrow=true) {

+ 18 - 6
src/error.h

@@ -21,14 +21,14 @@ struct SourceMetadata {
     std::vector<const char*> lineStarts;
     CompileMode mode;
 
-    _Str getLine(int lineno) const {
-        if(lineno == -1) return "<?>";
+    std::pair<const char*,const char*> getLine(int lineno) const {
+        if(lineno == -1) return {nullptr, nullptr};
         lineno -= 1;
         if(lineno < 0) lineno = 0;
         const char* _start = lineStarts.at(lineno);
         const char* i = _start;
         while(*i != '\n' && *i != '\0') i++;
-        return _Str(_start, i-_start);
+        return {_start, i};
     }
 
     SourceMetadata(const char* source, _Str filename, CompileMode mode) {
@@ -41,12 +41,24 @@ struct SourceMetadata {
         this->mode = mode;
     }
 
-    _Str snapshot(int lineno){
+    _Str snapshot(int lineno, const char* cursor=nullptr){
         _StrStream ss;
         ss << "  " << "File \"" << filename << "\", line " << lineno << '\n';
-        _Str line = getLine(lineno).__lstrip();
-        if(line.empty()) line = "<?>";
+        std::pair<const char*,const char*> pair = getLine(lineno);
+        _Str line = "<?>";
+        int removedSpaces = 0;
+        if(pair.first && pair.second){
+            line = _Str(pair.first, pair.second-pair.first).__lstrip();
+            removedSpaces = pair.second - pair.first - line.size();
+            if(line.empty()) line = "<?>";
+        }
         ss << "    " << line << '\n';
+        if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second){
+            int column = cursor - pair.first - removedSpaces;
+            if(column >= 0){
+                ss << "    " << std::string(column, ' ') << "^\n";
+            }
+        }
         return ss.str();
     }
 

+ 0 - 6
src/parser.h

@@ -179,12 +179,6 @@ struct Parser {
         return c;
     }
 
-    inline bool isNameStart(char c){
-        if(isalpha(c) || c=='_') return true;
-        if(!isascii(c)) return true;
-        return false;
-    }
-
     int eatName() {
         current_char--;
         while(true){

+ 185 - 0
tests/dna2.py

@@ -0,0 +1,185 @@
+import random
+
+def f(x):
+  if x >= 5 :
+    return x+5
+  else :
+    return -x+5
+
+def create_init_DNA(min,max):
+# out: DNA(['0','1',....])
+  ret = random.randint(min,max)
+  return int_to_bin(ret)
+
+def int_to_bin(x):
+# in: int_DNA(int)
+# out: DNA
+  ret = []
+  if x >= 0:
+    ret.append(0)
+  else:
+    ret.append(1)
+    x = -x
+  for i in [32768,16384,8192,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(int)
+  ret = 0
+  new_x = x[:]
+  flag = -(int(new_x[0])*2-1)
+  mul = 1
+  new_x = reversed(new_x)
+  new_x.pop()
+  for i in new_x :
+    ret += flag * int(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,min,max):
+# in: num(int)
+# out: DNAs([DNA,DNA,...])
+  ret = []
+  for i in range(num):
+    ret.append(create_init_DNA(min,max))
+  return ret
+
+def bins_to_ints(x):
+# in: DNAs
+# out: int_DNAs([int,int,...])
+  ret = []
+  for i in x:
+    ret.append(bin_to_int(i))
+  return ret
+
+def ints_to_bins(x):
+# in: int_DNAs
+# out: DNAs
+  ret = []
+  for i in x:
+    ret.append(int_to_bin(i))
+  return ret
+
+def create_probabilitys(x):
+# in: DNAs
+# out: probabilitys([float,float...])
+  scores = survival_scores(x)
+  mid = []
+  ret = []
+  sum = 0
+  for i in scores:
+    sum+=i
+  for i in scores:
+    mid.append(1/(i+0.0/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[f(int_DNA),...]
+  ret = []
+  for i in x:
+    ret.append(f(bin_to_int(i)/100))
+  return ret
+
+def choose_DNA(DNAs,probabilitys):
+# in: DNAs,probabilitys
+# out: choosen_DNA(DNA)
+# probabilitys是由若干(0,1)之间的浮点数组成的数组,这些浮点数的和为1
+  i = 0 # i记录取出元素的位置
+  ran = random.random()
+  max_sum = 0
+  for max in probabilitys :
+    max_sum += max
+    if i != 0 :
+      min_sum += probabilitys[i-1]
+    else :
+      min_sum = 0
+    if (ran < max_sum) and (ran >= min_sum) :
+      return DNAs[i]
+    i += 1
+
+def mating_DNAs(DNAs,num=None):
+# in: DNAs,num(int)交配组DNA数量
+# out: mating_DNAs(DNAs)交配组
+  num = num or len(DNAs)
+  ret = []
+  for i in range(num) :
+    ret.append(choose_DNA(DNAs,create_probabilitys(DNAs)))
+  return ret
+
+def son_DNA(DNAs):
+# in: mating_DNAs(DNAs)交配组
+# out: son_DNA(DNA)交叉互换后产生的子代
+  father = DNAs[random.randint(0,len(DNAs)-1)]
+  mother = DNAs[random.randint(0,len(DNAs)-1)]
+  pos = random.randint(0,len(DNAs[0])-1)
+  son_DNA = []
+  son_DNA += father[0:pos]
+  son_DNA += mother[pos+1:-1]
+  return son_DNA
+
+def mutation(DNA,part_rate):
+# in: son_DNA(DNA)交叉互换后的子代,part_rate(float)碱基对变异概率
+# out: mut_DNA(DNA)变异后的子代
+  ret = DNA[:]
+  for i in range(len(ret)):
+    k = random.random()
+    if k < part_rate :
+      ret[i] = str(-int(ret[i])+1)
+  return ret
+
+def next_DNAs(DNAs,father_rate,part_rate,mut_rate,num):
+# in: mating_DNAs(DNAs),father_rate(float)父代保留占比,part_rate(float)碱基对突变概率,mut_rate(float)生物变异概率,num(int)下一代数量
+# out: next_DNAs(DNAs)
+  ret = []
+  pro_DNAs = create_probabilitys(DNAs)
+  father_num = int(father_rate*num+0.5)
+  son_num = num - father_num
+  i = 1
+  for pro in reversed(sorted(pro_DNAs)):
+    if i > father_num:
+      break
+    ret.append(DNAs[pro_DNAs.index(pro)])
+    i += 1
+  for s in range(son_num):
+    k = random.random()
+    son_DNA=(mating_DNAs(DNAs)[0])
+    if k < mut_rate :
+      son_DNA = mutation(son_DNA,part_rate)
+    ret.append(son_DNA)
+  return ret
+
+def iterate(DNAs,father_rate,part_rate,mut_rate,iter_num,population):
+# in: DNAs父代,father_rate(float)每一次迭代保留父代的占比, num(int)迭代次数,population(int)种群数量
+# out: DNAs子代
+  ret = eval(repr(DNAs))
+  for i in range(iter_num):
+    ret = next_DNAs(ret,father_rate,part_rate,mut_rate,population)
+  return ret
+
+
+def 百分比化(a):
+  b = str(a*100)[0:5]
+  return f'{b}%'
+
+a = create_DNAs(5,-9999,9999)
+
+
+