mirror of
https://github.com/samsonjs/csc360-a1-shell.git
synced 2026-03-25 08:45:52 +00:00
Modernize parser and shell code with Ruby 4 features
This commit is contained in:
parent
9630125a95
commit
850b2c23e2
4 changed files with 37 additions and 38 deletions
|
|
@ -60,9 +60,10 @@ module Shell
|
|||
def builtin_cd(args)
|
||||
dir = args.first
|
||||
oldpwd = Dir.pwd
|
||||
target = if dir.nil?
|
||||
target = case dir
|
||||
in nil
|
||||
Dir.home
|
||||
elsif dir == "-"
|
||||
in "-"
|
||||
ENV["OLDPWD"] || oldpwd
|
||||
else
|
||||
dir
|
||||
|
|
@ -85,7 +86,7 @@ module Shell
|
|||
logger.warn "#{red("[ERROR]")} Invalid export command"
|
||||
return -1
|
||||
else
|
||||
ENV[name] = value_parts.join("=").gsub(EXPORT_VARIABLE_PATTERN) { |m| ENV[m[1..]] || "" }
|
||||
ENV[name] = value_parts.join("=").gsub(EXPORT_VARIABLE_PATTERN) { ENV[it[1..]] || "" }
|
||||
end
|
||||
0
|
||||
end
|
||||
|
|
|
|||
|
|
@ -54,19 +54,24 @@ module Shell
|
|||
commands = parse_line(line)
|
||||
result = 0
|
||||
commands.each do |entry|
|
||||
command = entry[:command]
|
||||
next if command.strip.empty?
|
||||
next if entry[:op] == :and && result != 0
|
||||
case entry
|
||||
in StringParser::Command[text:, op:]
|
||||
command = text
|
||||
next if command.strip.empty?
|
||||
next if op == :and && result != 0
|
||||
|
||||
args = word_expander.expand(command)
|
||||
program = args.shift
|
||||
logger.verbose "Parsed command: #{program} #{args.inspect}"
|
||||
if builtins.builtin?(program)
|
||||
logger.verbose "Executing builtin #{program}"
|
||||
result = builtins.exec(program, args)
|
||||
args = word_expander.expand(command)
|
||||
program = args.shift
|
||||
logger.verbose "Parsed command: #{program} #{args.inspect}"
|
||||
if builtins.builtin?(program)
|
||||
logger.verbose "Executing builtin #{program}"
|
||||
result = builtins.exec(program, args)
|
||||
else
|
||||
logger.verbose "Shelling out for #{program}"
|
||||
result = job_control.exec_command(program, args)
|
||||
end
|
||||
else
|
||||
logger.verbose "Shelling out for #{program}"
|
||||
result = job_control.exec_command(program, args)
|
||||
raise ArgumentError, "Unknown parsed command node: #{entry.inspect}"
|
||||
end
|
||||
end
|
||||
result
|
||||
|
|
@ -76,12 +81,8 @@ module Shell
|
|||
end
|
||||
|
||||
# Looks like this: /path/to/somewhere%
|
||||
def prompt(pwd)
|
||||
"#{blue(pwd)}#{white("%")} #{CLEAR}"
|
||||
end
|
||||
def prompt(pwd) = "#{blue(pwd)}#{white("%")} #{CLEAR}"
|
||||
|
||||
def parse_line(line)
|
||||
StringParser.split_commands(line)
|
||||
end
|
||||
def parse_line(line) = StringParser.split_commands(line)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
module Shell
|
||||
class StringParser
|
||||
Command = Data.define(:text, :op)
|
||||
Token = Data.define(:type, :value)
|
||||
|
||||
class Scanner
|
||||
|
|
@ -336,22 +337,20 @@ module Shell
|
|||
tokens = Scanner.new(line).tokenize_command_list
|
||||
|
||||
tokens.each do |token|
|
||||
case token.type
|
||||
when :text
|
||||
commands << {command: token.value, op: next_op}
|
||||
if next_op == :and && token.value.strip.empty?
|
||||
case token
|
||||
in Token[type: :text, value:]
|
||||
if next_op == :and && value.strip.empty?
|
||||
raise ArgumentError, "syntax error: expected command after `&&`"
|
||||
end
|
||||
commands << Command.new(text: value, op: next_op)
|
||||
next_op = :always
|
||||
when :separator
|
||||
if token.value == :and
|
||||
if commands.empty? || commands.last[:command].strip.empty?
|
||||
raise ArgumentError, "syntax error near unexpected token `&&`"
|
||||
end
|
||||
next_op = :and
|
||||
else
|
||||
next_op = :always
|
||||
in Token[type: :separator, value: :and]
|
||||
if commands.empty? || commands.last.text.strip.empty?
|
||||
raise ArgumentError, "syntax error near unexpected token `&&`"
|
||||
end
|
||||
next_op = :and
|
||||
in Token[type: :separator, value: :always]
|
||||
next_op = :always
|
||||
else
|
||||
raise ArgumentError, "Unknown token type: #{token.type}"
|
||||
end
|
||||
|
|
@ -360,9 +359,7 @@ module Shell
|
|||
commands
|
||||
end
|
||||
|
||||
def read_dollar_paren(line, start_index)
|
||||
Scanner.new(line, index: start_index).read_dollar_paren_body
|
||||
end
|
||||
def read_dollar_paren(line, start_index) = Scanner.new(line, index: start_index).read_dollar_paren_body
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ module Shell
|
|||
expanded = expand_variables(word.text)
|
||||
.tr(ESCAPED_DOLLAR, "$")
|
||||
.tr(ESCAPED_BACKTICK, "`")
|
||||
expand_braces(expanded).map { |part| SplitWord.new(text: part, globbed: word.globbed) }
|
||||
expand_braces(expanded).map { SplitWord.new(text: it, globbed: word.globbed) }
|
||||
end
|
||||
.flat_map do |word|
|
||||
if word.globbed
|
||||
|
|
@ -116,7 +116,7 @@ module Shell
|
|||
if glob_words.empty?
|
||||
words << SplitWord.new(text: field, globbed: false)
|
||||
else
|
||||
glob_words.each { |glob_word| words << SplitWord.new(text: glob_word, globbed: true) }
|
||||
glob_words.each { words << SplitWord.new(text: it, globbed: true) }
|
||||
end
|
||||
else
|
||||
words << SplitWord.new(text: field, globbed: false)
|
||||
|
|
@ -535,7 +535,7 @@ module Shell
|
|||
return [word] unless body.include?(",")
|
||||
|
||||
parts = body.split(",", -1)
|
||||
parts.flat_map { |part| expand_braces(prefix + part + suffix) }
|
||||
parts.flat_map { expand_braces(prefix + it + suffix) }
|
||||
end
|
||||
|
||||
def escaped_replacement(char)
|
||||
|
|
|
|||
Loading…
Reference in a new issue