class TaskJuggler::ProjectFileScanner
This class specializes the TextParser::Scanner
class to detect the tokens of the TJP syntax.
Public Class Methods
new(masterFile)
click to toggle source
Calls superclass method
# 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