Răsfoiți Sursa

support 1 element tuple

blueloveTH 2 ani în urmă
părinte
comite
d5128404ae
4 a modificat fișierele cu 31 adăugiri și 15 ștergeri
  1. 7 9
      docs/features/differences.md
  2. 6 1
      python/builtins.py
  3. 10 4
      src/compiler.h
  4. 8 1
      tests/06_tuple.py

+ 7 - 9
docs/features/differences.md

@@ -23,13 +23,12 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
 1. `__getattr__` and `__setattr__`.
 1. `__getattr__` and `__setattr__`.
 2. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
 2. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
 3. `__slots__` in class definition.
 3. `__slots__` in class definition.
-4. One element tuple. `(1,)` is not supported.
-5. Unpacking in `list` and `dict` literals, e.g. `[1, 2, *a]`.
-6. Access the exception object in try..except.
-7.  `else` clause in try..except.
-8.  Inplace methods like `__iadd__` and `__imul__`.
-9. `__del__` in class definition.
-10. Multiple inheritance.
+4. Unpacking in `list` and `dict` literals, e.g. `[1, 2, *a]`.
+5. Access the exception object in try..except.
+6.  `else` clause in try..except.
+7.  Inplace methods like `__iadd__` and `__imul__`.
+8. `__del__` in class definition.
+9. Multiple inheritance.
 
 
 ## Different behaviors
 ## Different behaviors
 
 
@@ -41,5 +40,4 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
 6. `__ne__` is not required. Define `__eq__` is enough.
 6. `__ne__` is not required. Define `__eq__` is enough.
 7. Raw string cannot have boundary quotes in it, even escaped. See [#55](https://github.com/blueloveTH/pocketpy/issues/55).
 7. Raw string cannot have boundary quotes in it, even escaped. See [#55](https://github.com/blueloveTH/pocketpy/issues/55).
 8. In a starred unpacked assignment, e.g. `a, b, *c = x`, the starred variable can only be presented in the last position. `a, *b, c = x` is not supported.
 8. In a starred unpacked assignment, e.g. `a, b, *c = x`, the starred variable can only be presented in the last position. `a, *b, c = x` is not supported.
-9. `a < b < c` does not work as you expected. Use `a < b and b < c` instead. **(available in main branch now)**
-10. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
+9. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.

+ 6 - 1
python/builtins.py

@@ -160,10 +160,15 @@ str.strip = __f
 
 
 ##### list #####
 ##### list #####
 list.__repr__ = lambda self: '[' + ', '.join([repr(i) for i in self]) + ']'
 list.__repr__ = lambda self: '[' + ', '.join([repr(i) for i in self]) + ']'
-tuple.__repr__ = lambda self: '(' + ', '.join([repr(i) for i in self]) + ')'
 list.__json__ = lambda self: '[' + ', '.join([i.__json__() for i in self]) + ']'
 list.__json__ = lambda self: '[' + ', '.join([i.__json__() for i in self]) + ']'
 tuple.__json__ = lambda self: '[' + ', '.join([i.__json__() for i in self]) + ']'
 tuple.__json__ = lambda self: '[' + ', '.join([i.__json__() for i in self]) + ']'
 
 
+def __f(self):
+    if len(self) == 1:
+        return '(' + repr(self[0]) + ',)'
+    return '(' + ', '.join([repr(i) for i in self]) + ')'
+tuple.__repr__ = __f
+
 def __qsort(a: list, L: int, R: int, key):
 def __qsort(a: list, L: int, R: int, key):
     if L >= R: return;
     if L >= R: return;
     mid = a[(R+L)//2];
     mid = a[(R+L)//2];

+ 10 - 4
src/compiler.h

@@ -221,7 +221,8 @@ class Compiler {
         std::vector<Expr_> items;
         std::vector<Expr_> items;
         items.push_back(ctx()->s_expr.popx());
         items.push_back(ctx()->s_expr.popx());
         do {
         do {
-            EXPR();         // NOTE: "1," will fail, "1,2" will be ok
+            if(!is_expression()) break;
+            EXPR();
             items.push_back(ctx()->s_expr.popx());
             items.push_back(ctx()->s_expr.popx());
         } while(match(TK(",")));
         } while(match(TK(",")));
         ctx()->s_expr.push(make_expr<TupleExpr>(
         ctx()->s_expr.push(make_expr<TupleExpr>(
@@ -563,16 +564,21 @@ __SUBSCR_END:
         consume_end_stmt();
         consume_end_stmt();
     }
     }
 
 
+    bool is_expression(){
+        PrattCallback prefix = rules[curr().type].prefix;
+        return prefix != nullptr;
+    }
+
     void parse_expression(int precedence, bool push_stack=true) {
     void parse_expression(int precedence, bool push_stack=true) {
+        PrattCallback prefix = rules[curr().type].prefix;
+        if (prefix == nullptr) SyntaxError(Str("expected an expression, but got ") + TK_STR(curr().type));
         advance();
         advance();
-        PrattCallback prefix = rules[prev().type].prefix;
-        if (prefix == nullptr) SyntaxError(Str("expected an expression, but got ") + TK_STR(prev().type));
         (this->*prefix)();
         (this->*prefix)();
         while (rules[curr().type].precedence >= precedence) {
         while (rules[curr().type].precedence >= precedence) {
             TokenIndex op = curr().type;
             TokenIndex op = curr().type;
             advance();
             advance();
             PrattCallback infix = rules[op].infix;
             PrattCallback infix = rules[op].infix;
-            if(infix == nullptr) throw std::runtime_error("(infix == nullptr) is true");
+            PK_ASSERT(infix != nullptr);
             (this->*infix)();
             (this->*infix)();
         }
         }
         if(!push_stack) ctx()->emit_expr();
         if(!push_stack) ctx()->emit_expr();

+ 8 - 1
tests/06_tuple.py

@@ -14,4 +14,11 @@ assert b == (1, 2, 3, 4, 5)
 
 
 a = tuple([])
 a = tuple([])
 b = *a, 1, 2, 3, *a, *a
 b = *a, 1, 2, 3, *a, *a
-assert b == (1, 2, 3)
+assert b == (1, 2, 3)
+
+
+assert (1,) == tuple([1])
+assert (1,2,) == tuple([1,2])
+
+a = 1,
+assert a == (1,)