[apps/code] Fix script importation status

Scenario: Execute the script parabola.py, open the variable box, select
any leaf, enter, open the variable box again -> no variables are loaded
anymore
This commit is contained in:
Léa Saviot
2020-06-09 15:12:13 +02:00
parent 213d3d322d
commit 1ccb55a16e
7 changed files with 67 additions and 71 deletions

View File

@@ -52,7 +52,7 @@ bool ConsoleController::loadPythonEnvironment() {
m_pythonDelegate->initPythonWithUser(this); m_pythonDelegate->initPythonWithUser(this);
MicroPython::registerScriptProvider(m_scriptStore); MicroPython::registerScriptProvider(m_scriptStore);
m_importScriptsWhenViewAppears = m_autoImportScripts; m_importScriptsWhenViewAppears = m_autoImportScripts;
m_scriptStore->clearFetchInformation(); m_scriptStore->clearConsoleFetchInformation();
} }
return true; return true;
} }

View File

@@ -65,16 +65,18 @@ bool Script::nameCompliant(const char * name) {
return false; return false;
} }
uint8_t * StatusFromData(Script::Data d) {
return const_cast<uint8_t *>(static_cast<const uint8_t *>(d.buffer));
}
bool Script::autoImportationStatus() const { bool Script::autoImportationStatus() const {
assert(!isNull()); return getStatutBit(k_autoImportationStatusMask);
Data d = value();
return (*statusFromData(d) & k_autoImportationStatusMask) == 1;
} }
void Script::toggleAutoimportationStatus() { void Script::toggleAutoimportationStatus() {
assert(!isNull()); assert(!isNull());
Data d = value(); Data d = value();
*statusFromData(d) ^= k_autoImportationStatusMask; *StatusFromData(d) ^= k_autoImportationStatusMask;
setValue(d); setValue(d);
} }
@@ -83,46 +85,34 @@ const char * Script::content() const {
return ((const char *)d.buffer) + StatusSize(); return ((const char *)d.buffer) + StatusSize();
} }
bool Script::contentFetchedFromConsole() const { bool Script::fetchedFromConsole() const {
return fetchedStatus() == FetchedStatus::FromConsole; return getStatutBit(k_fetchedFromConsoleMask);
} }
bool Script::contentFetchedForVariableBox() const { void Script::setFetchedFromConsole(bool fetched) {
return fetchedStatus() == FetchedStatus::ForVariableBox; setStatutBit(k_fetchedFromConsoleMask, k_fetchedFromConsoleOffset, fetched);
} }
void Script::setContentFetchedFromConsole() { bool Script::fetchedForVariableBox() const {
setFetchedStatus(FetchedStatus::FromConsole); return getStatutBit(k_fetchedForVariableBoxMask);
} }
void Script::setContentFetchedForVariableBox() { void Script::setFetchedForVariableBox(bool fetched) {
setFetchedStatus(FetchedStatus::ForVariableBox); setStatutBit(k_fetchedForVariableBoxMask, k_fetchedForVariableBoxOffset, fetched);
} }
void Script::resetContentFetchedStatus() { bool Script::getStatutBit(uint8_t mask) const {
setFetchedStatus(FetchedStatus::None);
}
Script::FetchedStatus Script::fetchedStatus() const {
assert(!isNull()); assert(!isNull());
Data d = value(); Data d = value();
uint8_t status = (*statusFromData(d)) >> k_fetchedStatusOffset; return ((*StatusFromData(d)) & mask) != 0;
assert(status == static_cast<uint8_t>(FetchedStatus::None)
|| status == static_cast<uint8_t>(FetchedStatus::FromConsole)
|| status == static_cast<uint8_t>(FetchedStatus::ForVariableBox));
return static_cast<FetchedStatus>(status);
} }
void Script::setFetchedStatus(FetchedStatus fetchedStatus) { void Script::setStatutBit(uint8_t mask, uint8_t offset, bool statusBit) {
assert(!isNull()); assert(!isNull());
Data d = value(); Data d = value();
uint8_t * status = statusFromData(d); uint8_t * status = StatusFromData(d);
*status = ((*status) & ~k_fetchedStatusMask) | (static_cast<uint8_t>(fetchedStatus) << k_fetchedStatusOffset); //TODO Create and use a bit operations library *status = ((*status) & ~mask) | (static_cast<uint8_t>(statusBit) << offset); //TODO Create and use a bit operations library
setValue(d); setValue(d);
} }
uint8_t * Script::statusFromData(Data d) const {
return const_cast<uint8_t *>(static_cast<const uint8_t *>(d.buffer));
}
} }

View File

@@ -8,22 +8,22 @@ namespace Code {
/* Record: | Size | Name | Body | /* Record: | Size | Name | Body |
* Script: | | | Status | Content | * Script: | | | Status | Content |
* *
* Status is a byte long: xxxxxxxx
* ^^ ^
* FetchedStatus AutoImportationStatus
* *
* AutoImportationStatus is 1 if the script should be auto imported when the * |FetchedForVariableBoxBit
* Status is one byte long: xxxxxxxx
* ^ ^
* FetchedFromConsoleBit AutoImportationBit
*
* AutoImportationBit is 1 if the script should be auto imported when the
* console opens. * console opens.
* *
* FetchedStatus has two purposes: * FetchedFromConsoleBit is 1 if its content has been fetched from the console,
* - It is used to detect which scripts are imported in the console, so we can * so we can retrieve the correct variables afterwards in the variable box.
* retrieve the correct variables afterwards in the variable box. When a *
* script has been imported, its fetchedStatus value is * FetchedForVariableBoxBit is used to prevent circular importation problems,
* FetchedStatus::FromConsole. * such as scriptA importing scriptB, which imports scriptA. Once we get the
* - It is used to prevent circular importation problems, such as scriptA * variables from a script to put them in the variable box, we switch the bit to
* importing scriptB, which imports scriptA. Once we get the variables from a * 1 and won't reload it afterwards. */
* script to put them in the variable box, we switch the status to
* FetchedStatus::ForVariableBox and won't reload it afterwards. */
class Script : public Ion::Storage::Record { class Script : public Ion::Storage::Record {
private: private:
@@ -49,25 +49,22 @@ public:
bool autoImportationStatus() const; bool autoImportationStatus() const;
void toggleAutoimportationStatus(); void toggleAutoimportationStatus();
const char * content() const; const char * content() const;
bool contentFetchedFromConsole() const;
bool contentFetchedForVariableBox() const; /* Fetched status */
void setContentFetchedFromConsole(); bool fetchedFromConsole() const;
void setContentFetchedForVariableBox(); void setFetchedFromConsole(bool fetched);
void resetContentFetchedStatus(); bool fetchedForVariableBox() const;
void setFetchedForVariableBox(bool fetched);
private: private:
static constexpr uint8_t k_autoImportationStatusMask = 0b1; static constexpr uint8_t k_autoImportationStatusMask = 0b1;
static constexpr uint8_t k_fetchedStatusBits = 0b11; static constexpr uint8_t k_fetchedForVariableBoxOffset = 7;
static constexpr uint8_t k_fetchedStatusOffset = 6; static constexpr uint8_t k_fetchedFromConsoleOffset = 6;
static constexpr uint8_t k_fetchedStatusMask = k_fetchedStatusBits << k_fetchedStatusOffset; static constexpr uint8_t k_fetchedForVariableBoxMask = 0b1 << k_fetchedForVariableBoxOffset;
/* Fetched status */ static constexpr uint8_t k_fetchedFromConsoleMask = 0b1 << k_fetchedFromConsoleOffset;
enum class FetchedStatus : uint8_t {
None = 0, bool getStatutBit(uint8_t offset) const;
FromConsole = 1, void setStatutBit(uint8_t mask, uint8_t offset, bool value);
ForVariableBox = 2
};
FetchedStatus fetchedStatus() const;
void setFetchedStatus(FetchedStatus status);
uint8_t * statusFromData(Data d) const;
}; };
} }

View File

@@ -31,16 +31,24 @@ const char * ScriptStore::contentOfScript(const char * name, bool markAsFetched)
return nullptr; return nullptr;
} }
if (markAsFetched) { if (markAsFetched) {
script.setContentFetchedFromConsole(); script.setFetchedFromConsole(true);
} }
return script.content(); return script.content();
} }
void ScriptStore::clearFetchInformation() { void ScriptStore::clearVariableBoxFetchInformation() {
// TODO optimize fetches // TODO optimize fetches
const int scriptsCount = numberOfScripts(); const int scriptsCount = numberOfScripts();
for (int i = 0; i < scriptsCount; i++) { for (int i = 0; i < scriptsCount; i++) {
scriptAtIndex(i).resetContentFetchedStatus(); scriptAtIndex(i).setFetchedForVariableBox(false);
}
}
void ScriptStore::clearConsoleFetchInformation() {
// TODO optimize fetches
const int scriptsCount = numberOfScripts();
for (int i = 0; i < scriptsCount; i++) {
scriptAtIndex(i).setFetchedFromConsole(false);
} }
} }

View File

@@ -40,7 +40,8 @@ public:
/* MicroPython::ScriptProvider */ /* MicroPython::ScriptProvider */
const char * contentOfScript(const char * name, bool markAsFetched) override; const char * contentOfScript(const char * name, bool markAsFetched) override;
void clearFetchInformation() override; void clearVariableBoxFetchInformation();
void clearConsoleFetchInformation();
Ion::Storage::Record::ErrorStatus addScriptFromTemplate(const ScriptTemplate * scriptTemplate); Ion::Storage::Record::ErrorStatus addScriptFromTemplate(const ScriptTemplate * scriptTemplate);
private: private:

View File

@@ -158,7 +158,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha
// Reset the node counts // Reset the node counts
empty(); empty();
m_scriptStore->clearFetchInformation();
if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) {
textToAutocompleteLength = strlen(textToAutocomplete); textToAutocompleteLength = strlen(textToAutocomplete);
} }
@@ -180,8 +180,8 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha
/* Handle the FetchedStatus: we will import the current script variables in /* Handle the FetchedStatus: we will import the current script variables in
* loadCurrentVariablesInScript, so we do not want to import those variables * loadCurrentVariablesInScript, so we do not want to import those variables
* before, if any imported script also imported the current script. */ * before, if any imported script also imported the current script. */
assert(!script.contentFetchedFromConsole() && !script.contentFetchedForVariableBox()); assert(!script.fetchedFromConsole() && !script.fetchedForVariableBox());
script.setContentFetchedForVariableBox(); script.setFetchedForVariableBox(true);
// Load the imported and current variables // Load the imported and current variables
const char * scriptContent = script.content(); const char * scriptContent = script.content();
@@ -229,7 +229,7 @@ void VariableBoxController::loadVariablesImportedFromScripts() {
const int scriptsCount = m_scriptStore->numberOfScripts(); const int scriptsCount = m_scriptStore->numberOfScripts();
for (int i = 0; i < scriptsCount; i++) { for (int i = 0; i < scriptsCount; i++) {
Script script = m_scriptStore->scriptAtIndex(i); Script script = m_scriptStore->scriptAtIndex(i);
if (script.contentFetchedFromConsole()) { if (script.fetchedFromConsole()) {
loadGlobalAndImportedVariablesInScriptAsImported(script, nullptr, -1, false); loadGlobalAndImportedVariablesInScriptAsImported(script, nullptr, -1, false);
} }
} }
@@ -240,6 +240,7 @@ void VariableBoxController::empty() {
m_currentScriptNodesCount = 0; m_currentScriptNodesCount = 0;
m_importedNodesCount = 0; m_importedNodesCount = 0;
m_shortenResultCharCount = 0; m_shortenResultCharCount = 0;
m_scriptStore->clearVariableBoxFetchInformation();
} }
void VariableBoxController::insertAutocompletionResultAtIndex(int index) { void VariableBoxController::insertAutocompletionResultAtIndex(int index) {
@@ -628,7 +629,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont
} }
void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) {
if (script.contentFetchedForVariableBox()) { if (script.fetchedForVariableBox()) {
// We already fetched these script variables // We already fetched these script variables
return; return;
} }
@@ -674,7 +675,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Scr
nlr_pop(); nlr_pop();
} }
// Mark that we already fetched these script variables // Mark that we already fetched these script variables
script.setContentFetchedForVariableBox(); script.setFetchedForVariableBox(true);
} }
bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) {

View File

@@ -13,7 +13,6 @@ namespace MicroPython {
class ScriptProvider { class ScriptProvider {
public: public:
virtual const char * contentOfScript(const char * name, bool markAsFetched) = 0; virtual const char * contentOfScript(const char * name, bool markAsFetched) = 0;
virtual void clearFetchInformation() = 0;
}; };
class ExecutionEnvironment { class ExecutionEnvironment {