diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 3f016e830..759f5a663 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -191,37 +191,37 @@ public: TimeRepresentatives[] = { Representative("s", nullptr, NegativeLongScalePrefixes, NegativeLongScalePrefixesCount), - Representative("min", "60*s", + Representative("min", "60*_s", NoPrefix, NoPrefixCount), - Representative("h", "60*60*s", + Representative("h", "60*60*_s", NoPrefix, NoPrefixCount), - Representative("day", "24*60*60*s", + Representative("day", "24*60*60*_s", NoPrefix, NoPrefixCount), - Representative("week", "7*24*60*60*s", + Representative("week", "7*24*60*60*_s", NoPrefix, NoPrefixCount), - Representative("month", "30*7*24*60*60*s", + Representative("month", "30*7*24*60*60*_s", NoPrefix, NoPrefixCount), - Representative("year", "365.25*24*60*60*s", + Representative("year", "365.25*24*60*60*_s", NoPrefix, NoPrefixCount), }, DistanceRepresentatives[] = { Representative("m", nullptr, AllPrefixes, AllPrefixesCount), - Representative("ang", "10^-10*m", + Representative("ang", "10^-10*_m", NoPrefix, NoPrefixCount), //FIXME Codepoint - Representative("au", "149587870700*m", + Representative("au", "149587870700*_m", NoPrefix, NoPrefixCount), - Representative("ly", "299792458*m/s*year", + Representative("ly", "299792458*_m/_s*_year", NoPrefix, NoPrefixCount), - Representative("pc", "180*60*60/π*au", + Representative("pc", "180*60*60/π*_au", NoPrefix, NoPrefixCount), }, MassRepresentatives[] = { Representative("g", nullptr, AllPrefixes, AllPrefixesCount), - Representative("t", "1000kg", + Representative("t", "1000_kg", PositiveLongScalePrefixes, PositiveLongScalePrefixesCount), - Representative("Da", "(6.02214076*10^23*1000)^-1*kg", + Representative("Da", "(6.02214076*10^23*1000)^-1*_kg", NoPrefix, NoPrefixCount), }, CurrentRepresentatives[] = { @@ -241,15 +241,15 @@ public: NoPrefix, NoPrefixCount), }, FrequencyRepresentatives[] = { - Representative("Hz", "s^-1", + Representative("Hz", "_s^-1", PositiveLongScalePrefixes, PositiveLongScalePrefixesCount), }, ForceRepresentatives[] = { - Representative("N", "kg*m*s^-2", + Representative("N", "_kg*_m*_s^-2", AllPrefixes, AllPrefixesCount), }, PressureRepresentatives[] = { - Representative("Pa", "kg*m^-1*s^-2", + Representative("Pa", "_kg*_m^-1*_s^-2", NoPrefix, NoPrefixCount), Representative("bar", "1000hPa", NoPrefix, NoPrefixCount), @@ -257,57 +257,57 @@ public: NoPrefix, NoPrefixCount), }, EnergyRepresentatives[] = { - Representative("J", "kg*m^2*s^-2", + Representative("J", "_kg*_m^2*_s^-2", AllPrefixes, AllPrefixesCount), Representative("eV", "1.602176634*10^−19*J", AllPrefixes, AllPrefixesCount), }, PowerRepresentatives[] = { - Representative("W", "kg*m^2*s^-3", + Representative("W", "_kg*_m^2*_s^-3", AllPrefixes, AllPrefixesCount), }, ElectricChargeRepresentatives[] = { - Representative("C", "A*s", + Representative("C", "_A*_s", AllPrefixes, AllPrefixesCount), }, ElectricPotentialRepresentatives[] = { - Representative("V", "kg*m^2*s^-3*A^-1", + Representative("V", "_kg*_m^2*_s^-3*_A^-1", AllPrefixes, AllPrefixesCount), }, ElectricCapacitanceRepresentatives[] = { - Representative("F", "A^2*s^4*kg^-1*m^-2", + Representative("F", "_A^2*_s^4*_kg^-1*_m^-2", AllPrefixes, AllPrefixesCount), }, ElectricResistanceRepresentatives[] = { - Representative("Ohm", "kg*m^2*s^-3*A^-2", + Representative("Ohm", "_kg*_m^2*_s^-3*_A^-2", AllPrefixes, AllPrefixesCount), //FIXME Omega CodePoint? }, ElectricConductanceRepresentatives[] = { - Representative("S", "A^2*s^3*kg^-1*m^-2", + Representative("S", "_A^2*_s^3*_kg^-1*_m^-2", AllPrefixes, AllPrefixesCount), }, MagneticFluxRepresentatives[] = { - Representative("Wb", "kg*m^2*s^-2*A^-1", + Representative("Wb", "_kg*_m^2*_s^-2*_A^-1", NoPrefix, NoPrefixCount), }, MagneticFieldRepresentatives[] = { - Representative("T", "kg*s^-2*A^-1", + Representative("T", "_kg*_s^-2*_A^-1", NoPrefix, NoPrefixCount), }, InductanceRepresentatives[] = { - Representative("H", "kg*m^2*s^-2*A^-2", + Representative("H", "_kg*_m^2*_s^-2*_A^-2", NoPrefix, NoPrefixCount), }, CatalyticActivityRepresentatives[] = { - Representative("kat", "mol*s^-1", + Representative("kat", "_mol*_s^-1", NoPrefix, NoPrefixCount), }, SurfaceRepresentatives[] = { - Representative("ha", "10^4*m^2", + Representative("ha", "10^4*_m^2", NoPrefix, NoPrefixCount), }, VolumeRepresentatives[] = { - Representative("L", "10^-3*m^3", + Representative("L", "10^-3*_m^3", NoPrefix, NoPrefixCount), }; static constexpr const Dimension DimensionTable[] = { diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 6086bb060..d4a02ab3b 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -18,12 +18,8 @@ Expression Parser::parse(Context * context) { } bool Parser::IsReservedName(const char * name, size_t nameLength) { - const Unit::Dimension * unitDimension = nullptr; - const Unit::Representative * unitRepresentative = nullptr; - const Unit::Prefix * unitPrefix = nullptr; return GetReservedFunction(name, nameLength) != nullptr - || IsSpecialIdentifierName(name, nameLength) - || Unit::CanParse(name, nameLength, &unitDimension, &unitRepresentative, &unitPrefix); + || IsSpecialIdentifierName(name, nameLength); } // Private @@ -88,6 +84,7 @@ Expression Parser::parseUntil(Context * context, Token::Type stoppingType) { &Parser::parseNumber, // Token::Number &Parser::parseNumber, // Token::BinaryNumber &Parser::parseNumber, // Token::HexadecimalNumber + &Parser::parseUnit, // Token::Unit &Parser::parseIdentifier, // Token::Identifier &Parser::parseUnexpected // Token::Undefined }; @@ -134,13 +131,15 @@ bool Parser::nextTokenHasPrecedenceOver(Token::Type stoppingType) { void Parser::isThereImplicitMultiplication() { /* This function is called at the end of - * parseNumber, parseIdentifier, parseFactorial, parseMatrix, parseLeftParenthesis - * in order to check whether it should be followed by a Token::ImplicitTimes. + * parseNumber, parseIdentifier, parseUnit, parseFactorial, parseMatrix, + * parseLeftParenthesis in order to check whether it should be followed by a + * Token::ImplicitTimes. * In that case, m_pendingImplicitMultiplication is set to true, * so that popToken, popTokenIfType, nextTokenHasPrecedenceOver can handle implicit multiplication. */ m_pendingImplicitMultiplication = ( m_nextToken.is(Token::Number) || m_nextToken.is(Token::Constant) || + m_nextToken.is(Token::Unit) || m_nextToken.is(Token::Identifier) || m_nextToken.is(Token::LeftParenthesis) || m_nextToken.is(Token::LeftSystemParenthesis) || @@ -336,10 +335,27 @@ void Parser::parseBang(Context * context, Expression & leftHandSide, Token::Type } void Parser::parseConstant(Context * context, Expression & leftHandSide, Token::Type stoppingType) { + assert(leftHandSide.isUninitialized()); leftHandSide = Constant::Builder(m_currentToken.codePoint()); isThereImplicitMultiplication(); } +void Parser::parseUnit(Context * context, Expression & leftHandSide, Token::Type stoppingType) { + assert(leftHandSide.isUninitialized()); + const Unit::Dimension * unitDimension = nullptr; + const Unit::Representative * unitRepresentative = nullptr; + const Unit::Prefix * unitPrefix = nullptr; leftHandSide = Constant::Builder(m_currentToken.codePoint()); + if (Unit::CanParse(m_currentToken.text(), m_currentToken.length(), + &unitDimension, &unitRepresentative, &unitPrefix)) + { + leftHandSide = Unit::Builder(unitDimension, unitRepresentative, unitPrefix); + } else { + m_status = Status::Error; // Unit does not exist + return; + } + isThereImplicitMultiplication(); +} + void Parser::parseReservedFunction(Context * context, Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper) { const char * name = (**functionHelper).name(); Expression parameters = parseFunctionParameters(context); @@ -477,22 +493,12 @@ void Parser::parseCustomIdentifier(Context * context, Expression & leftHandSide, } void Parser::parseIdentifier(Context * context, Expression & leftHandSide, Token::Type stoppingType) { - if (!leftHandSide.isUninitialized()) { - m_status = Status::Error; //FIXME - return; - } + assert(leftHandSide.isUninitialized()); const Expression::FunctionHelper * const * functionHelper = GetReservedFunction(m_currentToken.text(), m_currentToken.length()); - const Unit::Dimension * unitDimension = nullptr; - const Unit::Representative * unitRepresentative = nullptr; - const Unit::Prefix * unitPrefix = nullptr; if (functionHelper != nullptr) { parseReservedFunction(context, leftHandSide, functionHelper); } else if (IsSpecialIdentifierName(m_currentToken.text(), m_currentToken.length())) { parseSpecialIdentifier(context, leftHandSide); - } else if (Unit::CanParse(m_currentToken.text(), m_currentToken.length(), - &unitDimension, &unitRepresentative, &unitPrefix)) - { - leftHandSide = Unit::Builder(unitDimension, unitRepresentative, unitPrefix); } else { parseCustomIdentifier(context, leftHandSide, m_currentToken.text(), m_currentToken.length(), false); } diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index b286a150e..ebb99aa99 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -48,6 +48,7 @@ private: void parseUnexpected(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); void parseNumber(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); void parseConstant(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseUnit(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); void parseIdentifier(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); void parseEmpty(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); void parseMatrix(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); diff --git a/poincare/src/parsing/token.h b/poincare/src/parsing/token.h index 11e089d05..d815886a5 100644 --- a/poincare/src/parsing/token.h +++ b/poincare/src/parsing/token.h @@ -50,6 +50,7 @@ public: Number, BinaryNumber, HexadecimalNumber, + Unit, Identifier, Undefined }; diff --git a/poincare/src/parsing/tokenizer.cpp b/poincare/src/parsing/tokenizer.cpp index 99cb14186..67f838d72 100644 --- a/poincare/src/parsing/tokenizer.cpp +++ b/poincare/src/parsing/tokenizer.cpp @@ -147,6 +147,11 @@ Token Tokenizer::popToken() { if (!nextCodePointIsNeitherDotNorDigit) { return popNumber(); } + if (c == '_') { + Token result(Token::Unit); + result.setString(start + 1, popIdentifier()); + return result; + } if (isLetter(c)) { Token result(Token::Identifier); result.setString(start, 1 + popIdentifier()); // We already popped 1 code point diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 4a79aa1e0..c3f95f994 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -83,6 +83,9 @@ int UnitNode::simplificationOrderSameType(const ExpressionNode * e, bool ascendi } Layout UnitNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + /* TODO: compute the bufferSize more precisely... So far the longest unit is + * "month" of size 6 but later, we might add unicode to represent ohm or µ + * which would change the required size?*/ static constexpr size_t bufferSize = 10; char buffer[bufferSize]; int length = serialize(buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits); @@ -91,7 +94,11 @@ Layout UnitNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int } int UnitNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - return m_representative->serialize(buffer, bufferSize, m_prefix); + assert(bufferSize >= 0); + int underscoreLength = minInt(strlcpy(buffer, "_", bufferSize), bufferSize - 1); + buffer += underscoreLength; + bufferSize -= underscoreLength; + return underscoreLength + m_representative->serialize(buffer, bufferSize, m_prefix); } template