What's wrong
BinaryOperator.Divide and BinaryOperator.Modulo are spelled / and % for every target: PythonGenerator.GetOperatorSpelling (Coder/Languages/PythonGenerator.cs:803-808) and JavaScriptGenerator.cs:554-558 use them unchanged. The project treats int / int as truncating integer division; FloatingPointLiteralTests exists because 1 / 2 is integer division in C, C++ and Go. But Python's / and JavaScript's / are true division, and Python's % floors. So the same AST computes different values depending on the target language.
Repro
FunctionDeclaration d = new("half") { ReturnType = "int" };
d.Body.Add(new ReturnStatement(new BinaryExpression(
new LiteralExpression<int>(-7), BinaryOperator.Divide, new LiteralExpression<int>(2))));
Every generator emits return (-7 / 2). Running the emitted code:
| Target |
half() returns |
| C, C++, C#, Go, Rust (checked with rustc) |
-3 |
| Python (python3) |
-3.5, a float from a function annotated -> int |
| JavaScript (node) |
-3.5 |
Modulo also differs: Python evaluates -7 % 2 to 1, where the C family gives -1.
Why it matters
The whole purpose of the tool is that one AST means the same thing in every target. Arithmetic that silently changes value, and in Python's case changes type, is hard to spot in generated code and breaks anything that uses the result, such as indexing or loop bounds.
Suggested fix / acceptance criteria
- When both operands are statically integers (integer literals and integer-typed variables or parameters, where the type is known), emit truncating division:
int(a / b) or math.trunc(a / b) in Python, and Math.trunc(a / b) in JavaScript. Don't use Python's //, because it floors: -7 // 2 == -4.
- For integer modulo in Python, emit
math.fmod(a, b) cast to int, or a - b * int(a / b).
- If operand types are unknown, document the difference. A generator-level comment would also work.
- Add tests with negative operands for
Divide and Modulo in the Python and JavaScript generators.
What's wrong
BinaryOperator.DivideandBinaryOperator.Moduloare spelled/and%for every target:PythonGenerator.GetOperatorSpelling(Coder/Languages/PythonGenerator.cs:803-808) andJavaScriptGenerator.cs:554-558use them unchanged. The project treatsint / intas truncating integer division;FloatingPointLiteralTestsexists because1 / 2is integer division in C, C++ and Go. But Python's/and JavaScript's/are true division, and Python's%floors. So the same AST computes different values depending on the target language.Repro
Every generator emits
return (-7 / 2). Running the emitted code:half()returns-> intModulo also differs: Python evaluates
-7 % 2to1, where the C family gives-1.Why it matters
The whole purpose of the tool is that one AST means the same thing in every target. Arithmetic that silently changes value, and in Python's case changes type, is hard to spot in generated code and breaks anything that uses the result, such as indexing or loop bounds.
Suggested fix / acceptance criteria
int(a / b)ormath.trunc(a / b)in Python, andMath.trunc(a / b)in JavaScript. Don't use Python's//, because it floors:-7 // 2 == -4.math.fmod(a, b)cast toint, ora - b * int(a / b).DivideandModuloin the Python and JavaScript generators.