From d1a1ebd54cabc6646f20f6b1b341751a2bf3c2ec Mon Sep 17 00:00:00 2001 From: Physick <96335032+DegustatorPonos@users.noreply.github.com> Date: Sun, 2 Aug 2026 22:52:27 +0500 Subject: puzzle parser --- src/puzzles/parser.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/puzzles/puzzle.c | 6 +- src/puzzles/puzzle.h | 3 +- 3 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 src/puzzles/parser.c (limited to 'src/puzzles') diff --git a/src/puzzles/parser.c b/src/puzzles/parser.c new file mode 100644 index 0000000..cb958e7 --- /dev/null +++ b/src/puzzles/parser.c @@ -0,0 +1,160 @@ +#include +#include "puzzle.h" +#include +#include +#include +#include +#include + +/// Reads a uint8_t from file. +/// Assumes that the file is on the position +uint8_t read_u8(FILE *file) { + uint8_t outp; + fread(&outp, 1, 1, file); + return outp; +} + +/// Reads a uint32_t (little-endian) from file. +/// Assumes that the file is on the position +uint32_t read_u32(FILE *file) { + uint32_t outp = 0; + for (int i = 0; i < 4; i++) { + outp += ((uint32_t)read_u8(file)) << (i * 8); + } + return outp; +} + +/// Reads a double from file. +/// Assumes that the file is on the position +double read_double(FILE *file) { + double outp; + fread(&outp, sizeof(double), 1, file); + return outp; +} + +/// Reads a null terminated string from file. +/// Assumes that the file if on the position. +/// Allocates the string. +char *read_string(FILE *file) { + char buf[8192]; + size_t idx = 0; + int c; + + while (idx < sizeof(buf) - 1) { + c = fgetc(file); + + if (c == 0 || c == EOF) break; + + buf[idx] = (char)c; + idx += 1; + } + + buf[idx] = 0x0; + return strdup(buf); +} + +typedef enum { + TYPE_NULL = 0, + TYPE_BOOL = 1, + TYPE_NUM = 2, + TYPE_STRING = 3, + TYPE_LIST = 4, +} V1_IO_TYPE; + +void ReadPuzzleIO_V1(FILE *file, PuzzleIO *io) { + uint8_t type = read_u8(file); + + switch (type) { + case TYPE_NULL: // NULL + io->type = WREN_TYPE_NULL; + io->value = NULL; + break; + + case TYPE_BOOL: + { + bool *outp = malloc(sizeof(bool)); + *outp = read_u8(file) != 0; + io->type = WREN_TYPE_BOOL; + io->value = outp; + break; + } + + case TYPE_NUM: + { + double *outp = malloc(sizeof(double)); + *outp = read_double(file); + io->type = WREN_TYPE_NUM; + io->value = outp; + break; + } + + case TYPE_STRING: + io->type = WREN_TYPE_STRING; + io->value = read_string(file); + break; + + case TYPE_LIST: + TraceLog(LOG_ERROR, "The arrays are not yet supported"); + io->type = WREN_TYPE_NULL; + io->value = NULL; + break; + + default: + return; + } +} + +void readTestV1(FILE *file, Test *outp) { + outp->RecieverName = read_string(file); + outp->MainMethodSignature = read_string(file); + outp->argc = read_u32(file); + outp->argv = malloc(sizeof(PuzzleIO) * outp->argc); + + for (size_t i = 0; i < outp->argc; i++) { + ReadPuzzleIO_V1(file, &outp->argv[i]); + } + + ReadPuzzleIO_V1(file, &outp->ExpectedResult); +} + +// Reads file with the specification from puzzle_specs_v1.md. +// Assumes the first byte of the file was read and the file was not rewinded. +Puzzle *parseFileV1(FILE *file) { + Puzzle *outp = malloc(sizeof(Puzzle)); + if (outp == NULL) return NULL; + + outp->Name = read_string(file); + outp->Description = read_string(file); + outp->InitialCode = read_string(file); + outp->TestC = read_u32(file); + + outp->Tests = malloc(sizeof(Test) * outp->TestC); + for (size_t i = 0; i < outp->TestC; i++) { + readTestV1(file, &outp->Tests[i]); + } + + return outp; +} + +Puzzle *ReadPuzzleFromFile(const char *path) { + FILE *file = fopen(path, "r"); + if (file == NULL) { + perror("Failed to parse the puzzle file"); + return NULL; + } + + uint8_t spec_version = read_u8(file); + printf("Version: %d\n", spec_version); + Puzzle *outp = NULL; + switch (spec_version) { + case 1: + outp = parseFileV1(file); + break; + default: + TraceLog(LOG_ERROR, "Failed to parse the puzzle file: unknown spec version"); + break; + } + + fclose(file); + return outp; +} diff --git a/src/puzzles/puzzle.c b/src/puzzles/puzzle.c index 2da9ffc..6d0a4a0 100644 --- a/src/puzzles/puzzle.c +++ b/src/puzzles/puzzle.c @@ -41,9 +41,9 @@ 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); + if (t->RecieverName != NULL) free(t->RecieverName); + if (t->MainMethodSignature != NULL) free(t->MainMethodSignature); + if (t->argv != NULL) free(t->argv); } free(Tests); } diff --git a/src/puzzles/puzzle.h b/src/puzzles/puzzle.h index e7aebb1..20193ca 100644 --- a/src/puzzles/puzzle.h +++ b/src/puzzles/puzzle.h @@ -56,8 +56,7 @@ typedef struct { Test *Tests; } Puzzle; -// TODO -void ReadPuzzleFromFile(const char *path); +Puzzle *ReadPuzzleFromFile(const char *path); void FreePuzzle(Puzzle *self); /// A prebuilt puzzle. Used for debuging -- cgit v1.3