mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[poincare] Parsing: expression -> expression is always parsed but return
"undef" when the left expression is neither a custom variable or function nor a unit. This makes the behaviour consistent on theses expressions: 2 -> a+a 2 -> 2*a
This commit is contained in:
@@ -276,32 +276,29 @@ void Parser::parseRightwardsArrow(Expression & leftHandSide, Token::Type stoppin
|
||||
return;
|
||||
}
|
||||
// At this point, m_currentToken is Token::RightwardsArrow.
|
||||
bool parseId = m_nextToken.is(Token::Identifier) && !IsReservedName(m_nextToken.text(), m_nextToken.length());
|
||||
if (parseId) {
|
||||
popToken();
|
||||
// Try parsing a store
|
||||
Expression rightHandSide;
|
||||
parseCustomIdentifier(rightHandSide, m_currentToken.text(), m_currentToken.length(), true);
|
||||
if (m_status != Status::Progress) {
|
||||
return;
|
||||
}
|
||||
if (!m_nextToken.is(Token::EndOfStream)
|
||||
|| !(rightHandSide.type() == ExpressionNode::Type::Symbol
|
||||
|| (rightHandSide.type() == ExpressionNode::Type::Function
|
||||
&& rightHandSide.childAtIndex(0).type() == ExpressionNode::Type::Symbol)))
|
||||
{
|
||||
m_status = Status::Error; // Store expects a single symbol or function.
|
||||
return;
|
||||
}
|
||||
const char * tokenName = m_nextToken.text();
|
||||
size_t tokenNameLength = m_nextToken.length();
|
||||
/* Right part of the RightwardsArrow are either a Symbol, a Function or units.
|
||||
* Even undefined function "plouf(x)" should be interpreted as function and
|
||||
* not as a multiplication. */
|
||||
m_symbolPlusParenthesesAreFunctions = true;
|
||||
Expression rightHandSide = parseUntil(stoppingType);
|
||||
m_symbolPlusParenthesesAreFunctions = false;
|
||||
if (m_status != Status::Progress) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pattern : "-> a" or "-> f(x)" Try parsing a store
|
||||
if (m_nextToken.is(Token::EndOfStream) &&
|
||||
(rightHandSide.type() == ExpressionNode::Type::Symbol
|
||||
|| (rightHandSide.type() == ExpressionNode::Type::Function
|
||||
&& rightHandSide.childAtIndex(0).type() == ExpressionNode::Type::Symbol)) &&
|
||||
!IsReservedName(tokenName, tokenNameLength)) {
|
||||
leftHandSide = Store::Builder(leftHandSide, static_cast<SymbolAbstract&>(rightHandSide));
|
||||
return;
|
||||
}
|
||||
// Try parsing a unit convert
|
||||
Expression rightHandSide = parseUntil(stoppingType);
|
||||
if (m_status != Status::Progress) {
|
||||
return;
|
||||
}
|
||||
if (!m_nextToken.is(Token::EndOfStream) || rightHandSide.isUninitialized() || rightHandSide.type() == ExpressionNode::Type::Store || rightHandSide.type() == ExpressionNode::Type::UnitConvert) {
|
||||
if (!m_nextToken.is(Token::EndOfStream) || rightHandSide.isUninitialized() || rightHandSide.type() == ExpressionNode::Type::Store || rightHandSide.type() == ExpressionNode::Type::UnitConvert || rightHandSide.type() == ExpressionNode::Type::Equal) {
|
||||
m_status = Status::Error; // UnitConvert expect a unit on the right.
|
||||
return;
|
||||
}
|
||||
@@ -451,19 +448,19 @@ void Parser::parseSpecialIdentifier(Expression & leftHandSide) {
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length, bool symbolPlusParenthesesAreFunctions) {
|
||||
void Parser::parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length) {
|
||||
if (length >= SymbolAbstract::k_maxNameSize) {
|
||||
m_status = Status::Error; // Identifier name too long.
|
||||
return;
|
||||
}
|
||||
bool poppedParenthesisIsSystem = false;
|
||||
|
||||
/* If symbolPlusParenthesesAreFunctions is false, check the context: if the
|
||||
/* If m_symbolPlusParenthesesAreFunctions is 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 (m_context != nullptr && !symbolPlusParenthesesAreFunctions) {
|
||||
if (m_context != nullptr && !m_symbolPlusParenthesesAreFunctions) {
|
||||
idType = m_context->expressionTypeForIdentifier(name, length);
|
||||
if (idType != Context::SymbolAbstractType::Function) {
|
||||
leftHandSide = Symbol::Builder(name, length);
|
||||
@@ -511,7 +508,7 @@ void Parser::parseIdentifier(Expression & leftHandSide, Token::Type stoppingType
|
||||
} else if (IsSpecialIdentifierName(m_currentToken.text(), m_currentToken.length())) {
|
||||
parseSpecialIdentifier(leftHandSide);
|
||||
} else {
|
||||
parseCustomIdentifier(leftHandSide, m_currentToken.text(), m_currentToken.length(), false);
|
||||
parseCustomIdentifier(leftHandSide, m_currentToken.text(), m_currentToken.length());
|
||||
}
|
||||
isThereImplicitMultiplication();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ public:
|
||||
m_tokenizer(text),
|
||||
m_currentToken(Token(Token::Undefined)),
|
||||
m_nextToken(m_tokenizer.popToken()),
|
||||
m_pendingImplicitMultiplication(false) {}
|
||||
m_pendingImplicitMultiplication(false),
|
||||
m_symbolPlusParenthesesAreFunctions(false) {}
|
||||
|
||||
Expression parse();
|
||||
Status getStatus() const { return m_status; }
|
||||
@@ -75,7 +76,7 @@ private:
|
||||
void parseReservedFunction(Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper);
|
||||
void parseSpecialIdentifier(Expression & leftHandSide);
|
||||
void parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter1, Token::Type rightDelimiter1, Token::Type leftDelimiter2, Token::Type rightDelimiter2);
|
||||
void parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length, bool symbolPlusParenthesesAreFunctions);
|
||||
void parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length);
|
||||
void defaultParseLeftParenthesis(bool isSystemParenthesis, Expression & leftHandSide, Token::Type stoppingType);
|
||||
|
||||
// Data members
|
||||
@@ -88,6 +89,7 @@ private:
|
||||
Token m_currentToken;
|
||||
Token m_nextToken;
|
||||
bool m_pendingImplicitMultiplication;
|
||||
bool m_symbolPlusParenthesesAreFunctions;
|
||||
|
||||
// The array of reserved functions' helpers
|
||||
static constexpr const Expression::FunctionHelper * s_reservedFunctions[] = {
|
||||
|
||||
@@ -239,6 +239,7 @@ QUIZ_CASE(poincare_parsing_parse) {
|
||||
assert_text_not_parsable("t0000000");
|
||||
assert_text_not_parsable("[[t0000000[");
|
||||
assert_text_not_parsable("0→x=0");
|
||||
assert_text_not_parsable("0→3=0");
|
||||
assert_text_not_parsable("0=0→x");
|
||||
assert_text_not_parsable("1ᴇ2ᴇ3");
|
||||
assert_text_not_parsable("0b001112");
|
||||
@@ -428,9 +429,7 @@ QUIZ_CASE(poincare_parsing_parse_store) {
|
||||
assert_text_not_parsable("1→\1"); // UnknownX
|
||||
assert_text_not_parsable("1→\2"); // UnknownN
|
||||
assert_text_not_parsable("1→acos");
|
||||
assert_text_not_parsable("1→f(2)");
|
||||
assert_text_not_parsable("1→f(f)");
|
||||
assert_text_not_parsable("3→f(g(4))");
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_parsing_parse_unit_convert) {
|
||||
@@ -438,20 +437,6 @@ QUIZ_CASE(poincare_parsing_parse_unit_convert) {
|
||||
assert_parsed_expression_is("1→_m", UnitConvert::Builder(BasedInteger::Builder(1), meter));
|
||||
Expression kilometer = Expression::Parse("_km", nullptr);
|
||||
assert_parsed_expression_is("1→_m/_km", UnitConvert::Builder(BasedInteger::Builder(1), Division::Builder(meter, kilometer)));
|
||||
|
||||
assert_simplify("_m→a", Radian, Real);
|
||||
assert_simplify("_m→b", Radian, Real);
|
||||
assert_text_not_parsable("1_km→a×b");
|
||||
|
||||
assert_simplify("2→a");
|
||||
assert_text_not_parsable("3_m→a×_km");
|
||||
assert_simplify("2→f(x)");
|
||||
assert_text_not_parsable("3_m→f(2)×_km");
|
||||
|
||||
// Clean the storage for other tests
|
||||
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
|
||||
Ion::Storage::sharedStorage()->recordNamed("b.exp").destroy();
|
||||
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_parsing_implicit_multiplication) {
|
||||
|
||||
@@ -1022,6 +1022,9 @@ QUIZ_CASE(poincare_simplification_unit_convert) {
|
||||
assert_parsed_expression_simplify_to("4×_N×3_N×2_N→_N^3", "24×_N^3");
|
||||
|
||||
assert_parsed_expression_simplify_to("1→2", Undefined::Name());
|
||||
assert_parsed_expression_simplify_to("1→a+a", Undefined::Name());
|
||||
assert_parsed_expression_simplify_to("1→f(2)", Undefined::Name());
|
||||
assert_parsed_expression_simplify_to("1→f(g(4))", Undefined::Name());
|
||||
assert_parsed_expression_simplify_to("1→u(n)", Undefined::Name());
|
||||
assert_parsed_expression_simplify_to("1→u(n+1)", Undefined::Name());
|
||||
assert_parsed_expression_simplify_to("1→v(n)", Undefined::Name());
|
||||
@@ -1040,6 +1043,20 @@ QUIZ_CASE(poincare_simplification_unit_convert) {
|
||||
assert_parsed_expression_simplify_to("1→3_m", Undefined::Name());
|
||||
assert_parsed_expression_simplify_to("4→_km/_m", Undefined::Name());
|
||||
assert_parsed_expression_simplify_to("3×_min→_s+1-1", Undefined::Name());
|
||||
|
||||
assert_simplify("_m→a", Radian, Real);
|
||||
assert_simplify("_m→b", Radian, Real);
|
||||
assert_parsed_expression_simplify_to("1_km→a×b", Undefined::Name());
|
||||
|
||||
assert_simplify("2→a");
|
||||
assert_parsed_expression_simplify_to("3_m→a×_km", Undefined::Name());
|
||||
assert_simplify("2→f(x)");
|
||||
assert_parsed_expression_simplify_to("3_m→f(2)×_km", Undefined::Name());
|
||||
|
||||
// Clean the storage for other tests
|
||||
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
|
||||
Ion::Storage::sharedStorage()->recordNamed("b.exp").destroy();
|
||||
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_simplification_complex_format) {
|
||||
|
||||
Reference in New Issue
Block a user