yap-shell-parser 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/yap/shell/parser/grammar.y +14 -14
- data/lib/yap/shell/parser/lexer.rb +39 -9
- data/lib/yap/shell/parser/nodes.rb +25 -30
- data/lib/yap/shell/parser/version.rb +1 -1
- data/lib/yap/shell/parser_impl.rb +14 -14
- data/spec/yap/shell/lexer_spec.rb +124 -24
- data/spec/yap/shell/parser_spec.rb +3 -0
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 59dc1f16d41d54f7c14d7ff68abc1ad404d7bd39
         | 
| 4 | 
            +
              data.tar.gz: 95d1cfdfbe7ad7e35b6cc2e4be77a3cba9326a26
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0f324a8808805a0f4d64c0f63248040639e4dd06c48e6e818341fc6d1a895eee6330a71f4db3d1d3def9f12f6cf00605bc863b1c75d8003aa45f023678db1ee4
         | 
| 7 | 
            +
              data.tar.gz: b7a672e1cfabd50b07871b2f67f8042349cbd367cd53e1d8d3eafd23eaad7655c254f10484c5824893152e3be1711759e67cd07efe8a47aa3e7381ba0b8f3e5c
         | 
| @@ -29,18 +29,18 @@ stmts : stmts Separator stmt | |
| 29 29 | 
             
              | range_stmt
         | 
| 30 30 |  | 
| 31 31 | 
             
            stmt : stmt Conditional pipeline
         | 
| 32 | 
            -
                { result = ConditionalNode.new(val[1] | 
| 32 | 
            +
                { result = ConditionalNode.new(val[1], val[0], val[2]) }
         | 
| 33 33 | 
             
              | pipeline
         | 
| 34 34 | 
             
              | block_stmt
         | 
| 35 35 |  | 
| 36 36 | 
             
            block_stmt : range_stmt BlockBegin stmts BlockEnd
         | 
| 37 37 | 
             
                { result = val[0].tap { |range_node| range_node.tail = BlockNode.new(nil, val[2]) } }
         | 
| 38 38 | 
             
              | range_stmt BlockBegin BlockParams stmts BlockEnd
         | 
| 39 | 
            -
                { result = val[0].tap { |range_node| range_node.tail = BlockNode.new(nil, val[3], params: val[2] | 
| 39 | 
            +
                { result = val[0].tap { |range_node| range_node.tail = BlockNode.new(nil, val[3], params: val[2]) } }
         | 
| 40 40 | 
             
              | stmt BlockBegin stmts BlockEnd
         | 
| 41 41 | 
             
                { result = BlockNode.new(val[0], val[2]) }
         | 
| 42 42 | 
             
              | stmt BlockBegin BlockParams stmts BlockEnd
         | 
| 43 | 
            -
                { result = BlockNode.new(val[0], val[3], params: val[2] | 
| 43 | 
            +
                { result = BlockNode.new(val[0], val[3], params: val[2]) }
         | 
| 44 44 |  | 
| 45 45 | 
             
            range_stmt : Range
         | 
| 46 46 | 
             
                { result = RangeNode.new(val[0]) }
         | 
| @@ -74,10 +74,10 @@ command_w_heredoc : command_w_redirects Heredoc | |
| 74 74 | 
             
                { val[0].heredoc = val[1] ; result = val[0] }
         | 
| 75 75 | 
             
              | command_w_redirects
         | 
| 76 76 | 
             
              | Redirection
         | 
| 77 | 
            -
                { result = RedirectionNode.new(val[0] | 
| 77 | 
            +
                { result = RedirectionNode.new(val[0]) }
         | 
| 78 78 |  | 
| 79 79 | 
             
            command_w_redirects : command_w_redirects Redirection
         | 
| 80 | 
            -
                { val[0].redirects << RedirectionNode.new(val[1] | 
| 80 | 
            +
                { val[0].redirects << RedirectionNode.new(val[1]) ; result = val[0] }
         | 
| 81 81 | 
             
              | command_w_vars
         | 
| 82 82 | 
             
              | command
         | 
| 83 83 | 
             
              | vars
         | 
| @@ -86,28 +86,28 @@ command_w_vars : vars command | |
| 86 86 | 
             
              { result = EnvWrapperNode.new(val[0], val[1]) }
         | 
| 87 87 |  | 
| 88 88 | 
             
            vars : vars LValue RValue
         | 
| 89 | 
            -
                { val[0].add_var(val[1] | 
| 89 | 
            +
                { val[0].add_var(val[1], ArgumentNode.new(val[2])) ; result = val[0] }
         | 
| 90 90 | 
             
              | LValue RValue
         | 
| 91 | 
            -
                { result = EnvNode.new(val[0] | 
| 91 | 
            +
                { result = EnvNode.new(val[0], ArgumentNode.new(val[1])) }
         | 
| 92 92 |  | 
| 93 93 | 
             
            command : command2
         | 
| 94 94 |  | 
| 95 95 | 
             
            command2: Command
         | 
| 96 | 
            -
                { result = CommandNode.new(val[0] | 
| 96 | 
            +
                { result = CommandNode.new(val[0]) }
         | 
| 97 97 | 
             
              | Command args
         | 
| 98 | 
            -
                { result = CommandNode.new(val[0] | 
| 98 | 
            +
                { result = CommandNode.new(val[0], val[1].flatten) }
         | 
| 99 99 | 
             
              | LiteralCommand
         | 
| 100 | 
            -
                { result = CommandNode.new(val[0] | 
| 100 | 
            +
                { result = CommandNode.new(val[0], literal:true) }
         | 
| 101 101 | 
             
              | LiteralCommand args
         | 
| 102 | 
            -
                { result = CommandNode.new(val[0] | 
| 102 | 
            +
                { result = CommandNode.new(val[0], val[1].flatten, literal:true) }
         | 
| 103 103 |  | 
| 104 104 | 
             
            args : Argument
         | 
| 105 | 
            -
                { result = [ArgumentNode.new(val[0] | 
| 105 | 
            +
                { result = [ArgumentNode.new(val[0])] }
         | 
| 106 106 | 
             
              | args Argument
         | 
| 107 | 
            -
                { result = [val[0], ArgumentNode.new(val[1] | 
| 107 | 
            +
                { result = [val[0], ArgumentNode.new(val[1])].flatten }
         | 
| 108 108 |  | 
| 109 109 | 
             
            internal_eval : InternalEval
         | 
| 110 | 
            -
                { result = InternalEvalNode.new(val[0] | 
| 110 | 
            +
                { result = InternalEvalNode.new(val[0]) }
         | 
| 111 111 |  | 
| 112 112 | 
             
            ---- header
         | 
| 113 113 | 
             
            if $0 ==__FILE__
         | 
| @@ -4,6 +4,8 @@ module Yap::Shell | |
| 4 4 | 
             
              class Parser::Lexer
         | 
| 5 5 | 
             
                class Error < ::StandardError ; end
         | 
| 6 6 | 
             
                class HeredocMissingEndDelimiter < Error ; end
         | 
| 7 | 
            +
                class LineContinuationFound < Error ; end
         | 
| 8 | 
            +
                class NonterminatedString < Error ; end
         | 
| 7 9 |  | 
| 8 10 | 
             
                class Token
         | 
| 9 11 | 
             
                  include Comparable
         | 
| @@ -54,7 +56,7 @@ module Yap::Shell | |
| 54 56 | 
             
                REDIRECTION2           = /\A((&>|<)\s*(#{ARG}))/
         | 
| 55 57 |  | 
| 56 58 | 
             
                NUMERIC_RANGE              = /\A\(((\d+)\.\.(\d+))\)(\.each)?/
         | 
| 57 | 
            -
                NUMERIC_RANGE_W_CALL | 
| 59 | 
            +
                NUMERIC_RANGE_W_CALL       = /\A\(((\d+)\.\.(\d+))\)(\.each)?\s*:\s*/
         | 
| 58 60 | 
             
                NUMERIC_RANGE_W_PARAM      = /\A(\((\d+)\.\.(\d+))\)\s+as\s+([A-z0-9,\s]+)\s*:\s*/
         | 
| 59 61 | 
             
                NUMERIC_REPETITION         = /\A((\d+)(\.times))/
         | 
| 60 62 | 
             
                NUMERIC_REPETITION_2       = /\A((\d+)(\.times))\s*:\s*/
         | 
| @@ -63,6 +65,8 @@ module Yap::Shell | |
| 63 65 | 
             
                BLOCK_BEGIN = /\A\s+(\{)\s*(?:\|\s*([A-z0-9,\s]+)\s*\|)?/
         | 
| 64 66 | 
             
                BLOCK_END = /\A\s+(\})\s*/
         | 
| 65 67 |  | 
| 68 | 
            +
                LINE_CONTINUATION = /.*\\\Z/
         | 
| 69 | 
            +
             | 
| 66 70 | 
             
                SPLIT_BLOCK_PARAMS_RGX = /\s*,\s*|\s*/
         | 
| 67 71 |  | 
| 68 72 | 
             
                # Loop over the given input and yield command substitutions. This yields
         | 
| @@ -99,7 +103,7 @@ module Yap::Shell | |
| 99 103 | 
             
                end
         | 
| 100 104 |  | 
| 101 105 | 
             
                def tokenize(str)
         | 
| 102 | 
            -
                  @ | 
| 106 | 
            +
                  @chunk = str
         | 
| 103 107 | 
             
                  @tokens = []
         | 
| 104 108 | 
             
                  @lineno = 0
         | 
| 105 109 | 
             
                  @looking_for_args = false
         | 
| @@ -111,6 +115,9 @@ module Yap::Shell | |
| 111 115 | 
             
                  last_position = -1
         | 
| 112 116 | 
             
                  process_next_chunk = -> { @chunk = str.slice(@current_position..-1) ; @chunk != "" }
         | 
| 113 117 |  | 
| 118 | 
            +
                  strip_line_continutations_before_newlines
         | 
| 119 | 
            +
                  line_continuation_token
         | 
| 120 | 
            +
             | 
| 114 121 | 
             
                  while process_next_chunk.call
         | 
| 115 122 | 
             
                    result =
         | 
| 116 123 | 
             
                      comment_token ||
         | 
| @@ -120,12 +127,12 @@ module Yap::Shell | |
| 120 127 | 
             
                      subgroup_token ||
         | 
| 121 128 | 
             
                      assignment_token ||
         | 
| 122 129 | 
             
                      literal_command_token ||
         | 
| 130 | 
            +
                      string_token ||
         | 
| 123 131 | 
             
                      command_token ||
         | 
| 124 132 | 
             
                      whitespace_token ||
         | 
| 125 133 | 
             
                      terminator_token ||
         | 
| 126 134 | 
             
                      redirection_token ||
         | 
| 127 135 | 
             
                      heredoc_token ||
         | 
| 128 | 
            -
                      string_argument_token ||
         | 
| 129 136 | 
             
                      argument_token ||
         | 
| 130 137 | 
             
                      internal_eval_token
         | 
| 131 138 |  | 
| @@ -325,15 +332,16 @@ module Yap::Shell | |
| 325 332 | 
             
                    prev_char = ''
         | 
| 326 333 | 
             
                    loop do
         | 
| 327 334 | 
             
                      ch = @chunk[characters_read]
         | 
| 328 | 
            -
             | 
| 335 | 
            +
             | 
| 329 336 | 
             
                      if %w(' ").include?(ch)
         | 
| 337 | 
            +
                        @quoted_by = ch
         | 
| 330 338 | 
             
                        result = process_string @chunk[characters_read..-1], ch
         | 
| 331 339 | 
             
                        str << result.str
         | 
| 332 340 | 
             
                        characters_read += result.consumed_length
         | 
| 333 341 | 
             
                      elsif ch == '\\'
         | 
| 334 342 | 
             
                        # no-op
         | 
| 335 343 | 
             
                        characters_read += 1
         | 
| 336 | 
            -
                      elsif prev_char != '\\' && ch =~ /[\s\|;&\) | 
| 344 | 
            +
                      elsif prev_char != '\\' && ch =~ /[\s\|;&\(\)]/
         | 
| 337 345 | 
             
                        break
         | 
| 338 346 | 
             
                      else
         | 
| 339 347 | 
             
                        str << ch
         | 
| @@ -346,7 +354,11 @@ module Yap::Shell | |
| 346 354 | 
             
                    end
         | 
| 347 355 |  | 
| 348 356 | 
             
                    if characters_read > 0
         | 
| 349 | 
            -
                       | 
| 357 | 
            +
                      attrs = {}
         | 
| 358 | 
            +
                      if @quoted_by
         | 
| 359 | 
            +
                        attrs.merge!(quoted_by: @quoted_by)
         | 
| 360 | 
            +
                      end
         | 
| 361 | 
            +
                      token :Argument, str, attrs: attrs
         | 
| 350 362 | 
             
                      characters_read
         | 
| 351 363 | 
             
                    else
         | 
| 352 364 | 
             
                      nil
         | 
| @@ -363,7 +375,7 @@ module Yap::Shell | |
| 363 375 | 
             
                    @chunk = @chunk[i..-1]
         | 
| 364 376 | 
             
                    if %w(' ").include?(@chunk[0])
         | 
| 365 377 | 
             
                      result = process_string @chunk[0..-1], @chunk[0]
         | 
| 366 | 
            -
                      token :RValue, result.str
         | 
| 378 | 
            +
                      token :RValue, result.str, attrs: { quoted_by: @chunk[0] }
         | 
| 367 379 | 
             
                      consumed_length += result.consumed_length
         | 
| 368 380 | 
             
                    elsif md=@chunk.match(RH_VALUE)
         | 
| 369 381 | 
             
                      token :RValue, md[1]
         | 
| @@ -373,6 +385,19 @@ module Yap::Shell | |
| 373 385 | 
             
                  end
         | 
| 374 386 | 
             
                end
         | 
| 375 387 |  | 
| 388 | 
            +
                def line_continuation_token
         | 
| 389 | 
            +
                  if @chunk.match(LINE_CONTINUATION)
         | 
| 390 | 
            +
                    raise(
         | 
| 391 | 
            +
                      LineContinuationFound,
         | 
| 392 | 
            +
                      "Expected more input, line continutation found"
         | 
| 393 | 
            +
                    )
         | 
| 394 | 
            +
                  end
         | 
| 395 | 
            +
                end
         | 
| 396 | 
            +
             | 
| 397 | 
            +
                def strip_line_continutations_before_newlines
         | 
| 398 | 
            +
                  @chunk.gsub!(/\\\n/, '\\')
         | 
| 399 | 
            +
                end
         | 
| 400 | 
            +
             | 
| 376 401 | 
             
                def terminator_token
         | 
| 377 402 | 
             
                  if md=@chunk.match(CONDITIONAL_TERMINATOR)
         | 
| 378 403 | 
             
                    @looking_for_args = false
         | 
| @@ -390,10 +415,14 @@ module Yap::Shell | |
| 390 415 | 
             
                end
         | 
| 391 416 |  | 
| 392 417 | 
             
                # Matches single and double quoted strings
         | 
| 393 | 
            -
                def  | 
| 418 | 
            +
                def string_token
         | 
| 394 419 | 
             
                  if %w(' ").include?(@chunk[0])
         | 
| 395 420 | 
             
                    result = process_string @chunk[0..-1], @chunk[0]
         | 
| 396 | 
            -
                     | 
| 421 | 
            +
                    if @looking_for_args
         | 
| 422 | 
            +
                      token :Argument, result.str, attrs: { quoted_by: @chunk[0] }
         | 
| 423 | 
            +
                    else
         | 
| 424 | 
            +
                      token :Command, result.str
         | 
| 425 | 
            +
                    end
         | 
| 397 426 | 
             
                    return result.consumed_length
         | 
| 398 427 | 
             
                  end
         | 
| 399 428 | 
             
                end
         | 
| @@ -490,6 +519,7 @@ module Yap::Shell | |
| 490 519 |  | 
| 491 520 | 
             
                    if i >= input_str.length
         | 
| 492 521 | 
             
                      puts "#{' '*indent}C-yah: result:#{result_str.inspect}  length: #{input_str.length}"  if ENV["DEBUG"]
         | 
| 522 | 
            +
                      raise NonterminatedString, "Expected to find #{delimiter} in:\n  #{input_str}"
         | 
| 493 523 | 
             
                      return OpenStruct.new(str:result_str, consumed_length: input_str.length)
         | 
| 494 524 | 
             
                    end
         | 
| 495 525 |  | 
| @@ -19,26 +19,21 @@ module Yap::Shell | |
| 19 19 |  | 
| 20 20 | 
             
                  attr_reader :lvalue
         | 
| 21 21 |  | 
| 22 | 
            -
                  def initialize( | 
| 23 | 
            -
                    @lvalue =  | 
| 22 | 
            +
                  def initialize(token)
         | 
| 23 | 
            +
                    @lvalue = token.value
         | 
| 24 | 
            +
                    @attrs = token.attrs
         | 
| 24 25 | 
             
                  end
         | 
| 25 26 |  | 
| 26 | 
            -
                  def  | 
| 27 | 
            -
                     | 
| 27 | 
            +
                  def quoted?
         | 
| 28 | 
            +
                    double_quoted? || single_quoted?
         | 
| 28 29 | 
             
                  end
         | 
| 29 30 |  | 
| 30 | 
            -
                  def  | 
| 31 | 
            -
                    " | 
| 31 | 
            +
                  def double_quoted?
         | 
| 32 | 
            +
                    @attrs[:quoted_by] == '"'
         | 
| 32 33 | 
             
                  end
         | 
| 33 | 
            -
                end
         | 
| 34 34 |  | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
                  attr_reader :lvalue, :rvalue
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                  def initialize(lvalue, rvalue)
         | 
| 41 | 
            -
                    @lvalue, @rvalue = lvalue, rvalue
         | 
| 35 | 
            +
                  def single_quoted?
         | 
| 36 | 
            +
                    @attrs[:quoted_by] == "'"
         | 
| 42 37 | 
             
                  end
         | 
| 43 38 |  | 
| 44 39 | 
             
                  def inspect
         | 
| @@ -46,7 +41,7 @@ module Yap::Shell | |
| 46 41 | 
             
                  end
         | 
| 47 42 |  | 
| 48 43 | 
             
                  def to_s
         | 
| 49 | 
            -
                    " | 
| 44 | 
            +
                    "ArgumentNode(#{lvalue.inspect})"
         | 
| 50 45 | 
             
                  end
         | 
| 51 46 | 
             
                end
         | 
| 52 47 |  | 
| @@ -56,8 +51,8 @@ module Yap::Shell | |
| 56 51 | 
             
                  attr_reader :command, :args
         | 
| 57 52 | 
             
                  attr_accessor :heredoc, :redirects
         | 
| 58 53 |  | 
| 59 | 
            -
                  def initialize( | 
| 60 | 
            -
                    @command =  | 
| 54 | 
            +
                  def initialize(token, *args, literal:false, heredoc:nil)
         | 
| 55 | 
            +
                    @command = token.value
         | 
| 61 56 | 
             
                    @args = args.flatten
         | 
| 62 57 | 
             
                    @literal = literal
         | 
| 63 58 | 
             
                    @heredoc = nil
         | 
| @@ -108,13 +103,13 @@ module Yap::Shell | |
| 108 103 |  | 
| 109 104 | 
             
                  attr_reader :env
         | 
| 110 105 |  | 
| 111 | 
            -
                  def initialize( | 
| 106 | 
            +
                  def initialize(token, argument_node)
         | 
| 112 107 | 
             
                    @env = {}
         | 
| 113 | 
            -
                    @env[ | 
| 108 | 
            +
                    @env[token.value] = argument_node
         | 
| 114 109 | 
             
                  end
         | 
| 115 110 |  | 
| 116 | 
            -
                  def add_var( | 
| 117 | 
            -
                    @env[ | 
| 111 | 
            +
                  def add_var(token, argument_node)
         | 
| 112 | 
            +
                    @env[token.value] = argument_node
         | 
| 118 113 | 
             
                  end
         | 
| 119 114 | 
             
                end
         | 
| 120 115 |  | 
| @@ -165,8 +160,8 @@ module Yap::Shell | |
| 165 160 |  | 
| 166 161 | 
             
                  attr_reader :operator, :expr1, :expr2
         | 
| 167 162 |  | 
| 168 | 
            -
                  def initialize( | 
| 169 | 
            -
                    @operator =  | 
| 163 | 
            +
                  def initialize(token, expr1, expr2)
         | 
| 164 | 
            +
                    @operator = token.value
         | 
| 170 165 | 
             
                    @expr1    = expr1
         | 
| 171 166 | 
             
                    @expr2    = expr2
         | 
| 172 167 | 
             
                  end
         | 
| @@ -182,8 +177,8 @@ module Yap::Shell | |
| 182 177 | 
             
                  attr_reader :src
         | 
| 183 178 | 
             
                  alias_method :command, :src
         | 
| 184 179 |  | 
| 185 | 
            -
                  def initialize( | 
| 186 | 
            -
                    @src =  | 
| 180 | 
            +
                  def initialize(token)
         | 
| 181 | 
            +
                    @src = token.value
         | 
| 187 182 | 
             
                  end
         | 
| 188 183 |  | 
| 189 184 | 
             
                  def args
         | 
| @@ -231,9 +226,9 @@ module Yap::Shell | |
| 231 226 |  | 
| 232 227 | 
             
                  attr_reader :kind, :target
         | 
| 233 228 |  | 
| 234 | 
            -
                  def initialize( | 
| 235 | 
            -
                    @kind =  | 
| 236 | 
            -
                    @target = target
         | 
| 229 | 
            +
                  def initialize(token)
         | 
| 230 | 
            +
                    @kind = token.value
         | 
| 231 | 
            +
                    @target = token.attrs[:target]
         | 
| 237 232 | 
             
                  end
         | 
| 238 233 |  | 
| 239 234 | 
             
                  def to_s(indent:0)
         | 
| @@ -289,10 +284,10 @@ module Yap::Shell | |
| 289 284 |  | 
| 290 285 | 
             
                  attr_accessor :head, :tail, :params
         | 
| 291 286 |  | 
| 292 | 
            -
                  def initialize(head, tail, params:  | 
| 287 | 
            +
                  def initialize(head, tail, params: nil)
         | 
| 293 288 | 
             
                    @head = head
         | 
| 294 289 | 
             
                    @tail = tail
         | 
| 295 | 
            -
                    @params = params
         | 
| 290 | 
            +
                    @params = params ? params.value : []
         | 
| 296 291 | 
             
                  end
         | 
| 297 292 |  | 
| 298 293 | 
             
                  def to_s(indent:0)
         | 
| @@ -293,7 +293,7 @@ module_eval(<<'.,.,', 'grammar.y', 27) | |
| 293 293 |  | 
| 294 294 | 
             
            module_eval(<<'.,.,', 'grammar.y', 31)
         | 
| 295 295 | 
             
              def _reduce_6(val, _values, result)
         | 
| 296 | 
            -
                 result = ConditionalNode.new(val[1] | 
| 296 | 
            +
                 result = ConditionalNode.new(val[1], val[0], val[2]) 
         | 
| 297 297 | 
             
                result
         | 
| 298 298 | 
             
              end
         | 
| 299 299 | 
             
            .,.,
         | 
| @@ -311,7 +311,7 @@ module_eval(<<'.,.,', 'grammar.y', 36) | |
| 311 311 |  | 
| 312 312 | 
             
            module_eval(<<'.,.,', 'grammar.y', 38)
         | 
| 313 313 | 
             
              def _reduce_10(val, _values, result)
         | 
| 314 | 
            -
                 result = val[0].tap { |range_node| range_node.tail = BlockNode.new(nil, val[3], params: val[2] | 
| 314 | 
            +
                 result = val[0].tap { |range_node| range_node.tail = BlockNode.new(nil, val[3], params: val[2]) } 
         | 
| 315 315 | 
             
                result
         | 
| 316 316 | 
             
              end
         | 
| 317 317 | 
             
            .,.,
         | 
| @@ -325,7 +325,7 @@ module_eval(<<'.,.,', 'grammar.y', 40) | |
| 325 325 |  | 
| 326 326 | 
             
            module_eval(<<'.,.,', 'grammar.y', 42)
         | 
| 327 327 | 
             
              def _reduce_12(val, _values, result)
         | 
| 328 | 
            -
                 result = BlockNode.new(val[0], val[3], params: val[2] | 
| 328 | 
            +
                 result = BlockNode.new(val[0], val[3], params: val[2]) 
         | 
| 329 329 | 
             
                result
         | 
| 330 330 | 
             
              end
         | 
| 331 331 | 
             
            .,.,
         | 
| @@ -409,14 +409,14 @@ module_eval(<<'.,.,', 'grammar.y', 73) | |
| 409 409 |  | 
| 410 410 | 
             
            module_eval(<<'.,.,', 'grammar.y', 76)
         | 
| 411 411 | 
             
              def _reduce_29(val, _values, result)
         | 
| 412 | 
            -
                 result = RedirectionNode.new(val[0] | 
| 412 | 
            +
                 result = RedirectionNode.new(val[0]) 
         | 
| 413 413 | 
             
                result
         | 
| 414 414 | 
             
              end
         | 
| 415 415 | 
             
            .,.,
         | 
| 416 416 |  | 
| 417 417 | 
             
            module_eval(<<'.,.,', 'grammar.y', 79)
         | 
| 418 418 | 
             
              def _reduce_30(val, _values, result)
         | 
| 419 | 
            -
                 val[0].redirects << RedirectionNode.new(val[1] | 
| 419 | 
            +
                 val[0].redirects << RedirectionNode.new(val[1]) ; result = val[0] 
         | 
| 420 420 | 
             
                result
         | 
| 421 421 | 
             
              end
         | 
| 422 422 | 
             
            .,.,
         | 
| @@ -436,14 +436,14 @@ module_eval(<<'.,.,', 'grammar.y', 85) | |
| 436 436 |  | 
| 437 437 | 
             
            module_eval(<<'.,.,', 'grammar.y', 88)
         | 
| 438 438 | 
             
              def _reduce_35(val, _values, result)
         | 
| 439 | 
            -
                 val[0].add_var(val[1] | 
| 439 | 
            +
                 val[0].add_var(val[1], ArgumentNode.new(val[2])) ; result = val[0] 
         | 
| 440 440 | 
             
                result
         | 
| 441 441 | 
             
              end
         | 
| 442 442 | 
             
            .,.,
         | 
| 443 443 |  | 
| 444 444 | 
             
            module_eval(<<'.,.,', 'grammar.y', 90)
         | 
| 445 445 | 
             
              def _reduce_36(val, _values, result)
         | 
| 446 | 
            -
                 result = EnvNode.new(val[0] | 
| 446 | 
            +
                 result = EnvNode.new(val[0], ArgumentNode.new(val[1])) 
         | 
| 447 447 | 
             
                result
         | 
| 448 448 | 
             
              end
         | 
| 449 449 | 
             
            .,.,
         | 
| @@ -452,49 +452,49 @@ module_eval(<<'.,.,', 'grammar.y', 90) | |
| 452 452 |  | 
| 453 453 | 
             
            module_eval(<<'.,.,', 'grammar.y', 95)
         | 
| 454 454 | 
             
              def _reduce_38(val, _values, result)
         | 
| 455 | 
            -
                 result = CommandNode.new(val[0] | 
| 455 | 
            +
                 result = CommandNode.new(val[0]) 
         | 
| 456 456 | 
             
                result
         | 
| 457 457 | 
             
              end
         | 
| 458 458 | 
             
            .,.,
         | 
| 459 459 |  | 
| 460 460 | 
             
            module_eval(<<'.,.,', 'grammar.y', 97)
         | 
| 461 461 | 
             
              def _reduce_39(val, _values, result)
         | 
| 462 | 
            -
                 result = CommandNode.new(val[0] | 
| 462 | 
            +
                 result = CommandNode.new(val[0], val[1].flatten) 
         | 
| 463 463 | 
             
                result
         | 
| 464 464 | 
             
              end
         | 
| 465 465 | 
             
            .,.,
         | 
| 466 466 |  | 
| 467 467 | 
             
            module_eval(<<'.,.,', 'grammar.y', 99)
         | 
| 468 468 | 
             
              def _reduce_40(val, _values, result)
         | 
| 469 | 
            -
                 result = CommandNode.new(val[0] | 
| 469 | 
            +
                 result = CommandNode.new(val[0], literal:true) 
         | 
| 470 470 | 
             
                result
         | 
| 471 471 | 
             
              end
         | 
| 472 472 | 
             
            .,.,
         | 
| 473 473 |  | 
| 474 474 | 
             
            module_eval(<<'.,.,', 'grammar.y', 101)
         | 
| 475 475 | 
             
              def _reduce_41(val, _values, result)
         | 
| 476 | 
            -
                 result = CommandNode.new(val[0] | 
| 476 | 
            +
                 result = CommandNode.new(val[0], val[1].flatten, literal:true) 
         | 
| 477 477 | 
             
                result
         | 
| 478 478 | 
             
              end
         | 
| 479 479 | 
             
            .,.,
         | 
| 480 480 |  | 
| 481 481 | 
             
            module_eval(<<'.,.,', 'grammar.y', 104)
         | 
| 482 482 | 
             
              def _reduce_42(val, _values, result)
         | 
| 483 | 
            -
                 result = [ArgumentNode.new(val[0] | 
| 483 | 
            +
                 result = [ArgumentNode.new(val[0])] 
         | 
| 484 484 | 
             
                result
         | 
| 485 485 | 
             
              end
         | 
| 486 486 | 
             
            .,.,
         | 
| 487 487 |  | 
| 488 488 | 
             
            module_eval(<<'.,.,', 'grammar.y', 106)
         | 
| 489 489 | 
             
              def _reduce_43(val, _values, result)
         | 
| 490 | 
            -
                 result = [val[0], ArgumentNode.new(val[1] | 
| 490 | 
            +
                 result = [val[0], ArgumentNode.new(val[1])].flatten 
         | 
| 491 491 | 
             
                result
         | 
| 492 492 | 
             
              end
         | 
| 493 493 | 
             
            .,.,
         | 
| 494 494 |  | 
| 495 495 | 
             
            module_eval(<<'.,.,', 'grammar.y', 109)
         | 
| 496 496 | 
             
              def _reduce_44(val, _values, result)
         | 
| 497 | 
            -
                 result = InternalEvalNode.new(val[0] | 
| 497 | 
            +
                 result = InternalEvalNode.new(val[0]) 
         | 
| 498 498 | 
             
                result
         | 
| 499 499 | 
             
              end
         | 
| 500 500 | 
             
            .,.,
         | 
| @@ -72,18 +72,25 @@ describe Yap::Shell::Parser::Lexer do | |
| 72 72 | 
             
                    end
         | 
| 73 73 |  | 
| 74 74 | 
             
                    describe "ls {echo n }" do
         | 
| 75 | 
            -
                      it  | 
| 76 | 
            -
                         | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 75 | 
            +
                      it "parses as a block" do
         | 
| 76 | 
            +
                        should eq [
         | 
| 77 | 
            +
                          t(:Command, "ls", lineno:0),
         | 
| 78 | 
            +
                          t(:BlockBegin, '{', lineno: 0),
         | 
| 79 | 
            +
                          t(:Command, "echo", lineno:0),
         | 
| 80 | 
            +
                          t(:Argument, "n", lineno:0),
         | 
| 81 | 
            +
                          t(:BlockEnd, '}', lineno: 0)
         | 
| 82 | 
            +
                        ]
         | 
| 83 | 
            +
                      end
         | 
| 82 84 | 
             
                    end
         | 
| 83 85 |  | 
| 84 86 | 
             
                    describe "ls s{ echo n}" do
         | 
| 85 | 
            -
                      it " | 
| 86 | 
            -
                         | 
| 87 | 
            +
                      it "parses as arguments" do
         | 
| 88 | 
            +
                        should eq [
         | 
| 89 | 
            +
                          t(:Command, "ls", lineno:0),
         | 
| 90 | 
            +
                          t(:Argument, "s{", lineno:0),
         | 
| 91 | 
            +
                          t(:Argument, "echo", lineno:0),
         | 
| 92 | 
            +
                          t(:Argument, "n}", lineno:0)
         | 
| 93 | 
            +
                        ]
         | 
| 87 94 | 
             
                      end
         | 
| 88 95 | 
             
                    end
         | 
| 89 96 | 
             
                  end
         | 
| @@ -468,7 +475,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 468 475 | 
             
                    let(:str){ "ls 'hello there'" }
         | 
| 469 476 | 
             
                    it { should eq [
         | 
| 470 477 | 
             
                      t(:Command, "ls", lineno:0),
         | 
| 471 | 
            -
                      t(:Argument, "hello there", lineno:0)
         | 
| 478 | 
            +
                      t(:Argument, "hello there", lineno:0, attrs: { quoted_by: "'" })
         | 
| 472 479 | 
             
                    ]}
         | 
| 473 480 | 
             
                  end
         | 
| 474 481 |  | 
| @@ -476,7 +483,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 476 483 | 
             
                    let(:str){ "ls 'hello \\'there\\''" }
         | 
| 477 484 | 
             
                    it { should eq [
         | 
| 478 485 | 
             
                      t(:Command, "ls", lineno:0),
         | 
| 479 | 
            -
                      t(:Argument, "hello 'there'", lineno:0)
         | 
| 486 | 
            +
                      t(:Argument, "hello 'there'", lineno:0, attrs: { quoted_by: "'" })
         | 
| 480 487 | 
             
                    ]}
         | 
| 481 488 | 
             
                  end
         | 
| 482 489 |  | 
| @@ -484,7 +491,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 484 491 | 
             
                    let(:str){ %|ls 'hello "there"'| }
         | 
| 485 492 | 
             
                    it { should eq [
         | 
| 486 493 | 
             
                      t(:Command, "ls", lineno:0),
         | 
| 487 | 
            -
                      t(:Argument, 'hello "there"', lineno:0)
         | 
| 494 | 
            +
                      t(:Argument, 'hello "there"', lineno:0, attrs: { quoted_by: "'" })
         | 
| 488 495 | 
             
                    ]}
         | 
| 489 496 | 
             
                  end
         | 
| 490 497 |  | 
| @@ -492,7 +499,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 492 499 | 
             
                    let(:str){ "ls 'hello \\'there \\\\'guy\\\\' \\''" }
         | 
| 493 500 | 
             
                    it { should eq [
         | 
| 494 501 | 
             
                      t(:Command, "ls", lineno:0),
         | 
| 495 | 
            -
                      t(:Argument, "hello 'there \\'guy\\' '", lineno:0)
         | 
| 502 | 
            +
                      t(:Argument, "hello 'there \\'guy\\' '", lineno:0, attrs: { quoted_by: "'" })
         | 
| 496 503 | 
             
                    ]}
         | 
| 497 504 | 
             
                  end
         | 
| 498 505 |  | 
| @@ -500,8 +507,8 @@ describe Yap::Shell::Parser::Lexer do | |
| 500 507 | 
             
                    let(:str){ "ls 'hello \\'there\\'' 'how are \\'you\\'?'" }
         | 
| 501 508 | 
             
                    it { should eq [
         | 
| 502 509 | 
             
                      t(:Command, "ls", lineno:0),
         | 
| 503 | 
            -
                      t(:Argument, "hello 'there'", lineno:0),
         | 
| 504 | 
            -
                      t(:Argument, "how are 'you'?", lineno:0)
         | 
| 510 | 
            +
                      t(:Argument, "hello 'there'", lineno:0, attrs: { quoted_by: "'" }),
         | 
| 511 | 
            +
                      t(:Argument, "how are 'you'?", lineno:0, attrs: { quoted_by: "'" })
         | 
| 505 512 | 
             
                    ]}
         | 
| 506 513 | 
             
                  end
         | 
| 507 514 |  | 
| @@ -509,7 +516,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 509 516 | 
             
                    let(:str){ "alias z='echo hi'" }
         | 
| 510 517 | 
             
                    it { should eq [
         | 
| 511 518 | 
             
                      t(:Command, "alias", lineno:0),
         | 
| 512 | 
            -
                      t(:Argument, "z=echo hi", lineno:0),
         | 
| 519 | 
            +
                      t(:Argument, "z=echo hi", lineno:0, attrs: { quoted_by: "'" }),
         | 
| 513 520 | 
             
                    ]}
         | 
| 514 521 | 
             
                  end
         | 
| 515 522 | 
             
                end
         | 
| @@ -519,7 +526,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 519 526 | 
             
                    let(:str){ 'ls "hello there"' }
         | 
| 520 527 | 
             
                    it { should eq [
         | 
| 521 528 | 
             
                      t(:Command, 'ls', lineno:0),
         | 
| 522 | 
            -
                      t(:Argument, 'hello there', lineno:0)
         | 
| 529 | 
            +
                      t(:Argument, 'hello there', lineno:0, attrs: { quoted_by: '"' })
         | 
| 523 530 | 
             
                    ]}
         | 
| 524 531 | 
             
                  end
         | 
| 525 532 |  | 
| @@ -527,7 +534,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 527 534 | 
             
                    let(:str){ %|ls "hello 'there'"| }
         | 
| 528 535 | 
             
                    it { should eq [
         | 
| 529 536 | 
             
                      t(:Command, 'ls', lineno:0),
         | 
| 530 | 
            -
                      t(:Argument, "hello 'there'", lineno:0)
         | 
| 537 | 
            +
                      t(:Argument, "hello 'there'", lineno:0, attrs: { quoted_by: '"' })
         | 
| 531 538 | 
             
                    ]}
         | 
| 532 539 | 
             
                  end
         | 
| 533 540 |  | 
| @@ -535,7 +542,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 535 542 | 
             
                    let(:str){ 'ls "hello \\"there\\""' }
         | 
| 536 543 | 
             
                    it { should eq [
         | 
| 537 544 | 
             
                      t(:Command, 'ls', lineno:0),
         | 
| 538 | 
            -
                      t(:Argument, 'hello "there"', lineno:0)
         | 
| 545 | 
            +
                      t(:Argument, 'hello "there"', lineno:0, attrs: { quoted_by: '"' })
         | 
| 539 546 | 
             
                    ]}
         | 
| 540 547 | 
             
                  end
         | 
| 541 548 |  | 
| @@ -543,7 +550,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 543 550 | 
             
                    let(:str){ 'ls "hello \\"there \\\\"guy\\\\" \\""' }
         | 
| 544 551 | 
             
                    it { should eq [
         | 
| 545 552 | 
             
                      t(:Command, 'ls', lineno:0),
         | 
| 546 | 
            -
                      t(:Argument, 'hello "there \\"guy\\" "', lineno:0)
         | 
| 553 | 
            +
                      t(:Argument, 'hello "there \\"guy\\" "', lineno:0, attrs: { quoted_by: '"' })
         | 
| 547 554 | 
             
                    ]}
         | 
| 548 555 | 
             
                  end
         | 
| 549 556 |  | 
| @@ -551,8 +558,8 @@ describe Yap::Shell::Parser::Lexer do | |
| 551 558 | 
             
                    let(:str){ 'ls "hello \\"there\\"" "how are \\"you\\"?"' }
         | 
| 552 559 | 
             
                    it { should eq [
         | 
| 553 560 | 
             
                      t(:Command, 'ls', lineno:0),
         | 
| 554 | 
            -
                      t(:Argument, 'hello "there"', lineno:0),
         | 
| 555 | 
            -
                      t(:Argument, 'how are "you"?', lineno:0)
         | 
| 561 | 
            +
                      t(:Argument, 'hello "there"', lineno:0, attrs: { quoted_by: '"' }),
         | 
| 562 | 
            +
                      t(:Argument, 'how are "you"?', lineno:0, attrs: { quoted_by: '"' })
         | 
| 556 563 | 
             
                    ]}
         | 
| 557 564 | 
             
                  end
         | 
| 558 565 |  | 
| @@ -560,10 +567,28 @@ describe Yap::Shell::Parser::Lexer do | |
| 560 567 | 
             
                    let(:str){ "alias z=\"echo hi\"" }
         | 
| 561 568 | 
             
                    it { should eq [
         | 
| 562 569 | 
             
                      t(:Command, "alias", lineno:0),
         | 
| 563 | 
            -
                      t(:Argument, "z=echo hi", lineno:0) | 
| 570 | 
            +
                      t(:Argument, "z=echo hi", lineno:0, attrs: { quoted_by: '"' })
         | 
| 564 571 | 
             
                    ]}
         | 
| 565 572 | 
             
                  end
         | 
| 566 573 | 
             
                end
         | 
| 574 | 
            +
             | 
| 575 | 
            +
                context 'args with special characters' do
         | 
| 576 | 
            +
                  describe 'echo @{u}' do
         | 
| 577 | 
            +
                    it { should eq [
         | 
| 578 | 
            +
                      t(:Command, "echo", lineno:0),
         | 
| 579 | 
            +
                      t(:Argument, "@{u}", lineno:0)
         | 
| 580 | 
            +
                    ]}
         | 
| 581 | 
            +
                  end
         | 
| 582 | 
            +
             | 
| 583 | 
            +
                  describe 'echo @\(u\)' do
         | 
| 584 | 
            +
                    it "parentheses must be escaped to be treated as arguments" do
         | 
| 585 | 
            +
                      should eq [
         | 
| 586 | 
            +
                        t(:Command, "echo", lineno:0),
         | 
| 587 | 
            +
                        t(:Argument, "@(u)", lineno:0)
         | 
| 588 | 
            +
                      ]
         | 
| 589 | 
            +
                    end
         | 
| 590 | 
            +
                  end
         | 
| 591 | 
            +
                end
         | 
| 567 592 | 
             
              end
         | 
| 568 593 |  | 
| 569 594 | 
             
              context "statements" do
         | 
| @@ -1063,7 +1088,7 @@ describe Yap::Shell::Parser::Lexer do | |
| 1063 1088 | 
             
                    t(:LValue, "FOO", lineno: 0),
         | 
| 1064 1089 | 
             
                    t(:RValue, "abc", lineno: 0),
         | 
| 1065 1090 | 
             
                    t(:LValue, "BAR", lineno: 0),
         | 
| 1066 | 
            -
                    t(:RValue, "hello world", lineno: 0),
         | 
| 1091 | 
            +
                    t(:RValue, "hello world", lineno: 0, attrs: { quoted_by: "'"}),
         | 
| 1067 1092 | 
             
                    t(:Command, "ls", lineno: 0),
         | 
| 1068 1093 | 
             
                    t(:Argument, "-l", lineno: 0)
         | 
| 1069 1094 | 
             
                  ]}
         | 
| @@ -1332,4 +1357,79 @@ describe Yap::Shell::Parser::Lexer do | |
| 1332 1357 | 
             
                  end
         | 
| 1333 1358 | 
             
                end
         | 
| 1334 1359 | 
             
              end
         | 
| 1360 | 
            +
             | 
| 1361 | 
            +
              describe 'strings' do
         | 
| 1362 | 
            +
                describe 'non-terminated strings' do
         | 
| 1363 | 
            +
                  it 'raises an error on non-terminated double quotes' do
         | 
| 1364 | 
            +
                    expect do
         | 
| 1365 | 
            +
                      described_class.new.tokenize('"nonterminated')
         | 
| 1366 | 
            +
                    end.to raise_error(
         | 
| 1367 | 
            +
                      Yap::Shell::Parser::Lexer::NonterminatedString,
         | 
| 1368 | 
            +
                      %|Expected to find " in:\n  "nonterminated|
         | 
| 1369 | 
            +
                    )
         | 
| 1370 | 
            +
                  end
         | 
| 1371 | 
            +
             | 
| 1372 | 
            +
                  it 'raises an error on non-terminated single quotes' do
         | 
| 1373 | 
            +
                    expect do
         | 
| 1374 | 
            +
                      described_class.new.tokenize("'nonterminated")
         | 
| 1375 | 
            +
                    end.to raise_error(
         | 
| 1376 | 
            +
                      Yap::Shell::Parser::Lexer::NonterminatedString,
         | 
| 1377 | 
            +
                      %|Expected to find ' in:\n  'nonterminated|
         | 
| 1378 | 
            +
                    )
         | 
| 1379 | 
            +
                  end
         | 
| 1380 | 
            +
                end
         | 
| 1381 | 
            +
              end
         | 
| 1382 | 
            +
             | 
| 1383 | 
            +
              describe 'line continutations' do
         | 
| 1384 | 
            +
                describe 'backward slashes' do
         | 
| 1385 | 
            +
                  it 'raises an error when found at the end of the single line string' do
         | 
| 1386 | 
            +
                    expect do
         | 
| 1387 | 
            +
                      described_class.new.tokenize('echo hello \\')
         | 
| 1388 | 
            +
                    end.to raise_error(
         | 
| 1389 | 
            +
                      Yap::Shell::Parser::Lexer::LineContinuationFound,
         | 
| 1390 | 
            +
                      %|Expected more input, line continutation found|
         | 
| 1391 | 
            +
                    )
         | 
| 1392 | 
            +
                  end
         | 
| 1393 | 
            +
             | 
| 1394 | 
            +
                  it 'raises an error when found at the end of a multiline string' do
         | 
| 1395 | 
            +
                    expect do
         | 
| 1396 | 
            +
                      described_class.new.tokenize("echo hello \n world\\")
         | 
| 1397 | 
            +
                    end.to raise_error(
         | 
| 1398 | 
            +
                      Yap::Shell::Parser::Lexer::LineContinuationFound,
         | 
| 1399 | 
            +
                      %|Expected more input, line continutation found|
         | 
| 1400 | 
            +
                    )
         | 
| 1401 | 
            +
                  end
         | 
| 1402 | 
            +
             | 
| 1403 | 
            +
                  it 'does not raise when found before the end of a single line string' do
         | 
| 1404 | 
            +
                    expect do
         | 
| 1405 | 
            +
                      described_class.new.tokenize("echo hello \\ world")
         | 
| 1406 | 
            +
                    end.to_not raise_error
         | 
| 1407 | 
            +
                  end
         | 
| 1408 | 
            +
             | 
| 1409 | 
            +
                  it 'does not raise when found before the end of a multiline string' do
         | 
| 1410 | 
            +
                    expect do
         | 
| 1411 | 
            +
                      described_class.new.tokenize("echo hello \n world\\ word")
         | 
| 1412 | 
            +
                    end.to_not raise_error
         | 
| 1413 | 
            +
                  end
         | 
| 1414 | 
            +
             | 
| 1415 | 
            +
                  context 'newlines that follow line continuations inside a string are stripped' do
         | 
| 1416 | 
            +
                    let(:str){ "echo foo\\\nbar" }
         | 
| 1417 | 
            +
                    it { should eq [
         | 
| 1418 | 
            +
                      t(:Command, "echo", lineno:0),
         | 
| 1419 | 
            +
                      t(:Argument, "foobar", lineno:0)
         | 
| 1420 | 
            +
                    ]}
         | 
| 1421 | 
            +
                  end
         | 
| 1422 | 
            +
             | 
| 1423 | 
            +
                  context 'newlines that follow line continuations at the end of a string are not stripped' do
         | 
| 1424 | 
            +
                    it 'raises an error when found at the end of a multiline string' do
         | 
| 1425 | 
            +
                      expect do
         | 
| 1426 | 
            +
                        described_class.new.tokenize("echo foo\\\nbar\\\n" )
         | 
| 1427 | 
            +
                      end.to raise_error(
         | 
| 1428 | 
            +
                        Yap::Shell::Parser::Lexer::LineContinuationFound,
         | 
| 1429 | 
            +
                        %|Expected more input, line continutation found|
         | 
| 1430 | 
            +
                      )
         | 
| 1431 | 
            +
                    end
         | 
| 1432 | 
            +
                  end
         | 
| 1433 | 
            +
                end
         | 
| 1434 | 
            +
              end
         | 
| 1335 1435 | 
             
            end
         | 
| @@ -61,6 +61,9 @@ describe Yap::Shell::Parser do | |
| 61 61 | 
             
              it { is_expected.to parse "echo bar && > foo.txt" }
         | 
| 62 62 | 
             
              it { is_expected.to parse "#this is a comment" }
         | 
| 63 63 | 
             
              it { is_expected.to parse "echo foo #this last part is a comment" }
         | 
| 64 | 
            +
              it { is_expected.to parse "git reset --hard @{u}" }
         | 
| 64 65 |  | 
| 65 66 | 
             
              it { is_expected.to fail_parsing "ls ()" }
         | 
| 67 | 
            +
              it { is_expected.to parse("echo 'hi'")}
         | 
| 68 | 
            +
              it { is_expected.to parse("ls > foo.txt")}
         | 
| 66 69 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: yap-shell-parser
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Zach Dennis
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2016- | 
| 11 | 
            +
            date: 2016-05-05 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         |