amber-lang / amber-lang/bash2amber

[Detail Bug] bash2amber: Standalone `ls`/`pwd`/`lines` commands are converted into silent Amber function calls

オープン
#5 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
bug detail
主要言語
Rust
スター
2
フォーク
0
PR マージ指標
30日以内にマージされた PR はありません

説明

# 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.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。