@@ -14,92 +14,108 @@ function(_write_source_file _sketch_lines _file_path)
1414
1515endfunction ()
1616
17- #=============================================================================#
18- # Finds the best line to insert an '#include' of the platform's main header to.
19- # The function assumes that the initial state of the given 'active index' is set to the line that
20- # best fitted the insertion, however, it might need a bit more optimization. Why?
21- # Because above those lines there might be a comment, or a comment block,
22- # all of which should be taken into account in order to minimize the effect on code's readability.
23- # _sketch_lines - List of lines-of-code belonging to the sketch.
24- # _active_index - Index that indicates the best-not-optimized line to insert header to.
25- # _return_var - Name of variable in parent-scope holding the return value.
26- # Returns - Best fitted index to insert platform's main header '#include' to.
27- #=============================================================================#
28- function (_get_matching_header_insertion_index _sketch_lines _active_index _return_var )
17+ macro (_setup_regex_patterns)
18+
19+ string (CONCAT function_prototype_pattern
20+ " ${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN} "
21+ "| ${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN} " )
22+ string (CONCAT code_pattern
23+ " ${ARDUINO_CMAKE_PREPROCESSOR_REGEX_PATTERN} "
24+ "| ${function_prototype_pattern} " )
25+
26+ set (comment_line_pattern " \\ / \\ /" )
27+ set (comment_block_start_pattern " \\ / \\ *" )
28+ set (comment_block_end_pattern " \\ * \\ /" )
2929
30- if (${_active_index} EQUAL 0) # First line in a file will always result in the 1st index
31- set (${_return_var} 0 PARENT_SCOPE)
32- return ()
30+ endmacro ()
31+
32+ macro (_insert_platform_header _current_line _line_index)
33+
34+ if ("${_current_line} " MATCHES "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN} " )
35+ set (include_line "${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} \n " )
3336 else ()
34- decrement_integer(_active_index 1)
37+ set (include_line "${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} \n\n " )
38+ set (header_inclusion_block FALSE )
3539 endif ()
3640
37- list (GET _sketch_lines ${_active_index} previous_loc)
41+ list (INSERT converted_source ${_line_index} "${include_line} " )
42+
43+ endmacro ()
3844
39- if ("${previous_loc} " MATCHES "^//" ) # Simple one-line comment
40- set (matching_index ${_active_index} )
41- elseif ("${previous_loc} " MATCHES "\\ */$" ) # End of multi-line comment
45+ macro (_handle_platform_header)
4246
43- foreach (index RANGE ${_active_index} 0)
44- list (GET _sketch_lines ${index} multi_comment_line)
47+ if ("${line} " MATCHES "${comment_line_pattern} " )
48+ set (last_comment_start_index ${line_index} )
49+ set (last_comment_end_index ${line_index} )
50+ elseif ("${line} " MATCHES "${comment_block_start_pattern} " )
51+ set (last_comment_start_index ${line_index} )
52+ elseif ("${line} " MATCHES "${comment_block_end_pattern} " )
53+ set (last_comment_end_index ${line_index} )
54+ elseif ("${line} " MATCHES "${code_pattern} " )
4555
46- if ("${multi_comment_line} " MATCHES "^\\ /\\ *" ) # Start of multi-line comment
47- set (matching_index ${index} )
48- break ()
49- endif ()
50- endforeach ()
56+ set (header_inclusion_block TRUE )
57+
58+ # Calculate difference between current line index and last comment's end index
59+ math (EXPR line_index_diff "${line_index} - ${last_comment_end_index} " )
60+
61+ # Comment ends above current line, any lines should be inserted above
62+ if (${line_index_diff} EQUAL 1)
63+ _insert_platform_header("${line} " ${last_comment_start_index} )
64+ else ()
65+ _insert_platform_header("${line} " ${line_index} )
66+ endif ()
67+
68+ set (header_inserted TRUE )
5169
52- else () # Previous line isn't a comment - Return original index
53- increment_integer(_active_index 1)
54- set (matching_index ${_active_index} )
5570 endif ()
5671
57- set ( ${_return_var} ${matching_index} PARENT_SCOPE )
72+ endmacro ( )
5873
59- endfunction ( )
74+ macro (_handle_prototype_generation )
6075
61- #=============================================================================#
62- # Inline macro which handles the process of inserting a line including the platform header.
63- # _sketch_lines - List of code lines read from the converted sketch file.
64- # _insertion_line_index - Index of a code line at which the header should be inserted
65- #=============================================================================#
66- macro (_insert_line _inserted_line _sketch_lines _insertion_line_index)
76+ if (NOT "${line} " MATCHES "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN} " )
77+ if (NOT "${line} " STREQUAL "" ) # Not a newline
6778
68- _get_matching_header_insertion_index("${_sketch_lines} " ${_insertion_line_index} header_index)
79+ if (NOT header_inclusion_block)
80+ # Insert a newline to separate prototypes from the rest of the code
81+ list (INSERT converted_source ${line_index} "\n " )
82+ endif ()
6983
70- if (${header_index} LESS ${_insertion_line_index} )
71- set (formatted_include_line ${_inserted_line} "\n\n " )
72- elseif (${header_index} EQUAL 0)
73- set (formatted_include_line ${_inserted_line} "\n " )
74- else ()
75- set (formatted_include_line "\n " ${_inserted_line} )
84+ foreach (prototype ${_sketch_prototypes} )
85+ # Add missing semicolon to make a definition a declaration and escape it
86+ escape_semicolon_in_string("${prototype} ;" escaped_prototype)
87+ list (INSERT converted_source ${line_index} "${escaped_prototype} \n " )
88+ endforeach ()
89+
90+ if (header_inclusion_block)
91+ list (INSERT converted_source ${line_index} "\n // Prototypes generated by Arduino-CMake\n " )
92+ else ()
93+ list (INSERT converted_source ${line_index} "// Prototypes generated by Arduino-CMake\n " )
94+ endif ()
95+
96+ set (prototypes_inserted TRUE )
97+ set (header_inclusion_block FALSE )
7698
77- if (${header_index} GREATER_EQUAL ${_insertion_line_index} )
78- decrement_integer(header_index 1)
79- string (APPEND formatted_include_line "\n " )
8099 endif ()
81100 endif ()
82101
83- list (INSERT converted_source ${header_index} ${formatted_include_line} )
84-
85102endmacro ()
86103
87- macro (_insert_prototypes _prototypes _sketch_lines _insertion_line_index )
104+ macro (_handle_simple_lines )
88105
89- foreach (prototype ${_prototypes} )
90- # Add semicolon ';' to make it a declaration
91- escape_semicolon_in_string("${prototype} ;" formatted_prototype)
92-
93- _insert_line("${formatted_prototype} " "${sketch_lines} " ${line_index} )
94- increment_integer(_insertion_line_index 1)
95- endforeach ()
106+ if ("${line} " STREQUAL "" )
107+ list (APPEND converted_source "\n " )
108+ else ()
109+ escape_semicolon_in_string("${line} " formatted_line)
110+ list (APPEND converted_source "${formatted_line} \n " )
111+ endif ()
96112
97113endmacro ()
98114
99115#=============================================================================#
100- # Converts the given sketch file into a valid 'cpp' source file under the project's working dir.
101- # During the conversion process the platform's main header file is inserted to the source file
102- # since it's critical for it to include it - Something that doesn't happen in "Standard" sketches .
116+ # Converts the given sketch file into a valid '. cpp' source file under the project's working dir.
117+ # During the conversion process the platform's main header file is inserted to the source file,
118+ # as well as any given prototypes, found earlier through a function def-dec matching process .
103119# _sketch_file - Full path to the original sketch file (Read from).
104120# _converted_source_path - Full path to the converted target source file (Written to).
105121# _sketch_prototypes - List of prototypes to genereate, i.e. function definitions without a declaration.
@@ -108,38 +124,28 @@ function(convert_sketch_to_source _sketch_file _converted_source_path _sketch_pr
108124
109125 file (STRINGS "${_sketch_file} " sketch_lines)
110126
111- set (function_prototype_pattern
112- "${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN} |${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN} " )
113- set (header_insert_pattern
114- "${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN} |${function_prototype_pattern} " )
127+ _setup_regex_patterns()
115128
116129 set (header_inserted FALSE )
117130 set (prototypes_inserted FALSE )
131+ set (header_inclusion_block FALSE )
132+
133+ set (last_comment_start_index 0)
134+ set (last_comment_end_index 0)
118135
119136 list_max_index("${sketch_lines} " lines_count)
120- #[[list(LENGTH sketch_lines lines_count)
121- decrement_integer(lines_count 1)]]
122137
123138 foreach (line_index RANGE ${lines_count} )
124139
125140 list (GET sketch_lines ${line_index} line)
126141
127- if (NOT ${header_inserted} )
128- if ("${line} " MATCHES "${header_insert_pattern} " )
129- _insert_line("${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} " "${sketch_lines} " ${line_index} )
130- set (header_inserted TRUE )
131- endif ()
132- elseif (NOT ${prototypes_inserted} AND "${line} " MATCHES "${function_prototype_pattern} " )
133- _insert_prototypes("${_sketch_prototypes} " "${sketch_lines} " ${line_index} )
134- set (prototypes_inserted TRUE )
142+ if (NOT header_inserted)
143+ _handle_platform_header()
144+ elseif (NOT prototypes_inserted)
145+ _handle_prototype_generation()
135146 endif ()
136147
137- if ("${line} " STREQUAL "" )
138- list (APPEND converted_source "\n " )
139- else ()
140- escape_semicolon_in_string("${line} " formatted_line)
141- list (APPEND converted_source "${formatted_line} \n " )
142- endif ()
148+ _handle_simple_lines()
143149
144150 endforeach ()
145151
0 commit comments