summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/puzzles/puzzle.c104
-rw-r--r--src/puzzles/puzzle.h32
-rw-r--r--src/scenes/puzzleScene.c25
-rw-r--r--src/scenes/resultView.c10
-rw-r--r--src/scenes/scenes.h2
-rw-r--r--src/ui_elements/TextEditor.c142
-rw-r--r--src/ui_elements/UI.c3
-rw-r--r--src/ui_elements/UI.h6
-rw-r--r--src/utils/stringBuilder.c26
-rw-r--r--src/utils/stringBuilder.h3
-rw-r--r--src/wren_inter/wren_inter.c70
-rw-r--r--src/wren_inter/wren_inter.h6
12 files changed, 351 insertions, 78 deletions
diff --git a/src/puzzles/puzzle.c b/src/puzzles/puzzle.c
index cbad998..22f7a4d 100644
--- a/src/puzzles/puzzle.c
+++ b/src/puzzles/puzzle.c
@@ -1,21 +1,121 @@
#include "puzzle.h"
+#include "../wren_inter/wren_inter.h"
#include <stdlib.h>
#include <string.h>
+#include <wren.h>
+
+/// Returns 1 test puzzle for the GetTestPuzzle segment
+Test *getTestPuzzleTests() {
+ Test *outp = malloc(sizeof(Test));
+ outp->RecieverName = strdup("main");
+ outp->MainMethodSignature = strdup("call(_)");
+
+ outp->argc = 1;
+ outp->argv = malloc(sizeof(PuzzleIO));
+ outp->argv->type = WREN_TYPE_STRING;
+ outp->argv->value = strdup("Hello");
+
+ outp->ExpectedResult.type = WREN_TYPE_STRING;
+ outp->ExpectedResult.value = strdup("Hello");
+ return outp;
+}
Puzzle *GetTestPuzzle() {
Puzzle *outp = malloc(sizeof(Puzzle));
if (outp == NULL) return NULL;
outp->Name = strdup("Test puzzle");
- outp->Description = strdup("In this puzzle you will have to return the input string\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\n-\nThis is a line that should be somewhere down");
+ outp->Description = strdup("In this puzzle you will have to return the input string");
+ outp->InitialCode = strdup( "var main = Fn.new { |name| \n System.print(\"Hello, %(name)!\")\n}\n\nmain.call(\"world\")");
+ outp->TestC = 1;
+ outp->Tests = getTestPuzzleTests();
return outp;
}
+void FreeTests(Test *Tests, size_t TestC) {
+ if (TestC == 0 || Tests == NULL) return;
+ for (size_t i = 0; i < TestC; i++) {
+ Test *t = &Tests[i];
+ free(t->RecieverName);
+ free(t->MainMethodSignature);
+ free(t->argv);
+ }
+ free(Tests);
+}
+
void FreePuzzle(Puzzle *self) {
if (self == NULL) return;
if (self->Name != NULL) free(self->Name);
if (self->Description != NULL) free(self->Description);
- if (self->Tests != NULL) free(self->Tests);
+ if (self->InitialCode != NULL) free(self->InitialCode);
+ FreeTests(self->Tests, self->TestC);
free(self);
}
+
+
+enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm) {
+ // TODO: finish this
+ return RESULT_OK;
+}
+
+// Returns the res ptr. Does not modify the address
+SubmitionResult *TryEvaluateUserCode(WrenVM *vm, char *script, SubmitionResult *res) {
+ WrenInterpretResult result = wrenInterpret(vm, "main", script);
+ res->result = RESULT_OK;
+ switch (result) {
+ case WREN_RESULT_COMPILE_ERROR:
+ res->result = RESULT_COMPTIME_ERR;
+ return res;
+ case WREN_RESULT_RUNTIME_ERROR:
+ res->result = RESULT_RUNTIME_ERR;
+ return res;
+ default: break;
+ }
+ return res;
+}
+
+// Frees the vm. Does not modify the self address.
+SubmitionResult *PrepareResult(SubmitionResult *self,
+ WrenVM *vm,
+ enum PUZZLE_TEST_RESULT result) {
+ if (vm == NULL || self == NULL) return self;
+ self->result = result;
+ self->stdout = GetMachineOutput(vm);
+ InterpreterFreeMachine(vm);
+ return self;
+}
+
+SubmitionResult *SubmitSolution(Puzzle *self, char *script) {
+ if (self == NULL || script == NULL) return NULL;
+ SubmitionResult *res = malloc(sizeof(SubmitionResult));
+
+ WrenVM *vm = InterpreterPrepareMachine();
+ if (vm == NULL) {
+ res->result = RESULT_INIT_ERROR;
+ return res;
+ }
+
+ res = TryEvaluateUserCode(vm, script, res);
+ if (res->result != RESULT_OK) {
+ return PrepareResult(res, vm, res->result);
+ }
+
+ for (size_t i = 0; i < self->TestC; i++) {
+ enum PUZZLE_TEST_RESULT test_res = RunTest(&self->Tests[i], vm);
+ switch (test_res) {
+ case WREN_RESULT_COMPILE_ERROR:
+ return PrepareResult(res, vm, RESULT_COMPTIME_ERR);
+ case WREN_RESULT_RUNTIME_ERROR:
+ return PrepareResult(res, vm, RESULT_RUNTIME_ERR);
+ default: break;
+ }
+ }
+
+ return PrepareResult(res, vm, RESULT_OK);
+}
+
+void FreeSunmitionResult(SubmitionResult *res) {
+ if (res->stdout != NULL) free(res->stdout);
+ free(res);
+}
diff --git a/src/puzzles/puzzle.h b/src/puzzles/puzzle.h
index d530a89..6c72a18 100644
--- a/src/puzzles/puzzle.h
+++ b/src/puzzles/puzzle.h
@@ -3,6 +3,16 @@
#ifndef PUZZLE_H
+enum PUZZLE_TEST_RESULT : char {
+ RESULT_OK = 0,
+ RESULT_COMPTIME_NO_ENTRY,
+ RESULT_COMPTIME_ERR,
+ RESULT_RUNTIME_ERR,
+ // TODO: add async evaluation to prevent `while (true)` situation
+ RESULT_TIMEOUT,
+ RESULT_INIT_ERROR,
+};
+
// This is a param that would be placed in a slot
// https://wren.io/embedding/slots-and-handles.html#writing-slots
typedef struct {
@@ -13,22 +23,32 @@ typedef struct {
} PuzzleIO;
typedef struct {
+ // https://wren.io/embedding/calling-wren-from-c.html#setting-up-a-receiver
+ char *RecieverName;
// https://wren.io/embedding/calling-wren-from-c.html#getting-a-method-handle
char *MainMethodSignature;
size_t argc;
PuzzleIO *argv;
+ PuzzleIO ExpectedResult;
} Test;
+
+/// The user submitted code should be evaluated by this point.
+/// The entry point should be registered and the absence of the
+/// Main method signatire will be concidered an error
+enum PUZZLE_TEST_RESULT RunTest(Test *test, WrenVM *vm);
+
typedef struct {
char *Name;
char *Description;
+ char *InitialCode;
/// The tests that are accessible for an end user
size_t TestC;
Test *Tests;
} Puzzle;
-
+
// TODO
void ReadPuzzleFromFile(const char *path);
@@ -36,5 +56,15 @@ void FreePuzzle(Puzzle *self);
/// A prebuilt puzzle. Used for debuging
Puzzle *GetTestPuzzle();
+typedef struct {
+ char *stdout;
+ enum PUZZLE_TEST_RESULT result;
+} SubmitionResult;
+
+// Don't put anything in out_res, it will be overriten.
+// The stdout of the VM will be there
+SubmitionResult *SubmitSolution(Puzzle *self, char *script);
+void FreeSunmitionResult(SubmitionResult *res);
+
#define PUZZLE_H
#endif // PUZZLE_H
diff --git a/src/scenes/puzzleScene.c b/src/scenes/puzzleScene.c
index 5590bb8..57ac15d 100644
--- a/src/scenes/puzzleScene.c
+++ b/src/scenes/puzzleScene.c
@@ -72,7 +72,7 @@ bool drawPuzzleScene(void *self) {
// return true;
Rectangle pane1, pane2;
- GetPanesSplit(&pane1, &pane2, body, 0.5, 0.4);
+ GetPanesSplit(&pane1, &pane2, body, 0.35, 0.4);
DrawRecBordered(pane1, WHITE, COLORSCHEME_ORANGE, BORDER);
DrawRecBordered(pane2, WHITE, COLORSCHEME_ORANGE, BORDER);
@@ -85,12 +85,19 @@ bool drawPuzzleScene(void *self) {
bool updatePuzzleScene(void *self) {
puzzleSceneData *data = ((Scene *)self)->data;
- HandleKeyboard(data->EditorInfo);
+
+ Rectangle body = GetBodyRect();
+ Rectangle pane1, pane2;
+ GetPanesSplit(&pane1, &pane2, body, 0.35, 0.4);
+ UpdateTextArea(data->EditorInfo, pane2);
+
if (IsKeyPressed(KEY_F5)) {
- char *txt = GetText(data->EditorInfo);
- char *outp = EvaluateScript(txt);
- free(txt);
- AddScene(CreateResultView(outp));
+ char *script = GetText(data->EditorInfo);
+ // char *outp = EvaluateScript(txt);
+ // free(txt);
+ // AddScene(CreateResultView(outp));
+ SubmitionResult *res = SubmitSolution(data->PuzzlePtr, script);
+ AddScene(CreateResultView(res));
}
return true;
@@ -122,8 +129,12 @@ Scene *CreatePuzzleScene(Puzzle *puzzle) {
EditorDisplayParams->scroll_h = 0;
EditorDisplayParams->scroll_v = 0;
}
- data->EditorInfo = CreateTextArea(EditorDisplayParams);
+ if (puzzle->InitialCode != NULL) {
+ data->EditorInfo = CreateTextAreaFromText(EditorDisplayParams, puzzle->InitialCode);
+ } else {
+ data->EditorInfo = CreateTextArea(EditorDisplayParams);
+ }
outp->data = data;
return outp;
diff --git a/src/scenes/resultView.c b/src/scenes/resultView.c
index b433bd0..033d17e 100644
--- a/src/scenes/resultView.c
+++ b/src/scenes/resultView.c
@@ -11,7 +11,7 @@ static const int BORDER = 2;
static const int SCROLL_SPEED = 10;
typedef struct {
- char *value;
+ SubmitionResult *value;
int scroll;
/// For the fun popping up effect
float scroll_up;
@@ -57,17 +57,20 @@ bool drawResultView(void *self) {
// DrawBackground();
Rectangle body = GetResultViewBodyRect(data->scroll_up);
DrawRecBordered(body, WHITE, COLORSCHEME_ORANGE, BORDER);
- DrawTextInRec(body, data->value,
+ DrawTextInRec(body, data->value->stdout,
GetMainFont(), 20, COLORSCHEME_BROWN, 3, &data->scroll);
return true;
}
void deinitResultView(void *self) {
TraceLog(LOG_INFO, "Deleting a result view");
+ ResultViewData *data = ((Scene *)self)->data;
+ if (data->value != NULL) FreeSunmitionResult(data->value);
+ free(data);
free((Scene *)self);
}
-Scene *CreateResultView(char *result) {
+Scene *CreateResultView(SubmitionResult *result) {
TraceLog(LOG_INFO, "Creating a main menu");
Scene *outp = malloc(sizeof(Scene));
outp->Draw = drawResultView;
@@ -80,6 +83,7 @@ Scene *CreateResultView(char *result) {
free(outp);
return NULL;
}
+
data->value = result;
data->scroll = 0;
data->scroll_up = 1;
diff --git a/src/scenes/scenes.h b/src/scenes/scenes.h
index 37da761..b7fdf02 100644
--- a/src/scenes/scenes.h
+++ b/src/scenes/scenes.h
@@ -30,6 +30,6 @@ bool UpdateScene();
Scene *CreateMainMenu();
Scene *CreatePuzzleScene(Puzzle *puzzle);
-Scene *CreateResultView(char *result);
+Scene *CreateResultView(SubmitionResult *result);
#endif // SCENES_H
diff --git a/src/ui_elements/TextEditor.c b/src/ui_elements/TextEditor.c
index 06cfc41..3cf34ff 100644
--- a/src/ui_elements/TextEditor.c
+++ b/src/ui_elements/TextEditor.c
@@ -5,6 +5,7 @@
#include "../resources/resources.h"
#include <ctype.h>
#include <raylib.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -218,18 +219,18 @@ void MoveCursorRight(TextArea *ta) {
void MoveCursorRightWord(TextArea *ta) {
if (ta == NULL || ta->CurrentNode == NULL) return;
+ size_t line_len = ta->CurrentNode->len;
+ if (ta->CursorPosition.x == line_len) {
+ MoveCursorRight(ta);
+ return;
+ }
+ bool current_type = IsSkippable(GetCurrentChar(ta));
do {
ta->CursorPosition.x += 1;
- } while (IsSkippable(GetCurrentChar(ta)));
+ } while (IsSkippable(GetCurrentChar(ta)) == current_type);
- size_t line_len = ta->CurrentNode->len;
if (ta->CursorPosition.x > line_len) {
- if (ta->CurrentNode->NextNode == NULL) {
- ta->CursorPosition.x = line_len;
- return;
- }
- MoveCursorDown(ta);
- ta->CursorPosition.x = 0;
+ ta->CursorPosition.x = line_len;
}
}
@@ -254,9 +255,18 @@ void MoveCursorLeft(TextArea *ta) {
void MoveCursorLeftWord(TextArea *ta) {
if (ta == NULL || ta->CurrentNode == NULL) return;
+ if (ta->CursorPosition.x == 0) {
+ MoveCursorLeft(ta);
+ return;
+ }
+ char prev_symbol = ta->CurrentNode->text[(int)ta->CursorPosition.x - 1];
+ bool current_type = IsSkippable(prev_symbol);
+
do {
ta->CursorPosition.x -= 1;
- } while (IsSkippable(GetCurrentChar(ta)) && ta->CursorPosition.x > 0);
+ } while (IsSkippable(GetCurrentChar(ta)) == current_type && ta->CursorPosition.x >= 0);
+
+ ta->CursorPosition.x += 1;
if (ta->CursorPosition.x < 0) {
if (ta->CursorPosition.y == 0 || ta->CurrentNode->PrevNode == NULL) {
@@ -273,6 +283,15 @@ void MoveCursorHome(TextArea *ta) {
ta->CursorPosition.x = 0;
}
+size_t GetStartingSpaces(char *string) {
+ if (string == NULL) return 0;
+ size_t idx = 0, len = strlen(string);
+ while (string[idx] != 0 && string[idx] == ' ')
+ idx++;
+ if (string[idx] == 0) return 0; // no starting spaces
+ return idx;
+}
+
void BreakLine(TextArea *ta) {
if (ta == NULL || ta->CurrentNode == NULL) return;
if (ta->CursorPosition.x == 0) {
@@ -287,24 +306,44 @@ void BreakLine(TextArea *ta) {
return;
}
+ TextNode *next_node = (TextNode *)ta->CurrentNode->NextNode;
size_t current_node_len = strlen(ta->CurrentNode->text);
+ size_t spaces_len = GetStartingSpaces(ta->CurrentNode->text);
+ size_t needed_space = spaces_len;
+
+ size_t after_str_len = 0;
+ char *after_str = NULL;
+
if (ta->CursorPosition.x < current_node_len) {
- char *after_str = (ta->CurrentNode->text + (int)ta->CursorPosition.x);
- size_t after_str_len = strlen(after_str);
- if (((TextNode *)ta->CurrentNode->NextNode)->cap < after_str_len) {
- if (!AddSpaceDetermined(ta->CurrentNode->NextNode, after_str_len)) {
- TraceLog(LOG_ERROR, "Failed to push a node: the space reservaton failed");
- }
+ after_str = (ta->CurrentNode->text + (int)ta->CursorPosition.x);
+ after_str_len = strlen(after_str);
+ needed_space += after_str_len;
+ }
+
+ if (next_node->cap < needed_space + 1) {
+ if (!AddSpaceDetermined(ta->CurrentNode->NextNode, needed_space + 1)) {
+ TraceLog(LOG_ERROR, "Failed to push a node: the space reservaton failed");
+ return;
}
- strcpy(((TextNode *)ta->CurrentNode->NextNode)->text, after_str);
- ((TextNode *)ta->CurrentNode->NextNode)->len = after_str_len;
+ }
+
+ for (int i = 0; i < spaces_len; ++i) {
+ next_node->text[i] = ' ';
+ }
+ next_node->text[spaces_len] = 0x0;
+
+ if (after_str != NULL) {
+ strcpy(next_node->text + spaces_len, after_str);
+ ((TextNode *)ta->CurrentNode->NextNode)->len = after_str_len + spaces_len;
for (int i = ta->CursorPosition.x; i < current_node_len; i++) {
ta->CurrentNode->text[i] = 0x0;
}
ta->CurrentNode->len -= after_str_len;
}
+
+ next_node->len = strlen(next_node->text);
ta->CursorPosition.y += 1;
- ta->CursorPosition.x = 0;
+ ta->CursorPosition.x = spaces_len;
ta->CurrentNode = ta->CurrentNode->NextNode;
EnsureCursorIsInFrame(ta);
}
@@ -358,7 +397,9 @@ void DeleteChar(TextArea *ta) {
ta->CurrentNode->text[line_len - 1] = 0x0;
} else {
char *after_str = (ta->CurrentNode->text + (int)ta->CursorPosition.x);
- strcpy(ta->CurrentNode->text + (int)ta->CursorPosition.x - 1, after_str);
+ // Including a zero terminator here
+ size_t after_str_len = strlen(after_str) + 1;
+ memmove(ta->CurrentNode->text + (int)ta->CursorPosition.x - 1, after_str, after_str_len);
}
ta->CursorPosition.x -= 1;
ta->CurrentNode->len -= 1;
@@ -366,6 +407,54 @@ void DeleteChar(TextArea *ta) {
EnsureCursorIsInFrame(ta);
}
+TextArea *CreateTextAreaFromText(TextAreaDisplayParams *DisplayParams, char *text) {
+ if (DisplayParams == NULL || text == NULL) return NULL;
+ TextArea *outp = CreateTextArea(DisplayParams);
+ if (outp == NULL) return NULL;
+
+ const char *line_start = text;
+ const char *next_newline = NULL;
+
+ while (line_start != NULL) {
+ next_newline = strchr(line_start, '\n');
+
+ size_t part_len = next_newline - line_start;
+ if (next_newline == NULL) part_len = strlen(line_start);
+
+ if (!PushNode(outp)) {
+ TraceLog(LOG_ERROR, "Failed to push a node: the initializator returned NULL");
+ break;
+ }
+
+ TextNode *node = (TextNode *)outp->CurrentNode;
+
+ if (part_len > 0) {
+ if (node->cap < part_len) {
+ if (!AddSpaceDetermined(node, part_len)) {
+ TraceLog(LOG_ERROR, "Failed to reserve space for node text");
+ break;
+ }
+ }
+
+ strncpy(node->text, line_start, part_len);
+ node->text[part_len] = 0x0;
+ node->len = part_len;
+ } else {
+ node->len = 0;
+ if (node->text != NULL && node->cap > 0) {
+ node->text[0] = '\0';
+ }
+ }
+
+ outp->CurrentNode = outp->CurrentNode->NextNode;
+ if (next_newline != NULL) line_start = next_newline + 1;
+ else line_start = NULL;
+ }
+
+ outp->CurrentNode = outp->StartNode;
+ return outp;
+}
+
bool IsKeyPressedFix(int key) {
return IsKeyPressed(key) || IsKeyPressedRepeat(key);
}
@@ -474,6 +563,13 @@ void HandleScroll(TextArea *ta, Rectangle rec) {
}
}
+void UpdateTextArea(TextArea *ta, Rectangle rec) {
+ HandleKeyboard(ta);
+ if (IsMouseInRec(rec)) {
+ HandleScroll(ta, rec);
+ }
+}
+
/// draws a text area on the screen. Main draw entry point
void DrawTextArea(TextArea *ta, Rectangle rec) {
// those are used to move a cursor in frame when typing
@@ -481,11 +577,6 @@ void DrawTextArea(TextArea *ta, Rectangle rec) {
ta->DisplayParams->_area_width = rec.width;
TextAreaDisplayParams *params = ta->DisplayParams;
- // int vertical_acc = rec.y - *scroll;
-
- if (IsMouseInRec(rec)) {
- HandleScroll(ta, rec);
- }
Vector2 pos = {
.x = rec.x + params->spacing - params->scroll_h,
@@ -500,7 +591,8 @@ void DrawTextArea(TextArea *ta, Rectangle rec) {
TextNode *node = ta->StartNode;
BeginScissorMode(rec.x, rec.y, rec.width, rec.height);
while (node != NULL) {
- DrawTextEx(*params->font, node->text, pos, params->font_size, params->spacing, COLORSCHEME_BROWN);
+ DrawTextEx(*params->font, node->text, pos,
+ params->font_size, params->spacing, COLORSCHEME_BROWN);
if (node == ta->CurrentNode)
DrawCursor(ta, pos, cursorPos.x);
node = node->NextNode;
diff --git a/src/ui_elements/UI.c b/src/ui_elements/UI.c
index c653731..ffb66ba 100644
--- a/src/ui_elements/UI.c
+++ b/src/ui_elements/UI.c
@@ -1,7 +1,7 @@
#include "UI.h"
#include <raylib.h>
-const int MAX_LINES = 256;
+const int MAX_LINES = 8192;
const int SPACING_H = 1;
void DrawRecBordered(Rectangle rec, Color bg, Color border_color, int border_width) {
@@ -66,6 +66,7 @@ void DrawTextInRec(Rectangle rec, char *text, Font *font, int height, Color colo
BeginScissorMode(rec.x, rec.y, rec.width, rec.height);
for (int i = 1; i < lines; i++) {
+ if (i == MAX_LINES) break;
Vector2 pos = { .x = rec.x, .y = vertical_acc };
char *line_start = text + spans[i-1];
int line_length = spans[i] - spans[i-1];
diff --git a/src/ui_elements/UI.h b/src/ui_elements/UI.h
index f461cf5..bab154c 100644
--- a/src/ui_elements/UI.h
+++ b/src/ui_elements/UI.h
@@ -53,11 +53,11 @@ typedef struct {
} TextArea;
TextArea *CreateTextArea(TextAreaDisplayParams *DisplayParams);
+TextArea *CreateTextAreaFromText(TextAreaDisplayParams *DisplayParams, char *text);
+
void DrawTextArea(TextArea *ta, Rectangle rec);
-void InsertChar(TextArea *ta, char new_char);
-void DeleteChar(TextArea *ta);
+void UpdateTextArea(TextArea *ta, Rectangle rec);
-void HandleKeyboard(TextArea *ta);
char *GetText(TextArea *ta);
void FreeTextArea(TextArea *ta);
diff --git a/src/utils/stringBuilder.c b/src/utils/stringBuilder.c
index 805fb34..485a83b 100644
--- a/src/utils/stringBuilder.c
+++ b/src/utils/stringBuilder.c
@@ -2,7 +2,7 @@
#include <stdlib.h>
#include <string.h>
-void AppendStringBuilder(StringBuilder *sb, const char *str, char separator) {
+void AppendStringBuilder(StringBuilder *sb, const char *str) {
size_t str_len = strlen(str);
if (sb->val == NULL) {
sb->val = malloc(str_len + 1);
@@ -10,17 +10,33 @@ void AppendStringBuilder(StringBuilder *sb, const char *str, char separator) {
memcpy(sb->val, str, str_len);
sb->len = str_len;
} else {
- char *appended = realloc(sb->val, sb->len + str_len + 2);
+ char *appended = realloc(sb->val, sb->len + str_len + 1);
if (appended == NULL) return;
sb->val = appended;
- sb->val[sb->len] = separator;
- memcpy(sb->val + sb->len + 1, str, str_len);
- sb->len = sb->len + str_len + 1;
+ memcpy(sb->val + sb->len, str, str_len);
+ sb->len = sb->len + str_len;
}
sb->val[sb->len] = 0x0;
}
+void AppendStringBuilderSep(StringBuilder *sb, const char *str, char separator) {
+ size_t str_len = strlen(str);
+ if (sb->val == NULL) {
+ AppendStringBuilder(sb, str);
+ return;
+ }
+
+ char *appended = realloc(sb->val, sb->len + str_len + 2);
+ if (appended == NULL) return;
+ sb->val = appended;
+
+ sb->val[sb->len] = separator;
+ memcpy(sb->val + sb->len + 1, str, str_len);
+ sb->len = sb->len + str_len + 1;
+ sb->val[sb->len] = 0x0;
+}
+
void FreeStringBuilder(StringBuilder *sb) {
if (sb->val != NULL) {
free(sb->val);
diff --git a/src/utils/stringBuilder.h b/src/utils/stringBuilder.h
index a9730a2..07da46f 100644
--- a/src/utils/stringBuilder.h
+++ b/src/utils/stringBuilder.h
@@ -8,7 +8,8 @@ typedef struct {
size_t len;
} StringBuilder;
-void AppendStringBuilder(StringBuilder *sb, const char *str, char separator);
+void AppendStringBuilder(StringBuilder *sb, const char *str);
+void AppendStringBuilderSep(StringBuilder *sb, const char *str, char separator);
void FreeStringBuilder(StringBuilder *sb);
#endif // SB_H
diff --git a/src/wren_inter/wren_inter.c b/src/wren_inter/wren_inter.c
index 69df112..10ecc93 100644
--- a/src/wren_inter/wren_inter.c
+++ b/src/wren_inter/wren_inter.c
@@ -1,51 +1,42 @@
#include "wren_inter.h"
#include "../utils/stringBuilder.h"
+#include <stddef.h>
#include <string.h>
#include <raylib.h>
#include <stdio.h>
#include <wren.h>
-StringBuilder stdout_sb = {0};
-
void writeFn(WrenVM* vm, const char* text) {
- AppendStringBuilder(&stdout_sb, text, '\n');
+ StringBuilder* sb = (StringBuilder*)wrenGetUserData(vm);
+ AppendStringBuilder(sb, text);
}
-
+
void errorFn(WrenVM* vm, WrenErrorType errorType,
const char* module, const int line,
const char* msg)
{
+ StringBuilder* sb = (StringBuilder*)wrenGetUserData(vm);
switch (errorType)
{
case WREN_ERROR_COMPILE:
- {
- // TraceLog(LOG_ERROR, "[%s line %d] [Error] %s", module, line, msg);
- AppendStringBuilder(&stdout_sb, "Comptime error: ", '\n');
- AppendStringBuilder(&stdout_sb, msg, ' ');
- } break;
+ AppendStringBuilder(sb, "Comptime error: ");
+ AppendStringBuilder(sb, msg);
+ break;
case WREN_ERROR_STACK_TRACE:
- {
- AppendStringBuilder(&stdout_sb, "Stack trace: ", '\n');
- AppendStringBuilder(&stdout_sb, msg, ' ');
- // TraceLog(LOG_ERROR, "[%s line %d] in %s", module, line, msg);
- } break;
+ AppendStringBuilder(sb, "Stack trace: ");
+ AppendStringBuilder(sb, msg);
+ break;
case WREN_ERROR_RUNTIME:
- {
- AppendStringBuilder(&stdout_sb, "Runtime error: ", '\n');
- AppendStringBuilder(&stdout_sb, msg, ' ');
- // TraceLog(LOG_ERROR, "[Runtime Error] %s", msg);
- } break;
+ AppendStringBuilder(sb, "Runtime error: ");
+ AppendStringBuilder(sb, msg);
+ break;
}
}
char *EvaluateScript(char *script) {
TraceLog(LOG_INFO, "Evaluating %s...", script);
- WrenConfiguration config;
- wrenInitConfiguration(&config);
- config.writeFn = writeFn;
- config.errorFn = errorFn;
+ WrenVM *vm = InterpreterPrepareMachine();
- WrenVM* vm = wrenNewVM(&config);
if (vm == NULL) {
TraceLog(LOG_ERROR, "Failed to initialize a wren vm");
return NULL;
@@ -57,11 +48,32 @@ char *EvaluateScript(char *script) {
case WREN_RESULT_COMPILE_ERROR: break;
case WREN_RESULT_RUNTIME_ERROR: break;
}
- printf("Wren outp: %s", stdout_sb.val);
- wrenFreeVM(vm);
- if (stdout_sb.val == NULL) return NULL;
- char *outp = strdup(stdout_sb.val);
- FreeStringBuilder(&stdout_sb);
+ char *outp = GetMachineOutput(vm);
+ InterpreterFreeMachine(vm);
+
return outp;
}
+
+WrenVM *InterpreterPrepareMachine() {
+ WrenConfiguration config;
+ wrenInitConfiguration(&config);
+ config.writeFn = writeFn;
+ config.errorFn = errorFn;
+
+ StringBuilder *stdout_sb = calloc(1, sizeof(StringBuilder));
+ config.userData = stdout_sb;
+ return wrenNewVM(&config);
+}
+
+char *GetMachineOutput(WrenVM *vm) {
+ StringBuilder* sb = (StringBuilder*)wrenGetUserData(vm);
+ if (sb == NULL || sb->val == NULL) return NULL;
+ return strdup(sb->val);
+}
+
+void InterpreterFreeMachine(WrenVM *vm) {
+ StringBuilder* sb = (StringBuilder*)wrenGetUserData(vm);
+ if (sb != NULL && sb->val != NULL) free(sb);
+ wrenFreeVM(vm);
+}
diff --git a/src/wren_inter/wren_inter.h b/src/wren_inter/wren_inter.h
index 981a606..100f946 100644
--- a/src/wren_inter/wren_inter.h
+++ b/src/wren_inter/wren_inter.h
@@ -1,6 +1,12 @@
#ifndef WREN_INTER_H
#define WREN_INTER_H
+#include <wren.h>
+
char *EvaluateScript(char *script);
+WrenVM *InterpreterPrepareMachine();
+char *GetMachineOutput(WrenVM *vm);
+void InterpreterFreeMachine(WrenVM *vm);
+
#endif // WREN_INTER_H