Skip to content
This repository was archived by the owner on Apr 17, 2023. It is now read-only.

Commit 505283e

Browse files
committed
Added insertion of sketch prototypes to converted sources
Added utility function to escape semicolons in a string and vice-versa Fixed bug in `list_max_index` utility function
1 parent 4742857 commit 505283e

File tree

5 files changed

+86
-39
lines changed

5 files changed

+86
-39
lines changed

cmake/Platform/Sketches/SketchManager.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function(add_sketch_to_target _target_name _sketch_file)
3434
resolve_sketch_libraries(${_target_name} ${_sketch_file} "${sketch_headers}")
3535
resolve_sketch_prototypes(${_sketch_file} "${sketch_headers}" sketch_prototypes)
3636

37-
convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path})
37+
convert_sketch_to_source(${_sketch_file} ${sketch_converted_source_path} ${sketch_prototypes})
3838

3939
endif ()
4040

cmake/Platform/Sketches/SketchPrototypesResolver.cmake

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ function(resolve_sketch_prototypes _sketch_file _sketch_headers _return_var)
2222
match_function_declaration("${func_def}" "${_sketch_headers}" match)
2323

2424
if (${match} MATCHES "NOTFOUND")
25-
# ToDo: Append signature to list of prototypes to create
26-
message("Coludn't find a matching declaration for `${func_def}`")
25+
list(APPEND prototypes "${func_def}")
2726
endif ()
2827

2928
endforeach ()
3029

30+
set(${_return_var} ${prototypes} PARENT_SCOPE)
31+
3132
endfunction()
Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#=============================================================================#
22
# Writes the given lines of code belonging to the sketch to the given file path.
3-
# _sketch_loc - List of lines-of-code belonging to the sketch.
3+
# _sketch_lines - List of lines-of-code belonging to the sketch.
44
# _file_path - Full path to the written source file.
55
#=============================================================================#
6-
function(_write_source_file _sketch_loc _file_path)
6+
function(_write_source_file _sketch_lines _file_path)
77

88
file(WRITE "${_file_path}" "") # Clear previous file's contents
99

10-
foreach (loc ${_sketch_loc})
11-
string(REGEX REPLACE "^(.+)${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}(.*)$" "\\1;\\2" original_loc "${loc}")
12-
file(APPEND "${_file_path}" "${original_loc}")
10+
foreach (line ${_sketch_lines})
11+
escape_semicolon_in_string("${line}" original_line REVERSE)
12+
file(APPEND "${_file_path}" "${original_line}")
1313
endforeach ()
1414

1515
endfunction()
@@ -20,12 +20,12 @@ endfunction()
2020
# best fitted the insertion, however, it might need a bit more optimization. Why?
2121
# Because above those lines there might be a comment, or a comment block,
2222
# all of which should be taken into account in order to minimize the effect on code's readability.
23-
# _sketch_loc - List of lines-of-code belonging to the sketch.
24-
# _active_index - Index that indicates the best-not-optimized loc to insert header to.
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.
2525
# _return_var - Name of variable in parent-scope holding the return value.
2626
# Returns - Best fitted index to insert platform's main header '#include' to.
2727
#=============================================================================#
28-
function(_get_matching_header_insertion_index _sketch_loc _active_index _return_var)
28+
function(_get_matching_header_insertion_index _sketch_lines _active_index _return_var)
2929

3030
if (${_active_index} EQUAL 0) # First line in a file will always result in the 1st index
3131
set(${_return_var} 0 PARENT_SCOPE)
@@ -34,14 +34,14 @@ function(_get_matching_header_insertion_index _sketch_loc _active_index _return_
3434
decrement_integer(_active_index 1)
3535
endif ()
3636

37-
list(GET _sketch_loc ${_active_index} previous_loc)
37+
list(GET _sketch_lines ${_active_index} previous_loc)
3838

3939
if ("${previous_loc}" MATCHES "^//") # Simple one-line comment
4040
set(matching_index ${_active_index})
4141
elseif ("${previous_loc}" MATCHES "\\*/$") # End of multi-line comment
4242

4343
foreach (index RANGE ${_active_index} 0)
44-
list(GET _sketch_loc ${index} multi_comment_line)
44+
list(GET _sketch_lines ${index} multi_comment_line)
4545

4646
if ("${multi_comment_line}" MATCHES "^\\/\\*") # Start of multi-line comment
4747
set(matching_index ${index})
@@ -63,63 +63,86 @@ endfunction()
6363
# _sketch_lines - List of code lines read from the converted sketch file.
6464
# _insertion_line_index - Index of a code line at which the header should be inserted
6565
#=============================================================================#
66-
macro(_insert_platform_header_include_line _sketch_lines _insertion_line_index)
66+
macro(_insert_line _inserted_line _sketch_lines _insertion_line_index)
6767

6868
_get_matching_header_insertion_index("${_sketch_lines}" ${_insertion_line_index} header_index)
6969

7070
if (${header_index} LESS ${_insertion_line_index})
71-
set(formatted_include_line ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} "\n\n")
71+
set(formatted_include_line ${_inserted_line} "\n\n")
7272
elseif (${header_index} EQUAL 0)
73-
set(formatted_include_line ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE} "\n")
73+
set(formatted_include_line ${_inserted_line} "\n")
7474
else ()
75-
set(formatted_include_line "\n" ${ARDUINO_CMAKE_PLATFORM_HEADER_INCLUDE_LINE})
75+
set(formatted_include_line "\n" ${_inserted_line})
7676

7777
if (${header_index} GREATER_EQUAL ${_insertion_line_index})
7878
decrement_integer(header_index 1)
7979
string(APPEND formatted_include_line "\n")
8080
endif ()
8181
endif ()
8282

83-
list(INSERT refined_sketch ${header_index} ${formatted_include_line})
83+
list(INSERT converted_source ${header_index} ${formatted_include_line})
84+
85+
endmacro()
86+
87+
macro(_insert_prototypes _prototypes _sketch_lines _insertion_line_index)
88+
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 ()
8496

8597
endmacro()
8698

8799
#=============================================================================#
88100
# Converts the given sketch file into a valid 'cpp' source file under the project's working dir.
89101
# During the conversion process the platform's main header file is inserted to the source file
90102
# since it's critical for it to include it - Something that doesn't happen in "Standard" sketches.
91-
# _sketch_file - Full path to the original sketch file (Read from).
92-
# _converted_source_path - Full path to the converted target source file (Written to).
103+
# _sketch_file - Full path to the original sketch file (Read from).
104+
# _converted_source_path - Full path to the converted target source file (Written to).
105+
# _sketch_prototypes - List of prototypes to genereate, i.e. function definitions without a declaration.
93106
#=============================================================================#
94-
function(convert_sketch_to_source _sketch_file _converted_source_path)
107+
function(convert_sketch_to_source _sketch_file _converted_source_path _sketch_prototypes)
95108

96-
file(STRINGS "${_sketch_file}" sketch_loc)
109+
file(STRINGS "${_sketch_file}" sketch_lines)
97110

111+
set(function_prototype_pattern
112+
"${ARDUINO_CMAKE_FUNCTION_DECLARATION_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}")
98113
set(header_insert_pattern
99-
"${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${ARDUINO_CMAKE_FUNCTION_DEFINITION_REGEX_PATTERN}")
114+
"${ARDUINO_CMAKE_HEADER_INCLUDE_REGEX_PATTERN}|${function_prototype_pattern}")
115+
100116
set(header_inserted FALSE)
117+
set(prototypes_inserted FALSE)
101118

102-
list(LENGTH sketch_loc num_of_loc)
103-
decrement_integer(num_of_loc 1)
119+
list_max_index("${sketch_lines}" lines_count)
120+
#[[list(LENGTH sketch_lines lines_count)
121+
decrement_integer(lines_count 1)]]
104122

105-
foreach (loc_index RANGE 0 ${num_of_loc})
123+
foreach (line_index RANGE ${lines_count})
106124

107-
list(GET sketch_loc ${loc_index} loc)
125+
list(GET sketch_lines ${line_index} line)
108126

109-
if (NOT ${header_inserted} AND "${loc}" MATCHES "${header_insert_pattern}")
110-
_insert_platform_header_include_line("${sketch_loc}" ${loc_index})
111-
set(header_inserted TRUE)
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)
112135
endif ()
113136

114-
if ("${loc}" STREQUAL "")
115-
list(APPEND refined_sketch "\n")
137+
if ("${line}" STREQUAL "")
138+
list(APPEND converted_source "\n")
116139
else ()
117-
string(REGEX REPLACE "^(.+);(.*)$" "\\1${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}\\2" refined_loc "${loc}")
118-
list(APPEND refined_sketch "${refined_loc}\n")
140+
escape_semicolon_in_string("${line}" formatted_line)
141+
list(APPEND converted_source "${formatted_line}\n")
119142
endif ()
120143

121144
endforeach ()
122145

123-
_write_source_file("${refined_sketch}" "${_converted_source_path}")
146+
_write_source_file("${converted_source}" "${_converted_source_path}")
124147

125148
endfunction()

cmake/Platform/Utilities/ListUtils.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ function(list_max_index _list _return_var)
3737
list(LENGTH _list list_length)
3838

3939
set(index ${list_length})
40-
if (${index} GREATER 0)
41-
decrement_integer(${index} 1)
40+
if (${list_length} GREATER 0)
41+
decrement_integer(index 1)
4242
endif ()
4343

4444
set(${_return_var} ${index} PARENT_SCOPE)

cmake/Platform/Utilities/StringUtils.cmake

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ endfunction()
7474
#=============================================================================#
7575
# Extracts a name symbol without possible file extension (marked usually by a dot ('.').
7676
# _input_string - String containing name symbol and possibly file extension.
77-
# _return_var - Name of a CMake variable that will hold the extraction result.
77+
# _return_var - Name of a CMake variable that will hold the return value.
7878
# Returns - String containing input name without possible file extension.
7979
#=============================================================================#
8080
function(get_name_without_file_extension _input_string _return_var)
@@ -89,7 +89,7 @@ endfunction()
8989
# Converts a given string to a PascalCase string, converting 1st letter to upper
9090
# and remaining to lower.
9191
# _input_string - String to convert.
92-
# _return_var - Name of a CMake variable that will hold the extraction result.
92+
# _return_var - Name of a CMake variable that will hold the return value.
9393
# Returns - PascalCase converted string.
9494
#=============================================================================#
9595
function(convert_string_to_pascal_case _input_string _return_var)
@@ -108,3 +108,26 @@ function(convert_string_to_pascal_case _input_string _return_var)
108108
set(${_return_var} ${combined_string} PARENT_SCOPE)
109109

110110
endfunction()
111+
112+
#=============================================================================#
113+
# Escapes a semicolon in a given string by replacing it with a "magic" string instead,
114+
# which isn't parsed as a list separator by CMake.
115+
# This function can also reverse an escaped semicolon by replacing it back with a semicolon.
116+
# _string - String to escape/re-escape.
117+
# [REVERSE] - Optional flag indicating whether to reverse an already-escaped string back to its original form.
118+
# _return_var - Name of a CMake variable that will hold the return value.
119+
# Returns - Original string if [REVERSE] provided, Semicolon-escaped string otherwise.
120+
#=============================================================================#
121+
function(escape_semicolon_in_string _string _return_var)
122+
123+
cmake_parse_arguments(parsed_args "REVERSE" "" "" ${ARGN})
124+
125+
if (parsed_args_REVERSE)
126+
string(REGEX REPLACE "^(.+)${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}(.*)$" "\\1;\\2" escaped_line "${_string}")
127+
else ()
128+
string(REGEX REPLACE "^(.+);(.*)$" "\\1${ARDUINO_CMAKE_SEMICOLON_REPLACEMENT}\\2" escaped_line "${_string}")
129+
endif ()
130+
131+
set(${_return_var} ${escaped_line} PARENT_SCOPE)
132+
133+
endfunction()

0 commit comments

Comments
 (0)