blueloveTH 2 лет назад
Родитель
Сommit
06068ab3e0
8 измененных файлов с 51 добавлено и 32 удалено
  1. 1 3
      docs/features/basic.md
  2. 4 6
      docs/features/goto.md
  3. 3 1
      python/builtins.py
  4. 1 1
      src/ceval.h
  5. 4 5
      src/compiler.h
  6. 19 7
      src/lexer.h
  7. 15 5
      src/pocketpy.h
  8. 4 4
      tests/27_goto.py

+ 1 - 3
docs/features/basic.md

@@ -1,11 +1,9 @@
 ---
 icon: dot
-order: 100
 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 features marked with `YES` are supported, and the features marked with `NO` are not supported.
 

+ 4 - 6
docs/features/goto.md

@@ -3,8 +3,6 @@ icon: dot
 title: Goto Statement
 ---
 
-# goto/label
-
 pkpy supports `goto` and `label` just like C. You are allowed to change the control flow unconditionally.
 
 ## 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.
 
 ```
-goto .<identifier>
-label .<identifier>
+$goto <identifier>
+$label <identifier>
 ```
 
 ## Example
@@ -22,7 +20,7 @@ label .<identifier>
 for i in range(10):
   for j in range(10):
     for k in range(10):
-      goto .exit
+      $goto exit
 
-label .exit
+$label exit
 ```

+ 3 - 1
python/builtins.py

@@ -1,6 +1,8 @@
+import sys as _sys
+
 def print(*args, sep=' ', end='\n'):
     s = sep.join([str(i) for i in args])
-    __sys_stdout_write(s + end)
+    _sys.stdout.write(s + end)
 
 def round(x, ndigits=0):
     assert ndigits >= 0

+ 1 - 1
src/ceval.h

@@ -501,7 +501,7 @@ __NEXT_STEP:;
         TOP()->attr().set(_name, _0);
         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)
         call_method(POPX(), __enter__);
         DISPATCH();

+ 4 - 5
src/compiler.h

@@ -795,17 +795,16 @@ __SUBSCR_END:
                 ctx()->emit(OP_WITH_EXIT, BC_NOARG, prev().line);
             } 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");
-                consume(TK(".")); consume(TK("@id"));
+                consume(TK("@id"));
                 bool ok = ctx()->add_label(prev().str());
                 if(!ok) SyntaxError("label " + prev().str().escape() + " already exists");
                 consume_end_stmt();
             } break;
-            case TK("goto"):
+            case TK("$goto"):
                 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);
                 consume_end_stmt();
                 break;

+ 19 - 7
src/lexer.h

@@ -21,10 +21,11 @@ constexpr const char* kTokens[] = {
     /*****************************************/
     ".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}",
     "**", "=", ">", "<", "...", "->", "?", "@", "==", "!=", ">=", "<=",
+    /** SPEC_BEGIN **/
+    "$goto", "$label",
     /** KW_BEGIN **/
     "class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "yield",
     "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"
 };
 
@@ -38,13 +39,7 @@ constexpr TokenIndex TK(const char token[]) {
         while(*i && *j && *i == *j) { i++; j++;}
         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;
-#else
-    FATAL_ERROR();
-#endif
 }
 
 #define TK_STR(t) kTokens[t]
@@ -125,6 +120,13 @@ struct Lexer {
         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 count = 0;
         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 '$': {
+                    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;

+ 15 - 5
src/pocketpy.h

@@ -72,11 +72,6 @@ inline void init_builtins(VM* _vm) {
 #undef BIND_NUM_ARITH_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->check_non_tagged_type(args[0], vm->tp_type);
         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){
     PyObject* mod = vm->new_module("sys");
     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){

+ 4 - 4
tests/27_goto.py

@@ -2,9 +2,9 @@ a = []
 
 for i in range(10):         # [0]
     for j in range(10):     # [0-0]
-        goto .test 
+        $goto test 
         print(2)
-    label .test
+    $label test
     a.append(i)
     for k in range(5):      # [0-1]
         for t in range(7):  # [0-1-0]
@@ -16,7 +16,7 @@ b = False
 
 for i in range(10):         # [1]
     for j in range(10):     # [1-0]
-        goto .out
+        $goto out
         b = True
-label .out
+$label out
 assert not b