mirror of
https://github.com/samsonjs/csc360-a1-shell.git
synced 2026-03-25 08:45:52 +00:00
Replace Ruby's old wordexp-like command splitting with a tokenizer and
parser that understands ; and && while honoring quotes and nesting.
Implement richer expansions for command substitution, arithmetic,
parameter defaults (${var:-...}), brace expansion, and escaped
dollar/backtick behavior via shared quote-state handling.
Expand the test suite with parser/expansion edge cases, escaping
parity checks, builtin usage validation, and job-control refresh tests.
Keep C green by adding a compat test profile for c/Makefile test and
by returning nonzero on builtin failures in -c mode, including clearer
`bg` usage output.
64 lines
1.4 KiB
Ruby
64 lines
1.4 KiB
Ruby
module Shell
|
|
# Shared quote/escape state machine for parsers that walk shell-like strings.
|
|
class QuoteCursor
|
|
attr_reader :state
|
|
|
|
def initialize(state: :unquoted)
|
|
@state = state
|
|
end
|
|
|
|
def unquoted?
|
|
state == :unquoted
|
|
end
|
|
|
|
# Consumes one logical unit from line[index], which may be one character
|
|
# or an escape pair (e.g., \" or \\$), and updates internal quote state.
|
|
# Returns [segment, next_index].
|
|
def consume(line, index)
|
|
c = line[index]
|
|
|
|
case state
|
|
when :unquoted
|
|
consume_unquoted(line, index, c)
|
|
when :single_quoted
|
|
consume_single_quoted(index, c)
|
|
when :double_quoted
|
|
consume_double_quoted(line, index, c)
|
|
else
|
|
raise "Unknown state #{state}"
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def consume_unquoted(line, index, c)
|
|
case c
|
|
when "'"
|
|
@state = :single_quoted
|
|
when "\""
|
|
@state = :double_quoted
|
|
when "\\"
|
|
if index + 1 < line.length
|
|
return [line[index, 2], index + 2]
|
|
end
|
|
end
|
|
[c, index + 1]
|
|
end
|
|
|
|
def consume_single_quoted(index, c)
|
|
@state = :unquoted if c == "'"
|
|
[c, index + 1]
|
|
end
|
|
|
|
def consume_double_quoted(line, index, c)
|
|
if c == "\\"
|
|
if index + 1 < line.length
|
|
return [line[index, 2], index + 2]
|
|
end
|
|
elsif c == "\""
|
|
@state = :unquoted
|
|
end
|
|
[c, index + 1]
|
|
end
|
|
end
|
|
end
|