Skip to content

Commit

Permalink
add ExecuteNode
Browse files Browse the repository at this point in the history
  • Loading branch information
Prevter committed Nov 1, 2024
1 parent ec777a9 commit 826382b
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 2 deletions.
45 changes: 45 additions & 0 deletions include/rift/nodes/execute.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include "node.hpp"
#include "../value.hpp"

#include <string>
#include <utility>

namespace rift {

/// @brief A node in the AST that should be evaluated as a sub-expression. (used for sub-string interpolation)
class ExecuteNode : public Node {
public:
/// @brief Construct the execute node.
/// @param child The child node to execute.
explicit ExecuteNode(Node* child) : m_child(child) {}

~ExecuteNode() override {
delete m_child;
}

/// @brief Get the child node to execute.
/// @return The child node to execute.
[[nodiscard]] const Node* getChild() const { return m_child; }

/// @copydoc Node::getType
[[nodiscard]] Type getType() const override { return Type::Execute; }

/// @copydoc Node::accept
void accept(Visitor* visitor) override;

/// @copydoc Node::getValue
[[nodiscard]] Value getValue(Visitor* visitor) const override;

/// @copydoc Node::print
std::ostream& print(std::ostream& out) const override {
out << "ExecuteNode(" << *m_child << ')';
return out;
}

private:
Node* m_child;
};

}
1 change: 1 addition & 0 deletions include/rift/nodes/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace rift {
BinaryOp,
FunctionCall,
TernaryOp,
Execute
};

/// @brief Destruct the node.
Expand Down
5 changes: 4 additions & 1 deletion include/rift/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ namespace rift {
*
* power : call ('^' factor)*
*
* interpolate : '$' call
*
* call : atom ('(' (expression (',' expression)*)? ')')?
*
* atom : number | string | identifier
Expand Down Expand Up @@ -60,14 +62,15 @@ namespace rift {
// Parse functions

Result<Node*> parseBlock();
inline Result<Node*> parseExpression() { return parseTernaryOp(); }
Result<Node*> parseExpression() { return parseTernaryOp(); }
Result<Node*> parseTernaryOp();
Result<Node*> parseBooleanMath();
Result<Node*> parseComparisonExpression();
Result<Node*> parseArithmeticExpression();
Result<Node*> parseTerm();
Result<Node*> parseFactor();
Result<Node*> parsePower();
Result<Node*> parseInterpolate();
Result<Node*> parseCall();
Result<Node*> parseAtom();

Expand Down
1 change: 1 addition & 0 deletions include/rift/token.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace rift {
PLUS, MINUS, STAR, SLASH, PERCENT, CARET,
QUESTION, COLON, NULL_COALESCE, ASSIGN,
LESS, GREATER, LESS_EQUAL, GREATER_EQUAL, EQUAL_EQUAL, NOT_EQUAL,
DOLLAR,

// Logical operators
AND, OR, NOT,
Expand Down
7 changes: 7 additions & 0 deletions include/rift/visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ namespace rift {
/// @return The value of the variable.
[[nodiscard]] Value getVariable(const std::string& name) const;

/// @brief Get all the variables.
/// @return The variables.
[[nodiscard]] const std::unordered_map<std::string, Value>* getVariables() const { return m_variables; }

/// @brief Visit a node.
void visit(Node* node);

Expand Down Expand Up @@ -49,6 +53,9 @@ namespace rift {
/// @brief Visit a ternary operation node.
void visit(class TernaryNode* node);

/// @brief Visit an execute node.
void visit(class ExecuteNode* node);

/// @brief Write a string to the output.
/// @param text The text to write.
void write(std::string_view text);
Expand Down
1 change: 1 addition & 0 deletions src/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ namespace rift {
case '/': return createToken(TokenType::SLASH, "/");
case '%': return createToken(TokenType::PERCENT, "%");
case '^': return createToken(TokenType::CARET, "^");
case '$': return createToken(TokenType::DOLLAR, "$");
case ':': {
if (peek() == '=') {
advance();
Expand Down
17 changes: 17 additions & 0 deletions src/nodes/execute.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <rift/nodes/execute.hpp>
#include <rift/visitor.hpp>

namespace rift {

void ExecuteNode::accept(Visitor* visitor) {
visitor->visit(this);
}

Value ExecuteNode::getValue(Visitor* visitor) const {
auto value = m_child->getValue(visitor);
if (value.isString()) {
return Value::from(rift::format(value.getString(), *visitor->getVariables()));
}
return value;
}
}
17 changes: 16 additions & 1 deletion src/parser.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <rift/parser.hpp>

#include <rift/nodes/binaryop.hpp>
#include <rift/nodes/execute.hpp>
#include <rift/nodes/functioncall.hpp>
#include <rift/nodes/identifier.hpp>
#include <rift/nodes/segment.hpp>
Expand Down Expand Up @@ -175,7 +176,7 @@ namespace rift {
}

Result<Node*> Parser::parsePower() {
auto res = parseCall();
auto res = parseInterpolate();
if (!res) return res;
auto* expression = res.getValue();
while (m_currentToken.type == TokenType::CARET) {
Expand All @@ -190,6 +191,20 @@ namespace rift {
return Result<Node*>::success(expression);
}

Result<Node*> Parser::parseInterpolate() {
if (m_currentToken.type != TokenType::DOLLAR) {
return parseCall();
}
advance();
auto res = parseCall();
if (!res) {
return res;
}
auto* expression = res.getValue();
auto* execute = new ExecuteNode(expression);
return Result<Node*>::success(execute);
}

Result<Node*> Parser::parseCall() {
auto res = parseAtom();
if (m_currentToken.type != TokenType::LEFT_PAREN || !res) {
Expand Down
6 changes: 6 additions & 0 deletions src/visitor.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <rift/visitor.hpp>

#include <rift/nodes/binaryop.hpp>
#include <rift/nodes/execute.hpp>
#include <rift/nodes/functioncall.hpp>
#include <rift/nodes/identifier.hpp>
#include <rift/nodes/root.hpp>
Expand Down Expand Up @@ -74,6 +75,11 @@ namespace rift {
write(value.toString());
}

void Visitor::visit(ExecuteNode* node) {
auto value = node->getValue(this);
write(value.toString());
}

const std::string& Visitor::evaluate() {
for (auto& node : m_script->m_nodes) {
node->accept(this);
Expand Down
1 change: 1 addition & 0 deletions test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ int main() {
RIFT_TEST_CASE("{duration(123.456)}", "2:03.456");

RIFT_TEST_CASE("{myCustomFunc('World')}", "Hello, World!");
RIFT_TEST_CASE("{$'string interpolation: {2 + 2}'}", "string interpolation: 4");
}

// Show the results
Expand Down

0 comments on commit 826382b

Please sign in to comment.