Class: PartializerUtils

Inherits:
Object show all
Includes:
Partials
Defined in:
lib/ceedling/partials/partializer_utils.rb

Constant Summary

Constants included from Partials

Partials::ACCUMULATE, Partials::DEDUCT, Partials::MOCK_PRIVATE, Partials::MOCK_PUBLIC, Partials::PRIVATE, Partials::PUBLIC, Partials::TEST_PRIVATE, Partials::TEST_PUBLIC

Instance Method Summary collapse

Methods included from Partials

manufacture_function_declaration, manufacture_function_definition

Instance Method Details

#format_line_number_list(funcs) ⇒ Array<String>

Format per-function line-number results as a list of human-readable strings.

Produces one entry per function in the form "name(): <line_num>". Functions with no resolved line number are rendered with 'N/A'. The returned array is passed directly to @loginator.log_list for debug output.

Parameters:

  • funcs (Array<CFunctionDefinition>)

    Functions with name and line_num fields

Returns:



177
178
179
180
181
# File 'lib/ceedling/partials/partializer_utils.rb', line 177

def format_line_number_list(funcs)
  funcs.map do |func|
    "#{func.name}(): #{func.line_num.nil? ? 'N/A' : func.line_num.to_s()}"
  end
end

#locate_function_in_source(code_block:, filepath:) ⇒ Integer?

Locate a function's line number by searching the original C source file.

Used when the global fallback mode is active — i.e., preprocessed output is unavailable for all functions in the current context. Delegates directly to code_finder.find_in_c_file.

Parameters:

  • code_block (String)

    Function definition text to search for

  • filepath (String)

    Path to the C source file to search

Returns:

  • (Integer, nil)

    1-indexed source line number, or nil if not found



143
144
145
# File 'lib/ceedling/partials/partializer_utils.rb', line 143

def locate_function_in_source(code_block:, filepath:)
  @code_finder.find_in_c_file(filepath, code_block)
end

#locate_function_via_preprocessed(code_block:, filepath:, preprocessed_filepath:) ⇒ Integer?

Locate a function's line number using preprocessed output with C source fallback.

Two-strategy lookup for a single function:

1. Try the GCC-preprocessed directives-only file — exact match preserving line markers.
2. If that yields nil, fall back to the original C source file.

Returns line number or nil if neither approach succeeds.

Parameters:

  • code_block (String)

    Function definition text to search for

  • filepath (String)

    Path to the original C source file (fallback target)

  • preprocessed_filepath (String)

    Path to the preprocessed directives-only file

Returns:

  • (Integer, nil)

    1-indexed source line number, or nil if not found



159
160
161
162
163
164
165
166
167
# File 'lib/ceedling/partials/partializer_utils.rb', line 159

def locate_function_via_preprocessed(code_block:, filepath:, preprocessed_filepath:)
  line_num = @code_finder.find_in_preprpocessed_file(preprocessed_filepath, code_block)
  return line_num unless line_num.nil?

  msg = "Using fallback C function location search for #{filepath}"
  @loginator.log( msg, Verbosity::OBNOXIOUS, LogLabels::WARNING )

  return @code_finder.find_in_c_file(filepath, code_block)
end

#matches_visibility?(decorators, visibility) ⇒ Boolean

Check if function decorators match the desired visibility

Returns:

  • (Boolean)


24
25
26
27
28
29
30
31
32
33
# File 'lib/ceedling/partials/partializer_utils.rb', line 24

def matches_visibility?(decorators, visibility)
  case visibility
  when PUBLIC
    return !is_function_private?(decorators)
  when PRIVATE
    return is_function_private?(decorators)
  else
    PartializerRuntime.raise_on_option(visibility)
  end
end

#rename_c_identifier(text, old_name, new_name) ⇒ String

Rename a C identifier throughout a text block with token-bounded substitution.

Replaces all occurrences of old_name that are bounded by C identifier boundaries with new_name. Token boundaries use Ruby \b (word boundary between \w = [a-zA-Z0-9_] and \W), which exactly matches C identifier boundaries. For example, renaming count:

- Matches:     `count = 0`, `(count)`, `count==5`, `*count`, `count[0]`
- No match:    `count_down`, `up_count`, `recount`

Note: This method has no comment-awareness. Callers that need comment content preserved verbatim (e.g., no-op placeholders) should use replace_declaration_with_noop with an opaque placeholder and restore the original text after renaming.

Parameters:

  • text (String)

    Code text to process

  • old_name (String)

    Identifier to replace

  • new_name (String)

    Replacement identifier

Returns:

  • (String)

    Modified text with all token-bounded occurrences renamed



118
119
120
# File 'lib/ceedling/partials/partializer_utils.rb', line 118

def rename_c_identifier(text, old_name, new_name)
  text.gsub(/\b#{Regexp.escape(old_name)}\b/, new_name)
end

#replace_compound_declaration_with_noops(text, original_decl, placeholder, count) ⇒ String

Replace a C compound variable declaration with N no-op expressions and a single comment.

Generates count (void)0; expressions where the final one carries a comment containing placeholder. The result replaces the first occurrence of original_decl in text. The caller supplies count = number of variables in the compound statement and a single unique placeholder token. After all variable renames are complete, the caller restores original_decl by replacing the placeholder with the original text.

Block form of sub is used so that \ and & in the declaration are not interpreted as regex replacement backreferences.

Parameters:

  • text (String)

    Code text to modify (e.g., a function code_block or body)

  • original_decl (String)

    Declaration text to replace (should be stripped of surrounding whitespace)

  • placeholder (String)

    Opaque token to embed in the single trailing comment

  • count (Integer)

    Number of no-op expressions to insert (one per variable)

Returns:



95
96
97
98
99
# File 'lib/ceedling/partials/partializer_utils.rb', line 95

def replace_compound_declaration_with_noops(text, original_decl, placeholder, count)
  noops   = "(void)0; " * (count - 1)
  comment = "(void)0; /* `#{placeholder}` replaced with no-op plus variable renamed & promoted to module-scope */"
  text.sub(original_decl) { noops + comment }
end

#replace_declaration_with_noop(text, original_decl, placeholder) ⇒ String

Replace a C variable declaration in a text block with a no-op expression.

Substitutes the first occurrence of original_decl in text with:

(void)0; /* <placeholder> */

The caller supplies a unique placeholder token for the comment slot. This allows subsequent rename operations (which use simple token-bounded substitution with no comment awareness) to run without touching the comment. After all renames are complete, the caller restores original_decl by replacing the placeholder.

Block form of sub is used so that \ and & in the declaration are not interpreted as regex replacement backreferences.

Parameters:

  • text (String)

    Code text to modify (e.g., a function code_block or body)

  • original_decl (String)

    Declaration text to replace (should be stripped of surrounding whitespace)

  • placeholder (String)

    Opaque token to embed in the comment (caller replaces it afterwards)

Returns:

  • (String)

    Modified text with declaration replaced by a no-op expression



75
76
77
# File 'lib/ceedling/partials/partializer_utils.rb', line 75

def replace_declaration_with_noop(text, original_decl, placeholder)
  replace_compound_declaration_with_noops(text, original_decl, placeholder, 1)
end

#setupObject



18
19
20
21
# File 'lib/ceedling/partials/partializer_utils.rb', line 18

def setup()
  # Aliases
  @code_finder = @preprocessinator_code_finder
end

#stamp_source_filepaths(funcs, filepath) ⇒ Object

Stamp the originating source filepath onto each function in a collection.

Mutates each element of funcs in place by assigning filepath to its source_filepath field. Called before any line-number search so the field is always populated regardless of whether a line number is ultimately found.

Parameters:

  • funcs (Array<CFunctionDefinition>)

    Functions to annotate

  • filepath (String)

    Path to the originating C source file



130
131
132
# File 'lib/ceedling/partials/partializer_utils.rb', line 130

def stamp_source_filepaths(funcs, filepath)
  funcs.each { |func| func.source_filepath = filepath }
end

#transform_function(func, signature, output_type) ⇒ Object

Transform function to appropriate output format FunctionDefinition or FunctionDeclaration



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ceedling/partials/partializer_utils.rb', line 36

def transform_function(func, signature, output_type)
  case output_type
  when :impl
    # Strip decorators from the front of code_block and count how many newlines were removed.
    # Adjust line_num upward so that emitted #line directives remain accurate.
    new_code_block, stripped_newlines = extract_code_block(func.code_block, func.decorators)
    Partials.manufacture_function_definition(
      name:            func.name,
      signature:       signature,
      source_filepath: func.source_filepath,
      line_num:        adjust_line_num(func.line_num, stripped_newlines),
      code_block:      new_code_block
    )
  when :interface
    Partials.manufacture_function_declaration(
      name: func.name,
      signature: signature
    )
  else
    PartializerRuntime.raise_on_option(output_type)
  end
end