Skip to content

feature: phase 2 implemented#14

Merged
Charliechen114514 merged 21 commits into
mainfrom
feat/phase2-core-deepen
Jun 28, 2026
Merged

feature: phase 2 implemented#14
Charliechen114514 merged 21 commits into
mainfrom
feat/phase2-core-deepen

Conversation

@Charliechen114514

Copy link
Copy Markdown
Member

No description provided.

- new -a/--archive: -r + preserve mode/owner/time, copy symlinks as links
- link-aware lstat-driven tree walk never follows symlinks (TOCTOU-safe)
- fix -p preserving only mode: now also sets owner + atime/mtime
- add fs::lstat and fs::set_times (utimensat, AT_SYMLINK_NOFOLLOW)
- directory attrs applied last so child writes don't reset dir mtime
- fs_util.hpp: include <vector> (was relying on transitive include)
- integer operands validated via from_chars (abc -eq abc now exits 2)
- recursive-descent parser: -o/-a/!/( ) with correct precedence
- arity/syntax errors unified to exit 2 (bare -z, unknown -op, stray paren)
- add -h/-b/-c/-p/-S file tests, -nt/-ot/-ef file comparisons, string < >
- HELP.extra synced
- -R/--recursive: GNU-style blocks with 'path:' headers, blank-line separated
- --color[=always|auto|never]: type-based ANSI colors (isatty gates auto)
- symlinked directories not descended into (cycle-safe)
- extract print_entry/collect_visible to dedup long/short/single-file paths
- fix format_permissions emitting a stray '-' before the type char
  (ls -l showed 'd-rwxr-xr-x' instead of 'drwxr-xr-x')
- -A/-B/-C NUM: trailing/leading/both context; -C sets A=B
- leading context via a bounded ring buffer, trailing via after_pending
- '--' separator between non-contiguous match groups
- context lines honor -n line numbers and multi-file path: prefix
- context disabled under -q/-l/-c (only counting/quiet apply)
- default path (no -A/-B/-C) byte-identical to before
- expression AST replaces flat AND chain: -a (implicit), -o, ! / -not, ( )
- recursive-descent parser with correct precedence (AND binds tighter than OR)
- -maxdepth hoisted to a global option; -exec stays an action leaf
- unknown primary / unbalanced paren / missing operand -> exit 1
- PATH vs expression disambiguation (leading '(' or '!' starts an expression)
- $((expr)) recursive-descent evaluator: + - * / %, comparisons, && || !,
  parens, integer literals, variables (bare or $VAR; unset/non-numeric -> 0)
- fix assignment RHS not being expanded (X=$((i+1)) now works; was stored raw)
- integration +5 arithmetic cases incl. a real counting while loop
- case WORD in PATTERN(|PATTERN)) body;; ... esac via CaseClause AST node
- lexer emits DSemi (;;) so case bodies terminate correctly
- patterns matched with fnmatch; * ? [ ] are pattern syntax, not filename globs
- add expand_noglob: expand param/arith/command without field-split/glob, for
  case words/patterns (fixes * matching cwd files instead of any string)
- integration +4 case cases: | alternation, * default, f* prefix, loop dispatch
- FuncDef AST node; name() { body; } parsed and registered in ShellState
- function calls run the body in-process with new positional params ($1..)
- return N sets a pending flag consumed at the call site, propagating through
  AndOr / while / for execution
- local declares function-scoped vars via a scope stack; get_var/set_var are
  scope-aware so locals do not leak to globals
- integration +4: definition+call, params, return status, local isolation
- lexer reads <<DELIM / <<-DELIM and collects the body up to the delimiter
  line (<<- strips leading tabs); body carried by the DLess/DLessDash token
- parser maps it to Redir::HereDoc; executor writes the body to a temp file
  and redirects stdin from it
- unquoted here-doc bodies expand param/arith/command via expand_noglob
- constraint: <<DELIM ends the command line (the common form)
- integration +3: plain body, var expansion, arithmetic expansion
- ${#VAR} length
- ${VAR#pat} / ${VAR##pat} strip shortest/longest matching prefix
- ${VAR%pat} / ${VAR%%pat} strip shortest/longest matching suffix
- ${VAR:-def} default, ${VAR:+alt} alternative
- glob prefix/suffix matching via fnmatch over increasing lengths
- integration +5 incl. the ${P##*/} basename idiom
- break N / continue: ShellState break_depth counts enclosing loops; the
  AndOr executor stops on pending break/continue so loop bodies abort early
- add break/continue builtins (were missing entirely — loop flags were never
  set, so break/continue silently did nothing)
- fix parse_compound_list corrupting a trailing && / || when merging across ';':
  it rewrote the last entry's operator to Semi, so 'false && echo M; echo X'
  wrongly ran echo M. Entries are now concatenated unchanged.
- integration +3: break, continue, break 2 across nested loops
- read -p PROMPT writes the prompt to stderr before reading
- read -r recognized (raw mode; backslashes already preserved)
- fix the last variable receiving a leading IFS char ('echo a b c | read x y z'
  now yields z='c', not ' c')
- integration +3: single/multi-var read, -p prompt
- ShellState holds a sig->command trap table; builtin_trap parses names
  (EXIT/INT/TERM/.../numeric), installs a handler that records the pending
  signal, or clears with 'trap - SIG'
- the AndOr executor runs the trap command at the next safe point; run_string
  and run_interactive run the EXIT trap before returning
- make every waitpid retry on EINTR so a signal-fired trap doesn't corrupt
  child-status retrieval
- integration +2: EXIT trap fires on exit, 'trap - EXIT' clears it
@Charliechen114514 Charliechen114514 merged commit f37fca4 into main Jun 28, 2026
8 checks passed
@Charliechen114514 Charliechen114514 deleted the feat/phase2-core-deepen branch June 28, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant