diff --git a/poincare/Makefile b/poincare/Makefile index 788518f79..de32ca59a 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -4,23 +4,28 @@ objs += $(addprefix poincare/src/,\ binary_operation.o\ commutative_operation.o\ context.o\ + cosinus.o\ expression.o\ expression_lexer.o\ expression_parser.o\ float.o\ fraction.o\ + function.o\ integer.o\ leaf_expression.o\ power.o\ product.o\ + sinus.o\ subtraction.o\ symbol.o\ + tangent.o\ ) objs += $(addprefix poincare/src/layout/,\ + exponent_layout.o\ expression_layout.o\ fraction_layout.o\ + function_layout.o\ horizontal_layout.o\ - exponent_layout.o\ string_layout.o\ ) objs += $(addprefix poincare/src/simplify/,\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index eeaf014ef..4b89926c0 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -3,13 +3,17 @@ #include #include +#include #include -#include #include +#include +#include #include #include #include +#include #include #include +#include #endif diff --git a/poincare/include/poincare/cosinus.h b/poincare/include/poincare/cosinus.h new file mode 100644 index 000000000..5d4fc4e7a --- /dev/null +++ b/poincare/include/poincare/cosinus.h @@ -0,0 +1,13 @@ +#ifndef POINCARE_COSINUS_H +#define POINCARE_COSINUS_H + +#include + +class Cosinus : public Function { + public: + Cosinus(Expression * arg): Function(arg, (char*) "cos") {} + float approximate(Context& context) override; + Type type() override; +}; + +#endif diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 664ce6a64..af5e199f5 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -10,13 +10,16 @@ class Expression { public: enum class Type : uint8_t { Addition, + Cosinus, Float, Fraction, Integer, Power, Product, + Sinus, Subtraction, - Symbol + Symbol, + Tangent, }; static Expression * parse(char const * string); virtual ~Expression(); diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h new file mode 100644 index 000000000..2a8fa67fe --- /dev/null +++ b/poincare/include/poincare/function.h @@ -0,0 +1,17 @@ +#ifndef POINCARE_FUNCTION_H +#define POINCARE_FUNCTION_H + +#include + +class Function : public Expression { + public: + Function(Expression * arg, char* function_name): m_arg(arg), m_function_name(function_name) {} + ~Function(); + ExpressionLayout * createLayout(ExpressionLayout * parent) override; + protected: + Expression * m_arg; + private: + char* m_function_name; +}; + +#endif diff --git a/poincare/include/poincare/sinus.h b/poincare/include/poincare/sinus.h new file mode 100644 index 000000000..5378dd789 --- /dev/null +++ b/poincare/include/poincare/sinus.h @@ -0,0 +1,13 @@ +#ifndef POINCARE_SINUS_H +#define POINCARE_SINUS_H + +#include + +class Sinus : public Function { + public: + Sinus(Expression * arg): Function(arg, (char*) "sin") {} + float approximate(Context& context) override; + Type type() override; +}; + +#endif diff --git a/poincare/include/poincare/tangent.h b/poincare/include/poincare/tangent.h new file mode 100644 index 000000000..f77593878 --- /dev/null +++ b/poincare/include/poincare/tangent.h @@ -0,0 +1,13 @@ +#ifndef POINCARE_TANGENT_H +#define POINCARE_TANGENT_H + +#include + +class Tangent : public Function { + public: + Tangent(Expression * arg): Function(arg, (char*) "tan") {} + float approximate(Context& context) override; + Type type() override; +}; + +#endif diff --git a/poincare/src/cosinus.cpp b/poincare/src/cosinus.cpp new file mode 100644 index 000000000..c21d00aa1 --- /dev/null +++ b/poincare/src/cosinus.cpp @@ -0,0 +1,11 @@ +#include +#include "layout/horizontal_layout.h" + +Expression::Type Cosinus::type() { + return Expression::Type::Cosinus; +} + +float Cosinus::approximate(Context& context) { + // FIXME: use cosinus obviously. + return m_arg->approximate(context); +} diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 5dd2bb7b4..008e5fca5 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -43,6 +43,9 @@ class Expression; [0-9]+ { yylval->string = yytext; return(INTEGER); } [A-Za-z]+ { yylval->string = yytext; return(SYMBOL); } +sin {return(SINUS);} +cos {return(COSINUS);} +tan {return(TANGENT);} \+ { return(PLUS); } \- { return(MINUS); } \* { return(MULTIPLY); } diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index 505f1505b..bb3dd2b14 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -54,6 +54,9 @@ void poincare_expression_yyerror(void * scanner, Expression ** expressionOutput, %token MULTIPLY %token DIVIDE %token POW +%token SINUS +%token COSINUS +%token TANGENT %token LEFT_PARENTHESIS %token RIGHT_PARENTHESIS @@ -85,6 +88,9 @@ exp: | exp DIVIDE exp { Expression * terms[2] = {$1,$3}; $$ = new Fraction(terms, false); } | exp POW exp { Expression * terms[2] = {$1,$3}; $$ = new Power(terms, false); } | LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = $2; } + | SINUS LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Sinus($3); } + | COSINUS LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Cosinus($3); } + | TANGENT LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Tangent($3); } ; %% diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp new file mode 100644 index 000000000..e7e230d11 --- /dev/null +++ b/poincare/src/function.cpp @@ -0,0 +1,10 @@ +#include +#include "layout/function_layout.h" + +Function::~Function() { + delete m_arg; +} + +ExpressionLayout * Function::createLayout(ExpressionLayout * parent) { + return new FunctionLayout(parent, m_function_name, m_arg); +} diff --git a/poincare/src/layout/function_layout.cpp b/poincare/src/layout/function_layout.cpp new file mode 100644 index 000000000..02bc5410b --- /dev/null +++ b/poincare/src/layout/function_layout.cpp @@ -0,0 +1,73 @@ +extern "C" { +#include +#include +} +#include "function_layout.h" +#include "string_layout.h" + +// This code seems like a duplicate of the horizontal layout but it isn't, indeed the horizontal +// layout is used to print the same operation applied to different expressions such that: +// "expr_1 + epr_2 + expr_3 + expr_4". +// Here we want the pattern +// FUNCTION_NAME(expr). +// Thus the code in horizontal layer is not really reusable. + +FunctionLayout::FunctionLayout(ExpressionLayout * parent, char* function_name, Expression * argument) : +ExpressionLayout(parent) { + m_children[0] = new StringLayout(this, function_name, 1); + + char string[2] = {'(', '\0'}; + m_children[1] = new StringLayout(this, string, 1); + + m_children[2] = argument->createLayout(this); + + string[0] = ')'; + m_children[3] = new StringLayout(this, string, 1); +} + +FunctionLayout::~FunctionLayout() { + for (int i(0); i<4; i++) { + delete m_children[i]; + } +} + +void FunctionLayout::render(KDPoint point) { } + +KDSize FunctionLayout::computeSize() { + KDSize size = (KDSize){.width = 0, .height = 0}; + int i = 0; + while (ExpressionLayout * c = child(i++)) { + KDSize childSize = c->size(); + size.width += childSize.width; + if (childSize.height > size.height) { + size.height = childSize.height; + } + } + return size; +} + +ExpressionLayout * FunctionLayout::child(uint16_t index) { + if (index >= 4) { + return nullptr; + } + return m_children[index]; +} + +KDPoint FunctionLayout::positionOfChild(ExpressionLayout * child) { + KDPoint position = (KDPoint){.x = 0, .y = 0}; + uint16_t index = 0; + for (int i=0;i<4;i++) { + if (m_children[i] == child) { + index = i; + break; + } + } + if (index > 0) { + ExpressionLayout * previousChild = m_children[index-1]; + assert(previousChild != nullptr); + position.x = previousChild->origin().x + previousChild->size().width; + } + position.y = (size().height - child->size().height)/2; + return position; +} + diff --git a/poincare/src/layout/function_layout.h b/poincare/src/layout/function_layout.h new file mode 100644 index 000000000..0b689dfcf --- /dev/null +++ b/poincare/src/layout/function_layout.h @@ -0,0 +1,21 @@ +#ifndef POINCARE_FUNCTION_LAYOUT_H +#define POINCARE_FUNCTION_LAYOUT_H + +#include +#include + +class FunctionLayout : public ExpressionLayout { + public: + FunctionLayout(ExpressionLayout * parent, char* function_name, Expression * arg); + ~FunctionLayout(); + protected: + void render(KDPoint point) override; + KDSize computeSize() override; + ExpressionLayout * child(uint16_t index) override; + KDPoint positionOfChild(ExpressionLayout * child) override; + private: + ExpressionLayout * m_children[4]; +}; + +#endif + diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index e1297a0d2..cc64c78af 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -6,7 +6,7 @@ extern "C" { #include "string_layout.h" HorizontalLayout::HorizontalLayout(ExpressionLayout * parent, Expression * left_expression, char symbol, Expression * right_expression) : -ExpressionLayout(parent ) { +ExpressionLayout(parent) { m_children[0] = left_expression->createLayout(this); char string[2] = {symbol, '\0'}; diff --git a/poincare/src/sinus.cpp b/poincare/src/sinus.cpp new file mode 100644 index 000000000..6e831cb2e --- /dev/null +++ b/poincare/src/sinus.cpp @@ -0,0 +1,11 @@ +#include +#include "layout/horizontal_layout.h" + +Expression::Type Sinus::type() { + return Expression::Type::Sinus; +} + +float Sinus::approximate(Context& context) { + // FIXME: use sinus obviously. + return m_arg->approximate(context); +} diff --git a/poincare/src/tangent.cpp b/poincare/src/tangent.cpp new file mode 100644 index 000000000..71e9d3191 --- /dev/null +++ b/poincare/src/tangent.cpp @@ -0,0 +1,11 @@ +#include +#include "layout/horizontal_layout.h" + +Expression::Type Tangent::type() { + return Expression::Type::Tangent; +} + +float Tangent::approximate(Context& context) { + // FIXME: use tangent obviously. + return m_arg->approximate(context); +}