From 8557bc56f7e10fc83da7d7d474d3023240345008 Mon Sep 17 00:00:00 2001 From: 0xtechnobabble <0xtechnobabble@protonmail.com> Date: Thu, 12 Mar 2020 13:45:45 +0200 Subject: [PATCH] LibJS: Implement update expressions Note that currently only the non-prefixed variant is supported (i.e i++ not ++i), this variant returns the value of the argument before the update. --- Libraries/LibJS/AST.cpp | 37 +++++++++++++++++++++++++++++++++++++ Libraries/LibJS/AST.h | 23 +++++++++++++++++++++++ Libraries/LibJS/Parser.cpp | 10 +++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 144098e9df..309decb3d9 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -442,6 +442,25 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const return rhs_result; } +Value UpdateExpression::execute(Interpreter& interpreter) const +{ + ASSERT(m_argument->is_identifier()); + auto name = static_cast(*m_argument).string(); + + auto previous_value = interpreter.get_variable(name); + ASSERT(previous_value.is_number()); + + switch (m_op) { + case UpdateOp::Increment: + interpreter.set_variable(name, Value(previous_value.as_double() + 1)); + break; + case UpdateOp::Decrement: + interpreter.set_variable(name, Value(previous_value.as_double() - 1)); + } + + return previous_value; +} + void AssignmentExpression::dump(int indent) const { const char* op_string = nullptr; @@ -470,6 +489,24 @@ void AssignmentExpression::dump(int indent) const m_rhs->dump(indent + 1); } +void UpdateExpression::dump(int indent) const +{ + const char* op_string = nullptr; + switch (m_op) { + case UpdateOp::Increment: + op_string = "++"; + break; + case UpdateOp::Decrement: + op_string = "--"; + break; + } + + ASTNode::dump(indent); + print_indent(indent + 1); + printf("%s\n", op_string); + m_argument->dump(indent + 1); +} + Value VariableDeclaration::execute(Interpreter& interpreter) const { interpreter.declare_variable(name().string(), m_declaration_type); diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index b907514755..5c28f44db3 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -444,6 +444,29 @@ private: NonnullOwnPtr m_rhs; }; +enum class UpdateOp { + Increment, + Decrement, +}; + +class UpdateExpression : public Expression { +public: + UpdateExpression(UpdateOp op, NonnullOwnPtr argument) + : m_op(op) + , m_argument(move(argument)) + { + } + + virtual Value execute(Interpreter&) const override; + virtual void dump(int indent) const override; + +private: + virtual const char* class_name() const override { return "UpdateExpression"; } + + UpdateOp m_op; + NonnullOwnPtr m_argument; +}; + enum class DeclarationType { Var, Let, diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 4b3a7b850e..3128e44c8d 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -174,6 +174,12 @@ NonnullOwnPtr Parser::parse_secondary_expression(NonnullOwnPtr(move(lhs), parse_expression()); + case TokenType::PlusPlus: + consume(); + return make(UpdateOp::Increment, move(lhs)); + case TokenType::MinusMinus: + consume(); + return make(UpdateOp::Decrement, move(lhs)); default: m_has_errors = true; expected("secondary expression (missing switch case)"); @@ -352,7 +358,9 @@ bool Parser::match_secondary_expression() const || type == TokenType::LessThan || type == TokenType::LessThanEquals || type == TokenType::ParenOpen - || type == TokenType::Period; + || type == TokenType::Period + || type == TokenType::PlusPlus + || type == TokenType::MinusMinus; } bool Parser::match_statement() const