[poincare/parser] Identifier is not already function -> symbol

We check the context: if an identifier is already a function, we
interpret it as such, otherwise it is a symbol.
This way, in the Equation app, x(x+1) is interpreted as x*(x+1)
This commit is contained in:
Léa Saviot
2020-01-16 11:04:58 +01:00
parent 756eeeb2d8
commit 9d6bab092f
6 changed files with 83 additions and 28 deletions

View File

@@ -32,6 +32,16 @@ void GlobalContext::DestroyRecordsBaseNamedWithoutExtension(const char * baseNam
}
}
Context::SymbolAbstractType GlobalContext::expressionTypeForIdentifier(const char * identifier, int length) {
const char * extension = Ion::Storage::sharedStorage()->extensionOfRecordBaseNamedWithExtensions(identifier, length, k_extensions, k_numberOfExtensions);
if (extension == nullptr) {
return Context::SymbolAbstractType::None;
}
assert(k_numberOfExtensions == 2);
assert(extension == Ion::Storage::expExtension || extension == Ion::Storage::funcExtension);
return extension == Ion::Storage::expExtension ? Context::SymbolAbstractType::Symbol : Context::SymbolAbstractType::Function;
}
const Expression GlobalContext::expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone) {
Ion::Storage::Record r = SymbolAbstractRecordWithBaseName(symbol.name());
return ExpressionForSymbolAndRecord(symbol, r);

View File

@@ -27,6 +27,7 @@ public:
/* Expression for symbol
* The expression recorded in global context is already an expression.
* Otherwise, we would need the context and the angle unit to evaluate it */
SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) override;
const Poincare::Expression expressionForSymbolAbstract(const Poincare::SymbolAbstract & symbol, bool clone) override;
void setExpressionForSymbolAbstract(const Poincare::Expression & expression, const Poincare::SymbolAbstract & symbol) override;

View File

@@ -115,6 +115,7 @@ public:
Record recordNamed(const char * fullName);
Record recordBaseNamedWithExtension(const char * baseName, const char * extension);
Record recordBaseNamedWithExtensions(const char * baseName, const char * const extension[], size_t numberOfExtensions);
const char * extensionOfRecordBaseNamedWithExtensions(const char * baseName, int baseNameLength, const char * const extension[], size_t numberOfExtensions);
// Record destruction
void destroyAllRecords();
@@ -169,7 +170,9 @@ private:
}
return RecordIterator((char *)m_buffer);
};
RecordIterator end() const { return RecordIterator(nullptr); };
RecordIterator end() const { return RecordIterator(nullptr); }
Record privateRecordAndExtensionOfRecordBaseNamedWithExtensions(const char * baseName, const char * const extensions[], size_t numberOfExtensions, const char * * extensionResult = nullptr, int baseNameLength = -1);
uint32_t m_magicHeader;
char m_buffer[k_storageSize];

View File

@@ -268,30 +268,13 @@ Storage::Record Storage::recordBaseNamedWithExtension(const char * baseName, con
}
Storage::Record Storage::recordBaseNamedWithExtensions(const char * baseName, const char * const extensions[], size_t numberOfExtensions) {
size_t nameLength = strlen(baseName);
{
const char * lastRetrievedRecordFullName = fullNameOfRecordStarting(m_lastRecordRetrievedPointer);
if (m_lastRecordRetrievedPointer != nullptr && strncmp(baseName, lastRetrievedRecordFullName, nameLength) == 0) {
for (size_t i = 0; i < numberOfExtensions; i++) {
if (strcmp(lastRetrievedRecordFullName+nameLength+1 /*+1 to pass the dot*/, extensions[i]) == 0) {
assert(UTF8Helper::CodePointIs(lastRetrievedRecordFullName + nameLength, '.'));
return m_lastRecordRetrieved;
}
}
}
}
for (char * p : *this) {
const char * currentName = fullNameOfRecordStarting(p);
if (strncmp(baseName, currentName, nameLength) == 0) {
for (size_t i = 0; i < numberOfExtensions; i++) {
if (strcmp(currentName+nameLength+1 /*+1 to pass the dot*/, extensions[i]) == 0) {
assert(UTF8Helper::CodePointIs(currentName + nameLength, '.'));
return Record(currentName);
}
}
}
}
return Record();
return privateRecordAndExtensionOfRecordBaseNamedWithExtensions(baseName, extensions, numberOfExtensions);
}
const char * Storage::extensionOfRecordBaseNamedWithExtensions(const char * baseName, int baseNameLength, const char * const extensions[], size_t numberOfExtensions) {
const char * result = nullptr;
privateRecordAndExtensionOfRecordBaseNamedWithExtensions(baseName, extensions, numberOfExtensions, &result, baseNameLength);
return result;
}
void Storage::destroyAllRecords() {
@@ -566,6 +549,42 @@ bool Storage::slideBuffer(char * position, int delta) {
return true;
}
Storage::Record Storage::privateRecordAndExtensionOfRecordBaseNamedWithExtensions(const char * baseName, const char * const extensions[], size_t numberOfExtensions, const char * * extensionResult, int baseNameLength) {
size_t nameLength = baseNameLength < 0 ? strlen(baseName) : baseNameLength;
{
const char * lastRetrievedRecordFullName = fullNameOfRecordStarting(m_lastRecordRetrievedPointer);
if (m_lastRecordRetrievedPointer != nullptr && strncmp(baseName, lastRetrievedRecordFullName, nameLength) == 0) {
for (size_t i = 0; i < numberOfExtensions; i++) {
if (strcmp(lastRetrievedRecordFullName+nameLength+1 /*+1 to pass the dot*/, extensions[i]) == 0) {
assert(UTF8Helper::CodePointIs(lastRetrievedRecordFullName + nameLength, '.'));
if (extensionResult != nullptr) {
*extensionResult = extensions[i];
}
return m_lastRecordRetrieved;
}
}
}
}
for (char * p : *this) {
const char * currentName = fullNameOfRecordStarting(p);
if (strncmp(baseName, currentName, nameLength) == 0) {
for (size_t i = 0; i < numberOfExtensions; i++) {
if (strcmp(currentName+nameLength+1 /*+1 to pass the dot*/, extensions[i]) == 0) {
assert(UTF8Helper::CodePointIs(currentName + nameLength, '.'));
if (extensionResult != nullptr) {
*extensionResult = extensions[i];
}
return Record(currentName);
}
}
}
}
if (extensionResult != nullptr) {
*extensionResult = nullptr;
}
return Record();
}
Storage::RecordIterator & Storage::RecordIterator::operator++() {
assert(m_recordStart);
record_size_t size = StorageHelper::unalignedShort(m_recordStart);

View File

@@ -1,6 +1,9 @@
#ifndef POINCARE_CONTEXT_H
#define POINCARE_CONTEXT_H
#include <stdint.h>
#include <assert.h>
namespace Poincare {
class Expression;
@@ -8,6 +11,12 @@ class SymbolAbstract;
class Context {
public:
enum class SymbolAbstractType : uint8_t {
None,
Function,
Symbol
};
virtual SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) { assert(false); return SymbolAbstractType::None; }
virtual const Expression expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone) = 0;
virtual void setExpressionForSymbolAbstract(const Expression & expression, const SymbolAbstract & symbol) = 0;
};

View File

@@ -284,7 +284,7 @@ void Parser::parseStore(Context * context, Expression & leftHandSide, Token::Typ
return;
}
Expression rightHandSide;
parseCustomIdentifier(context, rightHandSide, m_currentToken.text(), m_currentToken.length());
parseCustomIdentifier(context, rightHandSide, m_currentToken.text(), m_currentToken.length(), true);
if (m_status != Status::Progress) {
return;
}
@@ -421,12 +421,25 @@ void Parser::parseSpecialIdentifier(Context * context, Expression & leftHandSide
}
}
void Parser::parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length) {
void Parser::parseCustomIdentifier(Context * context, Expression & leftHandSide, const char * name, size_t length, bool symbolPlusParenthesesAreFunctions) {
if (length >= SymbolAbstract::k_maxNameSize) {
m_status = Status::Error; // Identifier name too long.
return;
}
bool poppedParenthesisIsSystem = false;
/* Check the context: if the identifier does not already exist as a function,
* interpret it as a symbol, even if there are parentheses afterwards. */
Context::SymbolAbstractType idType = Context::SymbolAbstractType::None;
if (context != nullptr && !symbolPlusParenthesesAreFunctions) {
idType = context->expressionTypeForIdentifier(name, length);
if (idType != Context::SymbolAbstractType::Function) {
leftHandSide = Symbol::Builder(name, length);
return;
}
}
/* If the identifier is followed by parentheses it is a function, else it is a
* symbol. The parentheses can be system parentheses, if serialized using
* SerializationHelper::Prefix. */
@@ -470,7 +483,7 @@ void Parser::parseIdentifier(Context * context, Expression & leftHandSide, Token
} else if (IsSpecialIdentifierName(m_currentToken.text(), m_currentToken.length())) {
parseSpecialIdentifier(context, leftHandSide);
} else {
parseCustomIdentifier(context, leftHandSide, m_currentToken.text(), m_currentToken.length());
parseCustomIdentifier(context, leftHandSide, m_currentToken.text(), m_currentToken.length(), false);
}
isThereImplicitMultiplication();
}