From a9ef7c884e4c35348afd1a41c986bff1cce8a2ff Mon Sep 17 00:00:00 2001
From: Mattias Ajander <mattias@ajander.se>
Date: Mon, 7 Apr 2025 00:20:12 +0200
Subject: [PATCH] WIP for command line arguemtns. Calling length on an empty
 args list causes segfault.

---
 examples/args.funk                      |  2 ++
 include/ast/expression/MethodCallNode.h |  1 +
 source/ast/BlockNode.cc                 |  5 +++++
 source/ast/declaration/VariableNode.cc  |  3 ++-
 source/ast/expression/ListNode.cc       |  2 +-
 source/ast/expression/MethodCallNode.cc |  6 +++++
 source/parser/Parser.cc                 | 29 ++++++++++++++++---------
 7 files changed, 36 insertions(+), 12 deletions(-)
 create mode 100644 examples/args.funk

diff --git a/examples/args.funk b/examples/args.funk
new file mode 100644
index 0000000..ba06c4d
--- /dev/null
+++ b/examples/args.funk
@@ -0,0 +1,2 @@
+print("A list of arguments with length: ", ARGS.length());
+print("The arguments are:", ARGS);
diff --git a/include/ast/expression/MethodCallNode.h b/include/ast/expression/MethodCallNode.h
index 5242745..220a8f4 100644
--- a/include/ast/expression/MethodCallNode.h
+++ b/include/ast/expression/MethodCallNode.h
@@ -1,4 +1,5 @@
 #pragma once
+#include "ast/declaration/VariableNode.h"
 #include "ast/expression/CallNode.h"
 #include "ast/expression/ListNode.h"
 #include "logging/LogMacros.h"
diff --git a/source/ast/BlockNode.cc b/source/ast/BlockNode.cc
index 826cdfb..8f16957 100644
--- a/source/ast/BlockNode.cc
+++ b/source/ast/BlockNode.cc
@@ -13,6 +13,11 @@ BlockNode::~BlockNode()
 
 void BlockNode::add(Node* statement)
 {
+    if (statement == nullptr)
+    {
+        LOG_WARN("Attempted to add null statement to block");
+        return;
+    }
     statements.push_back(statement);
 }
 
diff --git a/source/ast/declaration/VariableNode.cc b/source/ast/declaration/VariableNode.cc
index 69958e1..dbff58a 100644
--- a/source/ast/declaration/VariableNode.cc
+++ b/source/ast/declaration/VariableNode.cc
@@ -32,6 +32,7 @@ Node* VariableNode::evaluate() const
 
 String VariableNode::to_s() const
 {
+    if (value == nullptr) { return "Variable: " + identifier; }
     return "Variable: " + identifier + " = " + value->to_s();
 }
 
@@ -74,4 +75,4 @@ void VariableNode::set_value(ExpressionNode* new_value)
     }
     else { throw RuntimeError(get_location(), "Cannot modify immutable variable '" + identifier + "'"); }
 }
-} // namespace funk
\ No newline at end of file
+} // namespace funk
diff --git a/source/ast/expression/ListNode.cc b/source/ast/expression/ListNode.cc
index a09e44c..c6837df 100644
--- a/source/ast/expression/ListNode.cc
+++ b/source/ast/expression/ListNode.cc
@@ -33,7 +33,7 @@ NodeValue ListNode::get_value() const
 {
     ExpressionNode* result{dynamic_cast<ExpressionNode*>(evaluate())};
     if (!result) { throw RuntimeError(location, "List did not evaluate to an expression"); }
-    return result->get_value();
+    return NodeValue(result->to_s());
 }
 
 size_t ListNode::length() const
diff --git a/source/ast/expression/MethodCallNode.cc b/source/ast/expression/MethodCallNode.cc
index 2a4afbc..cefdb12 100644
--- a/source/ast/expression/MethodCallNode.cc
+++ b/source/ast/expression/MethodCallNode.cc
@@ -20,6 +20,12 @@ Node* MethodCallNode::evaluate() const
     Node* evaluated_object{object->evaluate()};
     if (!evaluated_object) { throw RuntimeError(location, "Failed to evaluate object for method call"); }
 
+    if (auto var_node = dynamic_cast<VariableNode*>(evaluated_object))
+    {
+        Node* var_value = var_node->get_value_node();
+        if (var_value) { evaluated_object = var_value; }
+    }
+
     if (auto list_node = dynamic_cast<ListNode*>(evaluated_object))
     {
         if (identifier.get_lexeme() == "length")
diff --git a/source/parser/Parser.cc b/source/parser/Parser.cc
index d35ab70..2e098f2 100644
--- a/source/parser/Parser.cc
+++ b/source/parser/Parser.cc
@@ -10,20 +10,22 @@ Node* Parser::parse(const Vector<String>& args)
 {
     LOG_DEBUG("Parse program");
 
-    if (!args.empty())
-    {
-        String arg_list{};
-        for (const String& arg : args) { arg_list += arg + ", "; }
-        LOG_INFO("Arguments: " + arg_list.substr(0, arg_list.length() - 2));
-    }
-
-    // TODO: Handle arguments
-
     BlockNode* block = new BlockNode(SourceLocation(filename, 0, 0));
+
+    LOG_DEBUG("Parsing arguments");
+
+    // Create a Vector of ExpressionNodes for the arguments
+    Vector<ExpressionNode*> list{};
+    // Populate the Vector with LiteralNodes
+    for (const String& arg : args) { list.push_back(new LiteralNode(SourceLocation(filename, 0, 0), arg)); }
+    // Create a ListNode for the arguments
+    ExpressionNode* args_list{new ListNode(SourceLocation(filename, 0, 0), TokenType::TEXT, list)};
+    // Create a DeclarationNode for the arguments
+    block->add(new DeclarationNode(SourceLocation(filename, 0, 0), true, TokenType::TEXT, "ARGS", args_list));
+    // Parse the rest of the program
     while (!done()) { block->add(parse_statement()); }
     return block;
 }
-
 Parser Parser::load(String filename)
 {
     Lexer lexer{read_file(filename), filename};
@@ -72,6 +74,13 @@ Node* Parser::parse_statement()
 {
     LOG_DEBUG("Parse statement");
 
+    if (check(TokenType::COMMENT) || check(TokenType::BLOCK_COMMENT))
+    {
+        LOG_INFO("Skipping comment");
+        next();
+        return nullptr;
+    }
+
     Node* control{parse_control()};
     if (control) { return control; }
 
-- 
GitLab