36936c479784 — Leonard Ritter tip 8 days ago
* `local` and `global` now treat right hand side declarations equivalent to `:=`
2 files changed, 51 insertions(+), 17 deletions(-)

M lib/scopes/core.sc
M testing/test_local.sc
M lib/scopes/core.sc +32 -15
@@ 3059,6 3059,16 @@ fn has-binding-operator? (expr)
                 return true
         repeat next
 
+# properly expand a right hand side term of a binding-like expression to conform to
+    how `:=` treats right hand side terms
+fn expand-binding-expr (anchor rhs next-expr env)
+    let rhs =
+        if (== (countof rhs) 1)
+            let rhs = (decons rhs)
+            rhs
+        else `rhs
+    sc_expand ('tag rhs anchor) next-expr env
+
 fn parse-binding-expr (anchor expr next-expr env)
     loop (lhs rhs = '() expr)
         if (empty? rhs)

          
@@ 3067,12 3077,7 @@ fn parse-binding-expr (anchor expr next-
         if (== ('typeof at) Symbol)
             let at = (as at Symbol)
             if (== at ':=)
-                let rhs =
-                    if (== (countof rhs) 1)
-                        let rhs = (decons rhs)
-                        rhs
-                    else `rhs
-                let rhs next-expr env = (sc_expand ('tag rhs anchor) next-expr env)
+                let rhs next-expr env = (expand-binding-expr anchor rhs next-expr env)
                 let newexpr =
                     'join
                         cons let ('reverse lhs)

          
@@ 7770,18 7775,30 @@ inline gen-allocator-sugar (copyf newf)
         let _let = ('tag `let anchor)
         let result =
             sugar-match values...
-            case (name '= value)
+            case (name '= value...)
+                let value next-expr sugar-scope = (expand-binding-expr anchor value... next-expr sugar-scope)
+                let callexpr =
+                    'tag `[(qq ([copy-by-value expr-head value]))] anchor
+                return `[(qq [_let name] = [callexpr])] next-expr sugar-scope
+            case (name ':= value...)
+                let value next-expr sugar-scope = (expand-binding-expr anchor value... next-expr sugar-scope)
                 let callexpr =
                     'tag `[(qq ([copy-by-value expr-head value]))] anchor
-                `[(qq [_let name] = [callexpr])]
-            case ('= value)
-                `[(qq ([copy-by-value expr-head value]))]
-            case (name ': T '= value)
+                return `[(qq [_let name] = [callexpr])] next-expr sugar-scope
+            case ('= value...)
+                let value next-expr sugar-scope = (expand-binding-expr anchor value... next-expr sugar-scope)
+                return `[(qq ([copy-by-value expr-head value]))] next-expr sugar-scope
+            case (':= value...)
+                let value next-expr sugar-scope = (expand-binding-expr anchor value... next-expr sugar-scope)
+                return `[(qq ([copy-by-value expr-head value]))] next-expr sugar-scope
+            case (name ': T '= value...)
+                let value next-expr sugar-scope = (expand-binding-expr anchor value... next-expr sugar-scope)
                 let callexpr =
                     'tag `[(qq ([copyf expr-head T value]))] anchor
-                `[(qq [_let name] = [callexpr])]
-            case (': T '= value)
-                `[(qq ([copyf expr-head T value]))]
+                return `[(qq [_let name] = [callexpr])] next-expr sugar-scope
+            case (': T '= value...)
+                let value next-expr sugar-scope = (expand-binding-expr anchor value... next-expr sugar-scope)
+                return `[(qq ([copyf expr-head T value]))] next-expr sugar-scope
             case (name ': T args...)
                 let callexpr =
                     'tag `[(qq [newf expr-head T] (unquote-splice args...))] anchor

          
@@ 7793,7 7810,7 @@ inline gen-allocator-sugar (copyf newf)
             default
                 error
                     .. "syntax: " (tostring expr-head) " [<name>] [: <type>] [= <value>]"
-        'tag result anchor
+        _ ('tag result anchor) next-expr sugar-scope
 
 """"declares a mutable variable on the local function stack.
 

          
M testing/test_local.sc +19 -2
@@ 1,3 1,5 @@ 
+
+using import testing
 
 # define stack variable with type signature and init value
 local a : i32 = 3:i8

          
@@ 5,8 7,23 @@ local a : i32 = 3:i8
 local b : i32
 assert (b == 0)
 b = 2
-# infer type from initialization argument
-local k = (a + b)
+# infer type from initialization argument; both `=` and `:=` are accepted
+local k := (a + b)
 assert (k == 5)
 
+# local ... = auto-wraps the right hand side, accepts multiple left hand arguments
+local x = + 1 2
+test (x == 3)
+local x2 : i32 = + 1 2
+test (x2 == 3)
+test ((local : i32 = + 1 2) == 3)
+
+# local ... = also supports block sugars like `if`
+# right hand side is evaluated in same scope
+local x := if ((local z := 10) == 10)
+    20
+else
+    30
+test (and (x == 20) (z == 10))
+
 true