Class: PreprocessinatorExtractor
- Defined in:
- lib/ceedling/preprocessinator_extractor.rb
Instance Method Summary collapse
-
#extract_file_as_array_from_expansion(input, filepath) ⇒ Object
‘input` must have the interface of IO – StringIO for testing or File in typical use.
-
#extract_file_as_string_from_expansion(input, filepath) ⇒ Object
Simple variation of preceding that returns file contents as single string.
-
#extract_include_guard(file_contents) ⇒ Object
Find include guard in file contents as string.
-
#extract_macro_defs(file_contents, include_guard) ⇒ Object
Extract all macro definitions as a list from a file as string.
-
#extract_pragmas(file_contents) ⇒ Object
Extract all pragmas as a list from a file as string.
-
#extract_test_directive_macro_calls(file_contents) ⇒ Object
Extract all test directive macros as a list from a file as string.
Instance Method Details
#extract_file_as_array_from_expansion(input, filepath) ⇒ Object
‘input` must have the interface of IO – StringIO for testing or File in typical use
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 |
# File 'lib/ceedling/preprocessinator_extractor.rb', line 82 def extract_file_as_array_from_expansion(input, filepath) ## ## Iterate through all lines and alternate between extract and ignore modes. ## All lines between a '#' line containing the filepath to extract (a line marker) and the next '#' line should be extracted. ## ## GCC preprocessor output line marker format: `# <linenum> "<filename>" <flags>` ## ## Documentation on line markers in GCC preprocessor output: ## https://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_9.html ## ## Notes: ## 1. Successive blocks can all be from the same source text file without a different, intervening '#' line. ## Multiple back-to-back blocks could all begin with '# 99 "path/file.c"'. ## 2. The first line of the file could start a text block we care about. ## 3. End of file could end a text block. ## 4. Usually, the first line marker contains no trailing flag. ## 5. Different preprocessors conforming to the GCC output standard may use different trailiing flags. ## 6. Our simple ping-pong-between-line-markers extraction technique does not require decoding flags. ## # Expand filepath under inspection to ensure proper match extaction_filepath = File.( filepath ) # Preprocessor directive blocks generally take the form of '# <digits> <text> [optional digits]' directive = /^# \d+ \"/ # Line markers have the specific form of '# <digits> "path/filename.ext" [optional digits]' (see above) line_marker = /^#\s\d+\s\"(.+)\"/ # Boolean to ping pong between line-by-line extract/ignore extract = false # Collection of extracted lines lines = [] # Use `each_line()` instead of `readlines()` (chomp removes newlines). # `each_line()` processes the IO buffer one line at a time instead of ingesting lines in an array. # At large buffer sizes needed for potentially lengthy preprocessor output this is far more memory efficient and faster. input.each_line( chomp:true ) do |line| # Clean up any oddball characters in an otherwise ASCII document line = line.clean_encoding # Handle expansion extraction if the line is not a preprocessor directive if extract and not line =~ directive # Strip a line so we can omit useless blank lines _line = line.strip() # Restore text with left-side whitespace if previous stripping left some text _line = line.rstrip() if !_line.empty? # Collect extracted lines lines << _line # Otherwise the line contained a preprocessor directive; drop out of extract mode else extract = false end # Enter extract mode if the line is a preprocessor line marker with filepath of interest matches = line.match( line_marker ) if matches and matches.size() > 1 filepath = File.( matches[1].strip() ) extract = true if extaction_filepath == filepath end end return lines end |
#extract_file_as_string_from_expansion(input, filepath) ⇒ Object
Simple variation of preceding that returns file contents as single string
150 151 152 |
# File 'lib/ceedling/preprocessinator_extractor.rb', line 150 def extract_file_as_string_from_expansion(input, filepath) return extract_file_as_array_from_expansion(input, filepath).join( "\n" ) end |
#extract_include_guard(file_contents) ⇒ Object
Find include guard in file contents as string
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/ceedling/preprocessinator_extractor.rb', line 175 def extract_include_guard(file_contents) # Look for first occurrence of #ifndef <sring> followed by #define <string> regex = /#\s*ifndef\s+(\w+)(?:\s*\n)+\s*#\s*define\s+(\w+)/ matches = file_contents.match( regex ) # Return if no match results return nil if matches.nil? # Return if match results are not expected size return nil if matches.size != 3 # Return if #ifndef <string> does not match #define <string> return nil if matches[1] != matches[2] # Return string in common return matches[1] end |
#extract_macro_defs(file_contents, include_guard) ⇒ Object
Extract all macro definitions as a list from a file as string
195 196 197 198 199 200 201 202 |
# File 'lib/ceedling/preprocessinator_extractor.rb', line 195 def extract_macro_defs(file_contents, include_guard) macro_definitions = extract_multiline_directives( file_contents, 'define' ) # Remove an include guard if provided macro_definitions.reject! {|macro| macro.include?( include_guard ) } if !include_guard.nil? return macro_definitions end |
#extract_pragmas(file_contents) ⇒ Object
Extract all pragmas as a list from a file as string
169 170 171 |
# File 'lib/ceedling/preprocessinator_extractor.rb', line 169 def extract_pragmas(file_contents) return extract_multiline_directives( file_contents, 'pragma' ) end |
#extract_test_directive_macro_calls(file_contents) ⇒ Object
Extract all test directive macros as a list from a file as string
156 157 158 159 160 161 162 163 164 165 |
# File 'lib/ceedling/preprocessinator_extractor.rb', line 156 def extract_test_directive_macro_calls(file_contents) # Look for TEST_SOURCE_FILE("...") and TEST_INCLUDE_PATH("...") in a string (i.e. a file's contents as a string) regexes = [ /(#{PATTERNS::TEST_SOURCE_FILE})/, /(#{PATTERNS::TEST_INCLUDE_PATH})/ ] return extract_tokens_by_regex_list( file_contents, *regexes ).map(&:first) end |