mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user