amber-lang / amber-lang/bash2amber
[Detail Bug] bash2amber: Standalone `ls`/`pwd`/`lines` commands are converted into silent Amber function calls
- Ngôn ngữ chính
- Rust
- Star
- 2
- Fork
- 0
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Mô tả
# Summary
- **Context**: The `src/amber/builtins/mod.rs` file acts as a dispatcher that identifies Bash commands and converts them into Amber built-in functions.
- **Bug**: The `render_builtin` function incorrectly includes `ls`, `pwd`, and `lines`, which are expression-oriented functions in Amber that return values but do not print to stdout.
- **Actual vs. expected**: Standalone Bash commands like `ls` or `pwd` are converted to silent Amber function calls (e.g., `trust ls()`) instead of being rendered as Bash literal commands (e.g., `$ ls $`), which would correctly print to stdout.
- **Impact**: Converted scripts will produce no output for `ls` and `pwd` commands, breaking fundamental Bash behavior. Additionally, the current implementation often generates type-invalid Amber code (e.g., `ls(true)` instead of `ls(".", true)`).
# Code with bug
```rust
pub(crate) fn render_builtin(simple: &SimpleCommand, ctx: &RenderContext) -> Option {
let name = simple.words.first()?;
match name.as_str() {
"cd" => cd::render(simple, ctx),
"clear" => clear::render(simple, ctx),
"cp" => cp::render(simple, ctx),
"exit" => exit::render(simple, ctx),
"ls" => ls::render(simple, ctx), // <-- BUG 🔴 Intercepts standalone 'ls' and makes it silent
"mv" => mv::render(simple, ctx),
"pwd" => pwd::render(simple, ctx), // <-- BUG 🔴 Intercepts standalone 'pwd' and makes it silent
"rm" => rm::render(simple, ctx),
"sleep" => sleep::render(simple, ctx),
"touch" => touch::render(simple, ctx),
"lines" => lines::render(simple, ctx), // <-- BUG 🔴 Intercepts standalone 'lines' and makes it silent
_ => None,
}
}
```
# Evidence
- **Amber Builtin Implementation**: The implementation of `ls` in `analysis/amber/builtin/ls.rs` shows that it reads the directory listing into an internal array variable (`__ls`) and returns that array. It does not print to stdout.
- **Bash vs. Amber Behavior**: In Bash, `ls` is a command used primarily for its output. In Amber, `ls()` is a function that returns an array. By intercepting `ls` in `render_builtin` (used for standalone statements), `bash2amber` replaces a printing command with a silent function call.
- **Failed Execution**: A converted script containing `ls` will produce no output. For example, `tests/bash/builtin_ls_pwd.sh` contains `ls`, and it is converted to `trust ls()` in `tests/amber/builtin_ls_pwd.ab`. Because the test is marked `### No execute`, it passes string comparison but the generated code is behaviorally broken.
- **Type Errors**: The `ls::render` logic often omits required positional arguments. For example, `ls -a` becomes `trust ls(true)`, where `true` (a boolean) is passed as the first argument (`path`), which expects a `Text` type in Amber. This results in code that fails to compile in Amber.
# Why has this bug gone undetected?
The project's test suite uses "No execute" tests for builtins, which only verify that the generated Amber code matches an expected string. Since the expected strings in the tests (like `trust ls()`) already incorporate the bug, the tests pass. Furthermore, the builtins work correctly when used in command substitutions (e.g., `x=$(ls)`), which is handled by `render_builtin_expr`, masking the issue for the most common use cases.
# Recommended fix
Remove `ls`, `pwd`, and `lines` from the `render_builtin` match block. They should only remain in `render_builtin_expr` so they are intercepted only when their return value is actually being used. When used as standalone statements, they should fall back to standard Bash command execution to preserve their output-printing behavior.
```rust
pub(crate) fn render_builtin(simple: &SimpleCommand, ctx: &RenderContext) -> Option {
let name = simple.words.first()?;
match name.as_str() {
"cd" => cd::render(simple, ctx),
"clear" => clear::render(simple, ctx),
"cp" => cp::render(simple, ctx),
"exit" => exit::render(simple, ctx),
// "ls" => ls::render(simple, ctx), // <-- FIX 🟢
"mv" => mv::render(simple, ctx),
// "pwd" => pwd::render(simple, ctx), // <-- FIX 🟢
"rm" => rm::render(simple, ctx),
"sleep" => sleep::render(simple, ctx),
"touch" => touch::render(simple, ctx),
// "lines" => lines::render(simple, ctx), // <-- FIX 🟢
_ => None,
}
}
```
# History
This bug was introduced in commit cb1f758 (@Ph0enixKM, 2026-02-13). The commit introduced the builtin translation infrastructure, but incorrectly included expression-oriented commands like `ls`, `pwd`, and `lines` in the standalone statement dispatcher, causing them to execute silently without printing to stdout.
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Đánh giá
Issue này chưa được đánh giá.