Project

General

Profile

Patch #5886 » bash.rb

Anh Kỳ Huỳnh, 2012-11-22 04:56

 
1
module CodeRay module Scanners
2
  
3
  class BASH < Scanner
4

    
5
    register_for :bash
6
    
7
    RESERVED_WORDS = %w{
8
      if elif fi until while done for do case in esac select 
9
      break else then shift function
10
    }
11

    
12
    PREDEFINED_CONSTANTS = %w{
13
        $CDPATH $HOME $IFS $MAIL $MAILPATH $OPTARG $LINENO $LINES
14
        $OPTIND $PATH $PS1 $PS2 $BASH $BASH_ARGCBASH_ARGV
15
        $BASH_COMMAND $BASH_ENV $BASH_EXECUTION_STRING
16
        $BASH_LINENO $BASH_REMATCH $BASH_SOURCE $COLUMNS
17
        $BASH_SUBSHELL $BASH_VERSINFO $BASH_VERSION $OSTYPE
18
        $COMP_CWORD $COMP_LINE $COMP_POINT $COMP_WORDBREAKS
19
        $COMP_WORDS $COMPREPLY $DIRSTACK $EMACS $EUID $OTPERR
20
        $FCEDIT $FIGNORE $FUNCNAME $GLOBIGNORE $GROUPS $OLDPWD
21
        $histchars $HISTCMD $HISTCONTROL $HISTFILE $MACHTYPE
22
        $HISTFILESIZE $HISTIGNORE $HISTSIZE $HISTTIMEFOMAT
23
        $HOSTFILE $HOSTNAME $HOSTTYPE $IGNOREEOF $INPUTRC $LANG
24
        $LC_ALL $LC_COLLATE $LC_CTYPE $LC_MESSAGES $LC_NUMERIC
25
        $PIPESTATUS $POSIXLY_CORRECT $MAILCHECK $PPID $PS3 $PS4
26
        $PROMPT_COMMAND $PWD $RANDOM $REPLY $SECONDS $SHELL
27
        $SHELLOPTS $SHLVL $TIMEFORMAT $TMOUT $TMPDIR $UID
28
    }
29

    
30
    BUILTIN =  %w{
31
      cd continue eval exec true false suspend unalias
32
      exit export getopts hash pwd readonly return test
33
      times trap umask unset alias bind builtin caller
34
      command declare echo enable help let local logout
35
      printf read shopt source type typeset ulimit
36
      set dirs popd pushd bg fg jobs kill wait disown
37
    }
38

    
39
    IDENT_KIND = WordList.new(:ident).
40
      add(RESERVED_WORDS, :reserved).
41
      # add(PREDEFINED_CONSTANTS, :pre_constant).
42
      add(BUILTIN, :method)
43

    
44
    ESCAPE = / [\$rtnb\n\\'"] /x
45
    # UNICODE_ESCAPE =  / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
46

    
47
    VARIABLE_SIMPLE = /\$[a-zA-Z]\w*/
48
    VARIABLE_EXPRESSION = /\$\{[!#]?[a-zA-Z].*?\}/
49

    
50
    def scan_tokens tokens, options
51

    
52
      state = :initial
53
      string_type = nil
54

    
55
      until eos?
56

    
57
        kind = nil
58
        match = nil
59

    
60
        if state == :initial
61
          if scan(/ \s+ | \\\n /x)
62
            kind = :space
63
          elsif match = scan(/\#!.*/) # until eof
64
            kind = :preprocessor
65
          elsif scan(/\#.*/)
66
            kind = :comment
67
          elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%] | \.(?!\d) /x)
68
            kind = :operator
69
          elsif match = scan(/[1-9][0-9]*/)
70
            kind = :number
71
          elsif scan(/ \\ (?: \S ) /mox)
72
            kind = :char
73
          elsif scan(/(#{VARIABLE_SIMPLE}|#{VARIABLE_EXPRESSION})/)
74
            kind = :instance_variable
75
          elsif match = scan(/ [$@A-Za-z_][A-Za-z_0-9]* /x)
76
            kind = IDENT_KIND[match]
77
          elsif match = scan(/["']/)
78
            tokens << [:open, :string]
79
            string_type = matched
80
            state = :string
81
            kind = :delimiter
82
          else
83
            getch
84
          end
85
        elsif state == :regex
86
          if scan(/[^\\\/]+/)
87
            kind = :content
88
          elsif scan(/\\\/|\\/)
89
            kind = :content
90
          elsif scan(/\//)
91
            tokens << [matched, :delimiter]
92
            tokens << [:close, :regexp]
93
            state = :initial
94
            next
95
          else
96
            getch
97
            kind = :content
98
          end
99
          
100
        elsif state == :string
101
          if scan(/[^\\"']+/)
102
            kind = :content
103
          elsif scan(/["']/)
104
            if string_type==matched
105
              tokens << [matched, :delimiter]
106
              tokens << [:close, :string]
107
              state = :initial
108
              string_type=nil
109
              next
110
            else
111
              kind = :content
112
            end
113
          elsif scan(/ \\ (?: \S ) /mox)
114
            kind = :char
115
          elsif scan(/ \\ | $ /x)
116
            # kind = :error
117
            kind = :content
118
            state = :initial
119
          else
120
            raise "else case \" reached; %p not handled." % peek(1), tokens
121
          end
122
        else
123
          raise 'else-case reached', tokens
124
        end
125
        match ||= matched
126
        tokens << [match, kind]
127
      end
128
      tokens
129
    end
130
  end
131
end end
    (1-1/1)