From 376d6ec73b6ae26af478e80941a6bee975ebfe15 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Tue, 4 Aug 2026 21:38:21 +1000 Subject: [PATCH] \#cimport implementation --- src/parser/parser.cpp | 72 +++++++++++++++++++++++++++++++++ src/parser/parser.hpp | 3 +- src/typechecker/typechecker.cpp | 34 +++++++++++++++- src/typechecker/typechecker.hpp | 2 + 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index d880fd0..40db61b 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -78,6 +78,8 @@ namespace Solstice { return "GreaterThan"; case NodeType::LesserThan: return "LesserThan"; + case NodeType::CImport: + return "#CImport"; } throw std::runtime_error("FIXME Unhandled case in nodeTypeToString"); } @@ -111,6 +113,73 @@ namespace Solstice { } return node; } + + Node Parser::parseHashCimport() { + // puts :: #cimport(Int, (String), "puts", ".") + Node node{NodeType::CImport}; + auto next = parseOneNode(Precedence::FunctionCall); + + if (!next.has_value()) { + throw std::runtime_error("expecing arguments to #cimport"); + } + + if (next->type != NodeType::Tuple) { + throw std::runtime_error("expecting tuple-like argument list to follow #cimport"); + } + + if (next->children.size() != 5) { + throw std::runtime_error("cimport takes 5 arguments, that has not been provided"); + } + + if (next->children[1].type != NodeType::Identifier) { + throw std::runtime_error("expecting an identifier for the function name as the first argument to #cimport"); + } + + if (next->children[1].type != NodeType::Identifier) { + throw std::runtime_error("expecting an identifier for the return type as the second argument to #cimport"); + } + + if (next->children[2].type != NodeType::Expression && next->children[2].type != NodeType::Tuple) { + throw std::runtime_error("expecting a tuple (or single expression in brackets) for function argument types"); + } + + for (const auto& idNode : next->children[2].children) { + if (idNode.type != NodeType::Identifier) { + throw std::runtime_error("expecting identifiers in the tuple of function argument types"); + } + } + + if (next->children[3].type == NodeType::Literal) { + auto lit = next->children[3].getLiteral(); + if (!lit.has_value()) { + throw std::runtime_error("literal does not hold a literal value"); + } + auto str = lit->getString(); + if (!str.has_value()) { + throw std::runtime_error("expecting string for c function name"); + } + } else { + throw std::runtime_error("expecting string for c function name"); + } + + if (next->children[4].type == NodeType::Literal) { + auto lit = next->children[4].getLiteral(); + if (!lit.has_value()) { + throw std::runtime_error("literal does not hold a literal value"); + } + auto str = lit->getString(); + if (!str.has_value()) { + throw std::runtime_error("expecting string for c library name"); + } + } else { + throw std::runtime_error("expecting string for c library name"); + } + + + node.children = next->children; + return node; + } + Node Parser::parseActionFunction() { Node node{NodeType::FunctionBind}; @@ -417,6 +486,9 @@ namespace Solstice { case TT::OpenCurly: return parseOpenCurly(); + case TT::Hash_CImport: + return parseHashCimport(); + case TT::NewLine: // ignore new line return parseOneNode(precedence); diff --git a/src/parser/parser.hpp b/src/parser/parser.hpp index e7d8344..32aac1c 100644 --- a/src/parser/parser.hpp +++ b/src/parser/parser.hpp @@ -15,7 +15,8 @@ namespace Solstice { FunctionBind, Bind, Set, SetType, Lambda, FunctionCall, Add, Subtract, Multiply, Divide, - Equal, NotEqual, GreaterThan, LesserThan + Equal, NotEqual, GreaterThan, LesserThan, + CImport }; enum class Precedence { diff --git a/src/typechecker/typechecker.cpp b/src/typechecker/typechecker.cpp index 9af2545..2c36fbc 100644 --- a/src/typechecker/typechecker.cpp +++ b/src/typechecker/typechecker.cpp @@ -1,8 +1,6 @@ #include "typechecker.hpp" #include "type.hpp" -#include #include -#include namespace Solstice { @@ -560,6 +558,32 @@ namespace Solstice { narrowBinaryNode(node, lesserThanOverloads); } + void TypeChecker::checkCImportType(Node& node) { + auto name = *node.children[0].getIdentifier(); + + // Get function's type + Function function; + auto returnTypeId = *node.children[1].getIdentifier(); + if (types.find(returnTypeId) == types.end()) { + throw std::runtime_error("Unknown type " + returnTypeId); + } + auto returnType = types[returnTypeId]; + + std::vector functionTypes; + for (const auto& arg : node.children[2].children) { + auto argTypeId = *arg.getIdentifier(); + if (types.find(argTypeId) == types.end()) { + throw std::runtime_error("Unknown type " + argTypeId); + } + functionTypes.push_back(types[argTypeId]); + } + + function.returnTypes[functionTypes] = returnType; + if (functions.find(name) != functions.end()) { + throw std::runtime_error("cannot override function with name " + name); + } + functions[name] = function; + } void TypeChecker::checkNodeType(Node& node) { switch (node.type) { @@ -570,6 +594,7 @@ namespace Solstice { switch (child.type) { case NodeType::Bind: case NodeType::FunctionBind: + case NodeType::CImport: checkNodeType(child); break; default: @@ -629,7 +654,12 @@ namespace Solstice { case NodeType::FunctionCall: checkFunctionCallNodeType(node); break; + case NodeType::CImport: + checkCImportType(node); + break; + default: + throw std::runtime_error("FIXME unimplemented type checking case"); } } diff --git a/src/typechecker/typechecker.hpp b/src/typechecker/typechecker.hpp index df8ae19..8263903 100644 --- a/src/typechecker/typechecker.hpp +++ b/src/typechecker/typechecker.hpp @@ -61,6 +61,8 @@ namespace Solstice { void checkGreaterThanType(Node& node); void checkLesserThanType(Node& node); + void checkCImportType(Node& node); + void checkNodeType(Node& node); public: