<p>Suppose I have a block scoped language, in this case represented</p>
<pre class="lang-js prettyprint-override"><code>let b=2;

function a() {
    b+=1;
    let c;
    while (c&gt;b) {
        let c;
        c-=1;
        b-=c;
    }
}
</code></pre>
<p>How can I transpile this into something like python where variables are function scoped?</p>
<p>Ideally I'd want to output something vaguely readable and not mangle the variable names too much.</p>
<p>Note that some variables now alias, like <code>c</code>, some need their scope expanded like <code>b</code> and some reduced like <code>c</code>. Ideally I'd have some generic system that could handle arbitrary scopes no matter what the rules of the source language are.</p>
<p>Both languages are dynamically typed.</p>

<python><transpilers>
How to transpile between languages with different scoping rules?
CC BY-SA 4.0
2023-06-28T06:17:00.097Z
Lexically scoped languages cannot emulate dynamically scoped languages.
Aster
CC BY-SA 4.0
2023-06-28T07:57:35.380Z
@Aster they surely can, at a price of replacing every potentially dynamically scoped variable reference with a global hash table lookup.
SK-logic
<p>The scope of a variable can be expanded by moving its declaration further out; to translate between block-scoped and function-scoped variables, you need to make sure the declaration is at the top of the function. This may mean that two variables which had the same name in the source program may end up having the same scope, and one must be renamed. Unfortunately there is no way around this, so even if you don't want to &quot;mangle the variable names too much&quot; you will still have to mangle them slightly. It's up to you what kind of mangling you decide to do; I like to append numbers starting from 2, so <code>c</code>, <code>c2</code>, <code>c3</code> and so on:</p>
<pre class="lang-javascript prettyprint-override"><code>function a() {
    let c, c2;
    // ...
}
</code></pre>
<p>The other thing you need to take care of is when the source and target languages have different rules for reassigning non-local variables. Some languages (e.g. Javascript) just allow this, others (e.g. Python) require you to declare which non-local variables as <code>global</code> or <code>nonlocal</code> if you want to reassign them, while others still (e.g. Java) may outright forbid reassigning captured variables even when the assignment occurs locally.</p>
<p>To get around this, you can wrap the variable in a mutable container:</p>
<pre class="lang-javascript prettyprint-override"><code>let b = {value: 2};

function a() {
    b.value += 1;
    // ...
}
</code></pre>
<p>This works by replacing variable accesses with field accesses, and variable assignments with field assignments. Most imperative languages support both in some way.</p>

CC BY-SA 4.0
2023-06-27T20:48:07.957Z
2023-06-27T20:48:07.957Z
kaya3
<p>When TypeScript needs variable names to not conflict, it suffixes variables of otherwise identical names with <code>_1</code>, <code>_2</code>, etc. You could have <code>c_1</code> and <code>c_2</code> in your example code above.</p>
<p>For global variables, Python at least has the keywords <code>nonlocal</code> and <code>global</code>. I've seen Python code before like</p>
<pre class="lang-py prettyprint-override"><code>def frobnicate():
  global foo
  global bar
  global baz
  global qux
  # ... it went on for a while.
</code></pre>
<p>Though I imagine that's not common in idiomatic code.</p>
<p>So, your example in the question would become:</p>
<pre class="lang-py prettyprint-override"><code>b = 2
def a():
  global b
  b = b + 1
  c_1 = None # Since it starts as `undefined` in the JS, and `None` is arguably
             # the best translation of that
  while c_1 &gt; b:
    c_2 = None
    c_2 = c_2 - 1
    b = b - c_2
</code></pre>

CC BY-SA 4.0
2023-06-27T20:33:35.087Z
2023-06-27T20:48:51.233Z
2023-06-27T20:48:51.233Z
Bbrk24
CC BY-SA 4.0
2023-06-27T20:35:21.240Z
FYI you can do `global foo, bar, baz, qux` all on one line if you wanted to. It would also apply to the whole scope so the extra `global b` is indeed unnecessary.
mousetail 'he-him'
CC BY-SA 4.0
2023-06-27T21:01:02.677Z
+1 for renaming, and I think `nonlocal` might be more appropriate here instead of `global`.
BoppreH
CC BY-SA 4.0
2023-06-28T10:48:12.657Z
Note that `b = b+1` and `b += 1` are not equivalent in python. In fact you wouldn't need `global b` if you only updated `b` using `+=` and never `=`.
Stef
CC BY-SA 4.0
2023-06-28T11:47:01.133Z
@Stef To be honest, I couldn’t remember whether Python even had `+=` to begin with. Like I said, I don’t Python much.
Bbrk24
CC BY-SA 4.0
2023-06-28T11:50:50.510Z
@Bbrk24 It does. But `b += 1` is not a synonym for `b = b + 1`. When you do `b = ...` you're binding a value to a local name `b`, regardless of whether there is already something else named `b`. But when you do `b += ...`, you're updating the object bound to the already-existing name `b`, which might be less local.
Stef
CC BY-SA 4.0
2023-06-28T14:07:49.790Z
Actually, you would still need `global b` if you only updated `b` using `+=`.
`b = 2
def a():
    b += 1` 
still raises `UnboundLocalError` when `a` is called.
MarcellPerger
# How to transpile between languages with different scoping rules?
Posted by: username_0 on 2023-06-27
Suppose I have a block scoped language, in this case represented
let b=2;

function a() {
    b+=1;
    let c;
    while (c>b) {
        let c;
        c-=1;
        b-=c;
    }
}

How can I transpile this into something like python where variables are function scoped?
Ideally I'd want to output something vaguely readable and not mangle the variable names too much.
Note that some variables now alias, like c, some need their scope expanded like b and some reduced like c. Ideally I'd have some generic system that could handle arbitrary scopes no matter what the rules of the source language are.
Both languages are dynamically typed.
**Tags:** python transpilers
> **Comments:**
> **username_1**: Lexically scoped languages cannot emulate dynamically scoped languages.  
> **username_2**: @Aster they surely can, at a price of replacing every potentially dynamically scoped variable reference with a global hash table lookup.  
---
## 2 answers
### Answer by username_4 on 2023-06-27. Score: 8
When TypeScript needs variable names to not conflict, it suffixes variables of otherwise identical names with _1, _2, etc. You could have c_1 and c_2 in your example code above.
For global variables, Python at least has the keywords nonlocal and global. I've seen Python code before like
def frobnicate():
  global foo
  global bar
  global baz
  global qux
  # ... it went on for a while.

Though I imagine that's not common in idiomatic code.
So, your example in the question would become:
b = 2
def a():
  global b
  b = b + 1
  c_1 = None # Since it starts as `undefined` in the JS, and `None` is arguably
             # the best translation of that
  while c_1 > b:
    c_2 = None
    c_2 = c_2 - 1
    b = b - c_2
> **Comments:**
> **username_0** (2023-06-27): FYI you can do `global foo, bar, baz, qux` all on one line if you wanted to. It would also apply to the whole scope so the extra `global b` is indeed unnecessary.  
> **username_5** (2023-06-27): +1 for renaming, and I think `nonlocal` might be more appropriate here instead of `global`.  
> **username_6** (2023-06-28): Note that `b = b+1` and `b += 1` are not equivalent in python. In fact you wouldn't need `global b` if you only updated `b` using `+=` and never `=`.  
> **username_4** (2023-06-28): @Stef To be honest, I couldn’t remember whether Python even had `+=` to begin with. Like I said, I don’t Python much.  
> **username_6** (2023-06-28): @Bbrk24 It does. But `b += 1` is not a synonym for `b = b + 1`. When you do `b = ...` you're binding a value to a local name `b`, regardless of whether there is already something else named `b`. But when you do `b += ...`, you're updating the object bound to the already-existing name `b`, which might be less local.  
> **username_7** (2023-06-28): Actually, you would still need `global b` if you only updated `b` using `+=`.
`b = 2
def a():
    b += 1` 
still raises `UnboundLocalError` when `a` is called.  
---
### Answer by username_3 on 2023-06-27. Score: 5
The scope of a variable can be expanded by moving its declaration further out; to translate between block-scoped and function-scoped variables, you need to make sure the declaration is at the top of the function. This may mean that two variables which had the same name in the source program may end up having the same scope, and one must be renamed. Unfortunately there is no way around this, so even if you don't want to "mangle the variable names too much" you will still have to mangle them slightly. It's up to you what kind of mangling you decide to do; I like to append numbers starting from 2, so c, c2, c3 and so on:
function a() {
    let c, c2;
    // ...
}

The other thing you need to take care of is when the source and target languages have different rules for reassigning non-local variables. Some languages (e.g. Javascript) just allow this, others (e.g. Python) require you to declare which non-local variables as global or nonlocal if you want to reassign them, while others still (e.g. Java) may outright forbid reassigning captured variables even when the assignment occurs locally.
To get around this, you can wrap the variable in a mutable container:
let b = {value: 2};

function a() {
    b.value += 1;
    // ...
}

This works by replacing variable accesses with field accesses, and variable assignments with field assignments. Most imperative languages support both in some way.
---
