Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#983: Refactor CTPG script options Java parser code #462

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ void ScriptImporter::importScript(std::string & scriptCode,
importScript(scriptCode, options, 0);
}

void ScriptImporter::replaceScripts(const ExecutionGraph::OptionsLineParser::CTPG::options_map_t::mapped_type & option_values,
const size_t recursionDepth,
std::vector<ReplacedScripts> &result) {
for (const auto & option: option_values) {
const char *importScriptCode = findImportScript(option.value);
std::string importScriptCodeStr;
if (m_importedScriptChecksums.addScript(importScriptCode) ) {
// Script has not been imported yet
// If this imported script contains %import statements
// they will be resolved in the next recursion.
ctpg_parser::options_map_t newOptions;
try {
ExecutionGraph::OptionsLineParser::CTPG::parseOptions(importScriptCode, newOptions);
} catch(const ExecutionGraph::OptionParserException & ex) {
Utils::rethrow(ex, "F-UDF-CL-SL-JAVA-1630");
}
importScriptCodeStr.assign(importScriptCode);
importScript(importScriptCodeStr, newOptions, recursionDepth + 1);
}
ReplacedScripts replacedScript = {.script = std::move(importScriptCodeStr), .origPos = option.idx_in_source, .origLen = option.size };
result.push_back(std::move(replacedScript));
}
}

void ScriptImporter::importScript(std::string & scriptCode,
ctpg_parser::options_map_t & options,
const size_t recursionDepth) {
Expand All @@ -43,35 +67,11 @@ void ScriptImporter::importScript(std::string & scriptCode,
{
return first.idx_in_source < second.idx_in_source;
});
struct ReplacedScripts {
ReplacedScripts(ReplacedScripts&&) = default;
std::string script;
size_t origPos;
size_t origLen;
};
std::vector<ReplacedScripts> replacedScripts;
replacedScripts.reserve(optionIt->second.size());
//In order to continue compatibility with legacy implementation we must collect import scripts in forward direction
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably go into collectImportScripts

Copy link
Collaborator Author

@tomuben tomuben Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, the comment is about both steps:
collectImportScripts() + ``replaceImportScripts`. I think it's better to keep it here

//but then replace in reverse direction (in order to keep consistency of positions)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one is already in replaceImportScripts

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

 (in order to keep consistency of positions)

for (const auto & option: optionIt->second) {
const char *importScriptCode = findImportScript(option.value);
std::string importScriptCodeStr;
if (m_importedScriptChecksums.addScript(importScriptCode) ) {
// Script has not been imported yet
// If this imported script contains %import statements
// they will be resolved in the next recursion.
ctpg_parser::options_map_t newOptions;
try {
ExecutionGraph::OptionsLineParser::CTPG::parseOptions(importScriptCode, newOptions);
} catch(const ExecutionGraph::OptionParserException & ex) {
Utils::rethrow(ex, "F-UDF-CL-SL-JAVA-1630");
}
importScriptCodeStr.assign(importScriptCode);
importScript(importScriptCodeStr, newOptions, recursionDepth + 1);
}
ReplacedScripts replacedScript = {.script = std::move(importScriptCodeStr), .origPos = option.idx_in_source, .origLen = option.size };
replacedScripts.push_back(std::move(replacedScript));
}
replaceScripts(optionIt->second, recursionDepth, replacedScripts);
tomuben marked this conversation as resolved.
Show resolved Hide resolved
//Now replace the imported script bodies from end to start. Doing it in forward order would invalidate the offsets of later import scripts.
for (auto optionIt = replacedScripts.rbegin(); optionIt != replacedScripts.rend(); optionIt++) {
tomuben marked this conversation as resolved.
Show resolved Hide resolved
scriptCode.replace(optionIt->origPos, optionIt->origLen, optionIt->script);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,39 @@ namespace JavaScriptOptions {

namespace CTPG {



class ScriptImporter {

public:
ScriptImporter(SwigFactory & swigFactory, Keywords & keywords);

void importScript(std::string & scriptCode, ExecutionGraph::OptionsLineParser::CTPG::options_map_t & options);

private:
struct ReplacedScripts {
ReplacedScripts(ReplacedScripts&&) = default;
std::string script;
size_t origPos;
size_t origLen;
};

private:
tomuben marked this conversation as resolved.
Show resolved Hide resolved
void importScript(std::string & scriptCode,
ExecutionGraph::OptionsLineParser::CTPG::options_map_t & options,
const size_t recursionDepth);
const char* findImportScript(const std::string & scriptKey);

void replaceScripts(const ExecutionGraph::OptionsLineParser::CTPG::options_map_t::mapped_type & option_values,
tomuben marked this conversation as resolved.
Show resolved Hide resolved
const size_t recursionDepth,
std::vector<ReplacedScripts> &result);

private:
tomuben marked this conversation as resolved.
Show resolved Hide resolved
Checksum m_importedScriptChecksums;
SwigFactory & m_swigFactory;
std::unique_ptr<SWIGMetadataIf> m_metaData;
Keywords & m_keywords;
//The empirical maximal value for recursion depth is ~26000. So we choose 20000 to have a certain buffer.
//The empirical maximal value for recursion depth is ~18000. So we choose 10000 to have a certain buffer.
tomuben marked this conversation as resolved.
Show resolved Hide resolved
tomuben marked this conversation as resolved.
Show resolved Hide resolved
const size_t cMaxRecursionDepth = 20000;
tomuben marked this conversation as resolved.
Show resolved Hide resolved
tomuben marked this conversation as resolved.
Show resolved Hide resolved
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,29 +200,53 @@ void parse(std::string&& code, options_type& result) {

} //namespace ParserInternals

struct LinePositions {
size_t mStartPos;
size_t mEndPos;
};

inline std::optional<const LinePositions> getNextLine(const size_t current_pos, const std::string & scriptCode) {
/**
* Find first of occurence of '%', starting search from position 'current_pos'.
* If no '%' is found, return an empty result.
* If '%' is found, search backwards from '%' for '\n' or \r':
* 1. If not found, '%' was found in the first line. Then we can set 'new_option_start_pos'=0
* 2. If found, set new_option_start_pos to position 1 char behind pos of found '\n' or '\r'.
* Then search forward for next occurence of '\n' or \r' and assign to var 'line_end_pos':
1. If not found, 'line_end_pos' will get assigned std::string::npos (std::string::substr(...,npos), returns substring until end of string
2. If found, 'line_end_pos' will assigned to position of line end of line where '%' was found
*/
std::optional<LinePositions> retVal;
const size_t new_option_start_pos = scriptCode.find_first_of("%", current_pos);
if (new_option_start_pos == std::string::npos)
return retVal;
size_t line_start_pos = scriptCode.find_last_of("\r\n", new_option_start_pos);
if (std::string::npos == line_start_pos)
line_start_pos = 0;
else
line_start_pos++;

tomuben marked this conversation as resolved.
Show resolved Hide resolved
const size_t line_end_pos = scriptCode.find_first_of("\r\n", line_start_pos);
retVal = LinePositions{ .mStartPos = line_start_pos, .mEndPos = line_end_pos};
return retVal;
}

void parseOptions(const std::string& code, options_map_t & result) {

size_t current_pos = 0;

do {
const size_t new_option_start_pos = code.find_first_of("%", current_pos);
if (new_option_start_pos == std::string::npos)
const std::optional<const LinePositions> currentLinePositions = getNextLine(current_pos, code);
if (!currentLinePositions)
break;
tomuben marked this conversation as resolved.
Show resolved Hide resolved
current_pos = code.find_last_of("\r\n", new_option_start_pos);
if (std::string::npos == current_pos)
current_pos = 0;
else
current_pos++;

const size_t new_pos = code.find_first_of("\r\n", current_pos);
std::string line = code.substr(current_pos, new_pos);
std::string line = code.substr(currentLinePositions->mStartPos, currentLinePositions->mEndPos);
options_type parser_result;
ParserInternals::parse(std::move(line), parser_result);
for (const auto & option: parser_result)
{
ScriptOption entry = {
.value = option.value,
.idx_in_source = current_pos + option.start.column - 1,
.idx_in_source = currentLinePositions->mStartPos + option.start.column - 1,
.size = option.end.column - option.start.column + 1
};
auto it_in_result = result.find(option.key);
Expand All @@ -237,10 +261,10 @@ void parseOptions(const std::string& code, options_map_t & result) {
it_in_result->second.push_back(entry);
}
}
if (new_pos == std::string::npos) {
if (currentLinePositions->mEndPos == std::string::npos) {
break;
}
current_pos = new_pos + 1;
current_pos = currentLinePositions->mEndPos + 1;
} while(true);
}

Expand Down
Loading