diff --git a/Makefile b/Makefile index 2db5a94..1e1314c 100644 --- a/Makefile +++ b/Makefile @@ -27,8 +27,9 @@ TARGET = kyn all: $(TARGET) # Link the object files to create the executable +# At this point, we do -lcurl to link curl for the request lib $(TARGET): $(OBJS) - $(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS) + $(CXX) $(CXXFLAGS) -lcurl -o $(TARGET) $(OBJS) # Compile .cpp files to .o files in the build directory $(BUILD_DIR)/%.o: %.cpp diff --git a/src/defs/defs.cpp b/src/defs/defs.cpp index edd9d6b..6721636 100644 --- a/src/defs/defs.cpp +++ b/src/defs/defs.cpp @@ -22,6 +22,7 @@ InstructionType strToInstructionType(std::string in) { else if (in == "file") return InstructionType::File; else if (in == "struct") return InstructionType::Struct; else if (in == "assert") return InstructionType::Assert; + else if (in == "request") return InstructionType::Request; else return InstructionType::Variable; } diff --git a/src/defs/defs.h b/src/defs/defs.h index e318507..778a1b6 100644 --- a/src/defs/defs.h +++ b/src/defs/defs.h @@ -6,7 +6,7 @@ #include enum class InstructionType { - None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare, Function, Struct, Return, Concat, Split, File, Assert + None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare, Function, Struct, Return, Concat, Split, File, Assert, Request }; enum class ValueType { diff --git a/src/executor/executor.cpp b/src/executor/executor.cpp index 99be250..9c4f1ec 100644 --- a/src/executor/executor.cpp +++ b/src/executor/executor.cpp @@ -18,6 +18,7 @@ #include "../modules/split/split.h" #include "../modules/concat/concat.h" #include "../modules/file/file.h" +#include "../modules/request/request.h" #include "../modules/assert/assert.h" // Forward declaration for mutual recursion @@ -257,6 +258,8 @@ Value execute(Instruction inst) { return modules::concat(inst.args); case InstructionType::File: return modules::file(inst.args); + case InstructionType::Request: + return modules::request(inst.args); case InstructionType::Exit: return modules::exit(inst.args); case InstructionType::Return: { diff --git a/src/modules/request/request.cpp b/src/modules/request/request.cpp new file mode 100644 index 0000000..9d79ba7 --- /dev/null +++ b/src/modules/request/request.cpp @@ -0,0 +1,69 @@ +#include "request.h" +#include "../../defs/defs.h" +#include "../../error/error.h" +#include +#include +#include + +enum class RequestType { + GET, POST +}; + +size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) { + size_t totalSize = size * nmemb; + userp->append((char*)contents, totalSize); + return totalSize; +} + +std::string curlWrapper(std::string url, RequestType requestType, std::string data = "") { + CURL* curl = curl_easy_init(); + std::string response; + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "kyn-libcurl-agent/1.0"); + + if (requestType == RequestType::POST) { + curl_easy_setopt(curl, CURLOPT_POST, 1L); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); + } + + CURLcode res = curl_easy_perform(curl); + if (res != CURLE_OK) { + error("Request failed: " + std::string(curl_easy_strerror(res))); + response = "KYNERR"; + } + + curl_easy_cleanup(curl); + } + return response; +} + +Value modules::request(std::vector args) { + if (args.size() < 2) { + error("Not enough args for request module"); + return Value("Error"); + } + if (args[1].valtype != ValueType::String) { + error("Expecting a string to identify request URL"); + return Value("Error"); + } + if (args[0].valtype == ValueType::Identifier) { + if (args[0].string_val == "get") { + std::string response = curlWrapper(args[1].string_val, RequestType::GET); + if (response == "KYNERR") return Value("Error"); + return Value(response); + } else if (args[0].string_val == "post") { + if (args.size() < 3 || args[2].valtype != ValueType::String) { + error("post submodule of request expects a string as 2nd arg"); + return Value("Error"); + } + std::string response = curlWrapper(args[1].string_val, RequestType::POST, args[2].string_val); + if (response == "KYNERR") return Value("Error"); + return Value(response); + } + } + error("Unknown submodule for request. Only 'get' and 'post' are available."); + return Value("Error"); +} diff --git a/src/modules/request/request.h b/src/modules/request/request.h new file mode 100644 index 0000000..037a8b3 --- /dev/null +++ b/src/modules/request/request.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include "../../defs/defs.h" + +namespace modules { + Value request(std::vector args); +} diff --git a/tests/loop.kyn b/tests/loop.kyn index 8ee52b9..bea16be 100644 --- a/tests/loop.kyn +++ b/tests/loop.kyn @@ -1,6 +1,6 @@ let counter = 0 -while compare $counter <= 1000 { +while compare $counter <= 10000 { println $counter counter = (math 1 + $counter) } diff --git a/tests/test.kyn b/tests/test.kyn new file mode 100644 index 0000000..d04622b --- /dev/null +++ b/tests/test.kyn @@ -0,0 +1,33 @@ +println "thing" + +if compare 5 == 10 { + println "uh oh its broken" +} else { + println "its working" +} + +struct Dingus { + name = + age = + fun init name age { + self name = name + self age = age + } + + fun tostring { + return (concat name ", " age) + } +} + +let myDingus = (Dingus "dingus" 23) + +fun myFn param1 param2 andSoOn { + println param1 + return param2 +} + +println (myFn 123 "hi" 3.14) + +let favNumbers = [7, 14, 21] + +println (file read "README.md")