blueloveTH 1 неделя назад
Родитель
Сommit
9a57b281e8

+ 1 - 1
docs/retype.yml

@@ -3,7 +3,7 @@ output: .retype
 url: https://pocketpy.dev
 branding:
   title: pocketpy
-  label: v2.1.8
+  label: v2.1.9
   logo: "./static/logo.png"
 favicon: "./static/logo.png"
 meta:

+ 2 - 0
include/pocketpy/compiler/lexer.h

@@ -74,6 +74,7 @@ typedef enum TokenIndex {
     TK_GE,
     TK_LE,
     TK_INVERT,
+    TK_WALRUS,
     /***************/
     TK_FALSE,
     TK_NONE,
@@ -141,6 +142,7 @@ typedef struct Token {
 // https://docs.python.org/3/reference/expressions.html#operator-precedence
 enum Precedence {
     PREC_LOWEST = 0,
+    PREC_NAMED_EXPR,   // :=
     PREC_LAMBDA,       // lambda
     PREC_TERNARY,      // ?:
     PREC_LOGICAL_OR,   // or

+ 1 - 1
plugins/flutter/pocketpy/ios/pocketpy.podspec

@@ -35,7 +35,7 @@ A new Flutter FFI plugin project.
 
   s.prepare_command = <<-CMD
   rm -rf pocketpy
-  git clone --branch v2.1.8 --depth 1 https://github.com/pocketpy/pocketpy.git
+  git clone --branch v2.1.9 --depth 1 https://github.com/pocketpy/pocketpy.git
   cd pocketpy
   git submodule update --init --recursive --depth 1
   bash build_ios_libs.sh

+ 1 - 1
plugins/flutter/pocketpy/macos/pocketpy.podspec

@@ -32,7 +32,7 @@ A new Flutter FFI plugin project.
 
   s.prepare_command = <<-CMD
   rm -rf pocketpy
-  git clone --branch v2.1.8 --depth 1 https://github.com/pocketpy/pocketpy.git
+  git clone --branch v2.1.9 --depth 1 https://github.com/pocketpy/pocketpy.git
   cd pocketpy
   git submodule update --init --recursive --depth 1
   bash build_darwin_libs.sh

+ 1 - 1
plugins/flutter/pocketpy/pubspec.yaml

@@ -1,6 +1,6 @@
 name: pocketpy
 description: A lightweight Python interpreter for game engines. It supports Android/iOS/Windows/Linux/MacOS.
-version: 2.1.8
+version: 2.1.9
 homepage: https://pocketpy.dev
 repository: https://github.com/pocketpy/pocketpy
 

+ 1 - 1
plugins/flutter/pocketpy/src/CMakeLists.txt

@@ -20,7 +20,7 @@ set(PK_BUILD_SHARED_LIB ON CACHE BOOL "" FORCE)
 FetchContent_Declare(
   pocketpy
   GIT_REPOSITORY https://github.com/pocketpy/pocketpy.git
-  GIT_TAG        v2.1.8
+  GIT_TAG        v2.1.9
 )
 
 FetchContent_MakeAvailable(pocketpy)

+ 47 - 0
src/compiler/compiler.c

@@ -717,6 +717,36 @@ GroupedExpr* GroupedExpr__new(int line, Expr* child) {
     return self;
 }
 
+// NamedExpr: walrus operator (x := expr)
+typedef struct NamedExpr {
+    EXPR_COMMON_HEADER
+    NameExpr* name;
+    Expr* rhs;
+} NamedExpr;
+
+static void NamedExpr__dtor(Expr* self_) {
+    NamedExpr* self = (NamedExpr*)self_;
+    vtdelete((Expr*)self->name);
+    vtdelete(self->rhs);
+}
+
+static void NamedExpr__emit_(Expr* self_, Ctx* ctx) {
+    NamedExpr* self = (NamedExpr*)self_;
+    vtemit_(self->rhs, ctx);                              // [value]
+    Ctx__emit_(ctx, OP_DUP_TOP, BC_NOARG, self->line);   // [value, value]
+    vtemit_store((Expr*)self->name, ctx);                 // [value]
+}
+
+static NamedExpr* NamedExpr__new(int line, NameExpr* name, Expr* rhs) {
+    const static ExprVt Vt = {.dtor = NamedExpr__dtor, .emit_ = NamedExpr__emit_};
+    NamedExpr* self = PK_MALLOC(sizeof(NamedExpr));
+    self->vt = &Vt;
+    self->line = line;
+    self->name = name;
+    self->rhs = rhs;
+    return self;
+}
+
 typedef struct BinaryExpr {
     EXPR_COMMON_HEADER
     Expr* lhs;
@@ -1680,6 +1710,22 @@ static Error* exprAnd(Compiler* self) {
     return NULL;
 }
 
+static Error* exprWalrus(Compiler* self) {
+    Error* err;
+    int line = prev()->line;
+    // LHS is on the stack; verify it's a simple name
+    Expr* lhs = Ctx__s_top(ctx());
+    if(!lhs->vt->is_name) {
+        return SyntaxError(self, "':=' target must be a simple name");
+    }
+    check(parse_expression(self, PREC_NAMED_EXPR + 1, false));
+    Expr* rhs = Ctx__s_popx(ctx());
+    NameExpr* name = (NameExpr*)Ctx__s_popx(ctx());
+    NamedExpr* e = NamedExpr__new(line, name, rhs);
+    Ctx__s_push(ctx(), (Expr*)e);
+    return NULL;
+}
+
 static Error* exprTernary(Compiler* self) {
     // [true_expr]
     Error* err;
@@ -2977,6 +3023,7 @@ const static PrattRule rules[TK__COUNT__] = {
     [TK_AND_KW ] =     { NULL,          exprAnd,            PREC_LOGICAL_AND   },
     [TK_OR_KW] =       { NULL,          exprOr,             PREC_LOGICAL_OR    },
     [TK_NOT_KW] =      { exprNot,       NULL,               PREC_LOGICAL_NOT   },
+    [TK_WALRUS] =      { NULL,          exprWalrus,         PREC_NAMED_EXPR    },
     [TK_TRUE] =        { exprLiteral0 },
     [TK_FALSE] =       { exprLiteral0 },
     [TK_NONE] =        { exprLiteral0 },

+ 6 - 1
src/compiler/lexer.c

@@ -469,7 +469,11 @@ static Error* lex_one_token(Lexer* self, bool* eof, bool is_fstring) {
                     // BUG: f"{stack[2:]}"
                     return eat_fstring_spec(self, eof);
                 }
-                add_token(self, TK_COLON);
+                if(matchchar(self, '=')) {
+                    add_token(self, TK_WALRUS);
+                } else {
+                    add_token(self, TK_COLON);
+                }
                 return NULL;
             }
             case ';': add_token(self, TK_SEMICOLON); return NULL;
@@ -694,6 +698,7 @@ const char* TokenSymbols[] = {
     ">=",
     "<=",
     "~",
+    ":=",
     /** KW_BEGIN **/
     // NOTE: These keywords should be sorted in ascending order!!
     "False",

+ 40 - 0
tests/90_walrus.py

@@ -0,0 +1,40 @@
+# Test walrus operator (:=)
+
+# Basic usage in if statement
+x = [1, 2, 3, 4, 5]
+if (n := len(x)) > 3:
+    assert n == 5
+
+# Usage in while loop
+data = [1, 2, 3, 0, 4, 5]
+results = []
+i = 0
+while (val := data[i]) != 0:
+    results.append(val)
+    i += 1
+assert results == [1, 2, 3]
+
+# Usage in list comprehension filter
+values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+even_squares = [y for x in values if (y := x * x) % 2 == 0]
+assert even_squares == [4, 16, 36, 64, 100]
+
+# Walrus in expression context
+a = 10
+b = (a := a + 5) * 2
+assert a == 15
+assert b == 30
+
+# Nested parenthesized walrus
+result = (x := (y := 3) + 1)
+assert x == 4
+assert y == 3
+
+# Test function 
+def test_walrus_in_function():
+    result = (x := (y := 3) + 1)
+    assert x == 4
+    assert y == 3
+    assert result == 4
+
+test_walrus_in_function()