Track all reported bugs, their status, and resolutions for the Neutron programming language.
This page documents all reported bugs in the Neutron programming language, including their status, discovery details, and resolutions.
Sunday, November 3, 2025 — Linux — Neutron-1.2.1-beta
Sunday, November 3, 2025 — Neutron-1.2.1
Two-part issue in stack management during function returns:
OP_RETURN resized the stack to return_slot_offset which pointed to the first argument, leaving the callee (function object) on the stack. This caused recursive calls to return the function object instead of the computed value.When a function called itself recursively, the return value was a function object (e.g., ) instead of the computed numeric value. This made all recursive algorithms impossible to implement. Example:
fun factorial(n) {
if (n <= 1) {
return 1;
}
var sub_result = factorial(n - 1); // Returns instead of number
return n * sub_result; // RuntimeError: Operands must be numbers
}
After the initial fix for regular functions, calling methods on objects within loops caused segfaults:
var i = 0;
while (i < 10) {
var p = Person();
p.initialize("Name"); // Segfault - stack corruption
i = i + 1;
}
1. **Added isBoundMethod flag to CallFrame** (include/vm.h):
false by default in CallFrame constructorsrc/vm.cpp line ~227):
frame->isBoundMethod = true when calling bound methods in VM::callValue()falsesrc/vm.cpp line ~549):
stack.resize(return_slot_offset) - keeps everything before receiverstack.resize(return_slot_offset - 1) - removes callee + argumentsreturn_slot_offset == 0 caseRegular Function Call:
Before: [outer_vars | callee | arg1 | arg2]
^slot_offset points to arg1
After: [outer_vars | result]
Resize to (slot_offset - 1) to remove callee
Bound Method Call:
Before: [outer_vars | receiver | arg1 | arg2]
^slot_offset points to receiver (acts as arg0)
After: [outer_vars | result]
Resize to (slot_offset) to keep outer_vars intact
Sunday, November 3, 2025 — Linux — Neutron-1.2.1-beta
Sunday, November 3, 2025 — Neutron-1.2.1
The compiler emitted bytecode with line number 0 (hardcoded placeholder) instead of actual line numbers from the source code. This was because Compiler::emitByte() used chunk->write(byte, 0) instead of tracking and passing the current line number.
Runtime errors did not display line numbers in error messages. When errors occurred, users saw messages like "RuntimeError in file.nt: Division by zero." without any indication of which line caused the problem. The error handler tried to display line numbers using frame->currentLine, but this was always -1 because the VM never updated it from the bytecode. The bytecode itself contained line 0 for all instructions because the compiler never tracked source line numbers.
1. Added int currentLine field to the Compiler class to track the current source line being compiled
2. Initialized currentLine = 1 in Compiler constructors
3. Updated Compiler::emitByte() to use chunk->write(byte, currentLine) instead of chunk->write(byte, 0)
4. Updated key visitor methods (visitBinaryExpr, visitUnaryExpr, visitVariableExpr, visitVarStmt) to extract line numbers from Token fields and update currentLine
5. Modified VM::run() to read line numbers from chunk->lines[] array before each instruction and update frame->currentLine
6. Fixed 43 runtime error calls to pass frame->currentLine instead of -1
All runtime errors now display accurate line numbers with source code context. Example output:
RuntimeError in /tmp/test.nt at line 8:
Division by zero.
8 | var z = x / y; // Should show line 8 in error
Stack trace:
at