[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);
MicroPython::registerScriptProvider(m_scriptStore);
m_importScriptsWhenViewAppears = m_autoImportScripts;
m_scriptStore->clearFetchInformation();
m_scriptStore->clearConsoleFetchInformation();
}
return true;
}

View File

@@ -65,16 +65,18 @@ bool Script::nameCompliant(const char * name) {
return false;
}
uint8_t * StatusFromData(Script::Data d) {
return const_cast<uint8_t *>(static_cast<const uint8_t *>(d.buffer));
}
bool Script::autoImportationStatus() const {
assert(!isNull());
Data d = value();
return (*statusFromData(d) & k_autoImportationStatusMask) == 1;
return getStatutBit(k_autoImportationStatusMask);
}
void Script::toggleAutoimportationStatus() {
assert(!isNull());
Data d = value();
*statusFromData(d) ^= k_autoImportationStatusMask;
*StatusFromData(d) ^= k_autoImportationStatusMask;
setValue(d);
}
@@ -83,46 +85,34 @@ const char * Script::content() const {
return ((const char *)d.buffer) + StatusSize();
}
bool Script::contentFetchedFromConsole() const {
return fetchedStatus() == FetchedStatus::FromConsole;
bool Script::fetchedFromConsole() const {
return getStatutBit(k_fetchedFromConsoleMask);
}
bool Script::contentFetchedForVariableBox() const {
return fetchedStatus() == FetchedStatus::ForVariableBox;
void Script::setFetchedFromConsole(bool fetched) {
setStatutBit(k_fetchedFromConsoleMask, k_fetchedFromConsoleOffset, fetched);
}
void Script::setContentFetchedFromConsole() {
setFetchedStatus(FetchedStatus::FromConsole);
bool Script::fetchedForVariableBox() const {
return getStatutBit(k_fetchedForVariableBoxMask);
}
void Script::setContentFetchedForVariableBox() {
setFetchedStatus(FetchedStatus::ForVariableBox);
void Script::setFetchedForVariableBox(bool fetched) {
setStatutBit(k_fetchedForVariableBoxMask, k_fetchedForVariableBoxOffset, fetched);
}
void Script::resetContentFetchedStatus() {
setFetchedStatus(FetchedStatus::None);
}
Script::FetchedStatus Script::fetchedStatus() const {
bool Script::getStatutBit(uint8_t mask) const {
assert(!isNull());
Data d = value();
uint8_t status = (*statusFromData(d)) >> k_fetchedStatusOffset;
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);
return ((*StatusFromData(d)) & mask) != 0;
}
void Script::setFetchedStatus(FetchedStatus fetchedStatus) {
void Script::setStatutBit(uint8_t mask, uint8_t offset, bool statusBit) {
assert(!isNull());
Data d = value();
uint8_t * status = statusFromData(d);
*status = ((*status) & ~k_fetchedStatusMask) | (static_cast<uint8_t>(fetchedStatus) << k_fetchedStatusOffset); //TODO Create and use a bit operations library
uint8_t * status = StatusFromData(d);
*status = ((*status) & ~mask) | (static_cast<uint8_t>(statusBit) << offset); //TODO Create and use a bit operations library
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 |
* 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.
*
* FetchedStatus has two purposes:
* - It is used to detect which scripts are imported in the console, so we can
* retrieve the correct variables afterwards in the variable box. When a
* script has been imported, its fetchedStatus value is
* FetchedStatus::FromConsole.
* - It is used to prevent circular importation problems, such as scriptA
* importing scriptB, which imports scriptA. Once we get the variables from a
* script to put them in the variable box, we switch the status to
* FetchedStatus::ForVariableBox and won't reload it afterwards. */
* FetchedFromConsoleBit is 1 if its content has been fetched from the console,
* so we can retrieve the correct variables afterwards in the variable box.
*
* FetchedForVariableBoxBit is used to prevent circular importation problems,
* such as scriptA importing scriptB, which imports scriptA. Once we get the
* variables from a script to put them in the variable box, we switch the bit to
* 1 and won't reload it afterwards. */
class Script : public Ion::Storage::Record {
private:
@@ -49,25 +49,22 @@ public:
bool autoImportationStatus() const;
void toggleAutoimportationStatus();
const char * content() const;
bool contentFetchedFromConsole() const;
bool contentFetchedForVariableBox() const;
void setContentFetchedFromConsole();
void setContentFetchedForVariableBox();
void resetContentFetchedStatus();
/* Fetched status */
bool fetchedFromConsole() const;
void setFetchedFromConsole(bool fetched);
bool fetchedForVariableBox() const;
void setFetchedForVariableBox(bool fetched);
private:
static constexpr uint8_t k_autoImportationStatusMask = 0b1;
static constexpr uint8_t k_fetchedStatusBits = 0b11;
static constexpr uint8_t k_fetchedStatusOffset = 6;
static constexpr uint8_t k_fetchedStatusMask = k_fetchedStatusBits << k_fetchedStatusOffset;
/* Fetched status */
enum class FetchedStatus : uint8_t {
None = 0,
FromConsole = 1,
ForVariableBox = 2
};
FetchedStatus fetchedStatus() const;
void setFetchedStatus(FetchedStatus status);
uint8_t * statusFromData(Data d) const;
static constexpr uint8_t k_fetchedForVariableBoxOffset = 7;
static constexpr uint8_t k_fetchedFromConsoleOffset = 6;
static constexpr uint8_t k_fetchedForVariableBoxMask = 0b1 << k_fetchedForVariableBoxOffset;
static constexpr uint8_t k_fetchedFromConsoleMask = 0b1 << k_fetchedFromConsoleOffset;
bool getStatutBit(uint8_t offset) const;
void setStatutBit(uint8_t mask, uint8_t offset, bool value);
};
}

View File

@@ -31,16 +31,24 @@ const char * ScriptStore::contentOfScript(const char * name, bool markAsFetched)
return nullptr;
}
if (markAsFetched) {
script.setContentFetchedFromConsole();
script.setFetchedFromConsole(true);
}
return script.content();
}
void ScriptStore::clearFetchInformation() {
void ScriptStore::clearVariableBoxFetchInformation() {
// TODO optimize fetches
const int scriptsCount = numberOfScripts();
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 */
const char * contentOfScript(const char * name, bool markAsFetched) override;
void clearFetchInformation() override;
void clearVariableBoxFetchInformation();
void clearConsoleFetchInformation();
Ion::Storage::Record::ErrorStatus addScriptFromTemplate(const ScriptTemplate * scriptTemplate);
private:

View File

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

View File

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