Hi, thank you so much for this project! While using it, I've run into a small limitation.
unbash parses command substitutions as structured CommandExpansion nodes in normal shell-word contexts, but inside arithmetic they are currently flattened into opaque ArithmeticWord nodes.
Problem
In arithmetic contexts such as:
$(( $(cmd) + 1 ))
(( $(cmd) + 1 ))
the embedded $(cmd) is preserved only as raw text inside ArithmeticWord.value, rather than being represented structurally in the arithmetic AST.
Repro
Arithmetic expansion
import { parse } from "unbash";
const ast = parse("echo $(( $(rm -rf /) + 1 ))");
console.log(JSON.stringify(ast, null, 2));
The arithmetic part is currently shaped like this:
{
"type": "ArithmeticExpansion",
"text": "$(( $(rm -rf /) + 1 ))",
"expression": {
"type": "ArithmeticBinary",
"operator": "+",
"left": {
"type": "ArithmeticWord",
"value": "$(rm -rf /)"
},
"right": {
"type": "ArithmeticWord",
"value": "1"
}
}
}
Arithmetic command
import { parse } from "unbash";
const ast = parse("(( $(rm -rf /) + 1 ))");
const cmd = ast.commands[0].command;
console.log(cmd.body);
console.log(cmd.expression);
Current behavior:
- top-level node is
ArithmeticCommand
body is " $(rm -rf /) + 1 "
expression is an ArithmeticBinary
expression.left is an ArithmeticWord with value: "$(rm -rf /)"
Why this matters
This makes arithmetic inconsistent with normal shell-word parsing, where command substitutions are exposed structurally and can be recursively analyzed.
For downstream consumers that walk the AST to inspect nested commands, arithmetic currently creates a blind spot and forces substring/reparse workarounds.
Expected behavior
Command substitutions inside arithmetic should ideally be represented structurally in the AST, rather than flattened into ArithmeticWord.
From reading the source, this appears to come from src/arithmetic.ts, where readDollarAtom() currently treats $(...) as an ArithmeticWord.
I’d be happy to help with a PR if this sounds like a change you’d be open to.
Hi, thank you so much for this project! While using it, I've run into a small limitation.
unbashparses command substitutions as structuredCommandExpansionnodes in normal shell-word contexts, but inside arithmetic they are currently flattened into opaqueArithmeticWordnodes.Problem
In arithmetic contexts such as:
$(( $(cmd) + 1 ))(( $(cmd) + 1 ))the embedded
$(cmd)is preserved only as raw text insideArithmeticWord.value, rather than being represented structurally in the arithmetic AST.Repro
Arithmetic expansion
The arithmetic part is currently shaped like this:
{ "type": "ArithmeticExpansion", "text": "$(( $(rm -rf /) + 1 ))", "expression": { "type": "ArithmeticBinary", "operator": "+", "left": { "type": "ArithmeticWord", "value": "$(rm -rf /)" }, "right": { "type": "ArithmeticWord", "value": "1" } } }Arithmetic command
Current behavior:
ArithmeticCommandbodyis" $(rm -rf /) + 1 "expressionis anArithmeticBinaryexpression.leftis anArithmeticWordwithvalue: "$(rm -rf /)"Why this matters
This makes arithmetic inconsistent with normal shell-word parsing, where command substitutions are exposed structurally and can be recursively analyzed.
For downstream consumers that walk the AST to inspect nested commands, arithmetic currently creates a blind spot and forces substring/reparse workarounds.
Expected behavior
Command substitutions inside arithmetic should ideally be represented structurally in the AST, rather than flattened into
ArithmeticWord.From reading the source, this appears to come from
src/arithmetic.ts, wherereadDollarAtom()currently treats$(...)as anArithmeticWord.I’d be happy to help with a PR if this sounds like a change you’d be open to.