Class: TaskJuggler::ProjectFileScanner

Inherits:
TextParser::Scanner show all
Defined in:
lib/taskjuggler/ProjectFileScanner.rb

Overview

This class specializes the TextParser::Scanner class to detect the tokens of the TJP syntax.

Instance Method Summary collapse

Methods inherited from TextParser::Scanner

#addMacro, #addPattern, #close, #columnNo, #error, #expandMacro, #fileName, #include, #line, #lineNo, #macroDefined?, #mode=, #nextToken, #open, #returnToken, #sourceFileInfo, #warning

Constructor Details

#initialize(masterFile) ⇒ ProjectFileScanner

Returns a new instance of ProjectFileScanner.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/taskjuggler/ProjectFileScanner.rb', line 22

def initialize(masterFile)
  tokenPatterns = [
    # Any white spaces
    [ nil, /\s+/, :tjp, method('newPos') ],

    # Single line comments starting with #
    [ nil, /#.*\n?/, :tjp, method('newPos') ],

    # C++ style single line comments starting with //
    [ nil, /\/\/.*\n?/, :tjp, method('newPos') ],

    # C style single line comment /* .. */.
    [ nil, /\/\*.*\*\//, :tjp, method('newPos') ],

    # C style multi line comment: We need three patterns here. The first
    # one is for the start of the string. It switches the scanner mode to
    # the :cppComment mode.
    [ nil, /\/\*([^*]*[^\/]|.*)\n/, :tjp, method('startComment') ],
    # This is the string end pattern. It switches back to tjp mode.
    [ nil, /.*\*\//, :cppComment, method('endComment') ],
    # This pattern matches string lines that contain neither the start,
    # nor the end of the string.
    [ nil, /^.*\n/, :cppComment ],

    # Macro Call: This case is more complicated because we want to replace
    # macro calls inside of numbers, strings and identifiers. For this to
    # work, macro calls may have a prefix that looks like a number, a part
    # of a string or an identifier. This prefix is preserved and
    # re-injected into the scanner together with the expanded text. Macro
    # calls may span multiple lines. The ${ and the macro name must be in
    # the first line. Arguments that span multiple lines are not
    # supported. As above, we need rules for the start, the end and lines
    # with neither start nor end. Macro calls inside of strings need a
    # special start pattern that is active in the string modes. Both
    # patterns switch the scanner to macroCall mode.
    [ nil, /([-a-zA-Z_0-9>:.+]*|"(\\"|[^"])*?|'(\\'|[^'])*?)?\$\{\s*(\??[a-zA-Z_]\w*)(\s*"(\\"|[^"])*")*/,
      :tjp, method('startMacroCall') ],
    # This pattern is similar to the previous one, but is active inside of
    # multi-line strings. The corresponding rule for sizzors strings
    # can be found below.
    [ nil, /(\\"|[^"])*?\$\{\s*(\??[a-zA-Z_]\w*)(\s*"(\\"|[^"])*")*/,
      :dqString, method('startMacroCall') ],
    [ nil, /(\\'|[^'])*?\$\{\s*(\??[a-zA-Z_]\w*)(\s*"(\\"|[^"])*")*/,
      :sqString, method('startMacroCall') ],
    # This pattern matches the end of a macro call. It injects the prefix
    # and the expanded macro into the scanner again. The mode is restored
    # to the previous mode.
    [ nil, /(\s*"(\\"|[^"])*")*\s*\}/, :macroCall, method('endMacroCall') ],
    # This pattern collects macro call arguments in lines that contain
    # neither the start nor the end of the macro.
    [ nil, /.*\n/, :macroCall, method('midMacroCall') ],

    # Environment variable reference. This is similar to the macro call,
    # but the it can only extend within the starting line.
    [ nil, /([-a-zA-Z_0-9>:.+]*|"(\\"|[^"])*?|'(\\'|[^'])*?)?\$\([A-Z_][A-Z_0-9]*\)/,
      :tjp, method('environmentVariable') ],
    # An ID with a colon suffix: foo:
    [ :ID_WITH_COLON, /[a-zA-Z_]\w*:/, :tjp, method('chop') ],

    # An absolute ID: a.b.c
    [ :ABSOLUTE_ID, /[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)+/ ],

    # A normal ID: bar
    [ :ID, /[a-zA-Z_]\w*/ ],

    # A date
    [ :DATE, /\d{4}-\d{1,2}-\d{1,2}(-\d{1,2}:\d{1,2}(:\d{1,2})?(-[-+]?\d{4})?)?/, :tjp, method('to_date') ],

    # A time of day
    [ :TIME, /\d{1,2}:\d{2}/, :tjp, method('to_time') ],

    # A floating point number (e. g. 3.143)
    [ :FLOAT, /\d*\.\d+/, :tjp, method('to_f') ],

    # An integer number
    [ :INTEGER, /\d+/, :tjp, method('to_i') ],

    # Multi line string enclosed with double quotes. The string may
    # contain double quotes prefixed by a backslash. The first rule
    # switches the scanner to dqString mode.
    [ 'nil', /"(\\"|[^"])*/, :tjp, method('startStringDQ') ],
    # Any line not containing the start or end.
    [ 'nil', /^(\\"|[^"])*\n/, :dqString, method('midStringDQ') ],
    # The end of the string.
    [ :STRING, /(\\"|[^"])*"/, :dqString, method('endStringDQ') ],

    # Multi line string enclosed with single quotes.
    [ 'nil', /'(\\'|[^'])*/, :tjp, method('startStringSQ') ],
    # Any line not containing the start or end.
    [ 'nil', /^(\\'|[^'])*\n/, :sqString, method('midStringSQ') ],
    # The end of the string.
    [ :STRING, /(\\'|[^'])*'/, :sqString, method('endStringSQ') ],

    # Scizzors marked string -8<- ... ->8-: The opening mark must be the
    # last thing in the line. The indentation of the first line after the
    # opening mark determines the indentation for all following lines. So,
    # we first switch the scanner to szrString1 mode.
    [ 'nil', /-8<-.*\n/, :tjp, method('startStringSZR') ],
    # Since the first line can be the last line (empty string case), we
    # need to detect the end in szrString1 and szrString mode. The
    # patterns switch the scanner back to tjp mode.
    [ :STRING, /\s*->8-/, :szrString1, method('endStringSZR') ],
    [ :STRING, /\s*->8-/, :szrString, method('endStringSZR') ],
    # This rule handles macros inside of sizzors strings.
    [ nil, /.*?\$\{\s*(\??[a-zA-Z_]\w*)(\s*"(\\"|[^"])*")*/,
      [ :szrString, :szrString1 ], method('startMacroCall') ],
    # Any line not containing the start or end.
    [ 'nil', /.*\n/, :szrString1, method('firstStringSZR') ],
    [ 'nil', /.*\n/, :szrString, method('midStringSZR') ],

    # Single line macro definition
    [ :MACRO, /\[.*\]\n/, :tjp, method('chop2nl') ],

    # Multi line macro definition: The pattern switches the scanner into
    # macroDef mode.
    [ nil, /\[.*\n/, :tjp, method('startMacroDef') ],
    # The end of the macro is marked by a ']' that is immediately followed
    # by a line break. It switches the scanner back to tjp mode.
    [ :MACRO, /.*\]\n/, :macroDef, method('endMacroDef') ],
    # Any line not containing the start or end.
    [ nil, /.*\n/, :macroDef, method('midMacroDef') ],

    # Some multi-char literals.
    [ :LITERAL, /<=?/ ],
    [ :LITERAL, />=?/ ],
    [ :LITERAL, /!=?/ ],

    # Everything else is returned as a single-char literal.
    [ :LITERAL, /./ ]
  ]

  super(masterFile, Log, tokenPatterns, :tjp)
end