diff --git a/.github/workflows/continuous-integration-v2.yml b/.github/workflows/continuous-integration-v2.yml index a846a34..dfd7932 100644 --- a/.github/workflows/continuous-integration-v2.yml +++ b/.github/workflows/continuous-integration-v2.yml @@ -16,7 +16,8 @@ on: #CI workflows using a matrix jobs: - run-test-suites: + run-test-cases: + continue-on-error: true strategy: matrix: platforms: @@ -24,14 +25,35 @@ jobs: - { os: windows-latest, preinstall: , gdb_skip: false } - { os: macos-latest, preinstall: , gdb_skip: true } commands: - - make tests - - make tests-gdb + - { exec: make tests, gdb: false } + - { exec: make tests-gdb, gdb: true } runs-on: ${{ matrix.platforms.os }} steps: - uses: actions/checkout@v4 - name: Preinstall dependencies run: ${{ matrix.platforms.preinstall }} - - name: run the test suites - if: matrix.platforms.gdb_skip != true - run: ${{ matrix.commands }} + - name: run the test cases + if: matrix.commands.gdb == false || matrix.platforms.gdb_skip == false + run: ${{ matrix.commands.exec }} + + #TODO: hook this up to real script files + run-test-repl-scripts: + continue-on-error: true + needs: run-test-cases + strategy: + matrix: + platforms: + - { os: ubuntu-latest } + - { os: windows-latest } + - { os: macos-latest } + commands: + - { build: make repl, run: out/repl.exe -f '../scripts/example.toy' } + + runs-on: ${{ matrix.platforms.os }} + steps: + - uses: actions/checkout@v4 + - name: compile the repl + run: ${{ matrix.commands.build }} + - name: run the repl scripts + run: ${{ matrix.commands.run }} diff --git a/makefile b/makefile index e19d1bb..d29c463 100644 --- a/makefile +++ b/makefile @@ -9,7 +9,7 @@ export TOY_OUTDIR=out export TOY_OBJDIR=obj #targets -all: tests +all: .PHONY: source source: @@ -24,7 +24,7 @@ tests: clean $(MAKE) -C tests -k .PHONY: tests-gdb -tests-gdb: +tests-gdb: clean $(MAKE) -C tests all-gdb -k #util targets @@ -34,9 +34,6 @@ $(TOY_OUTDIR): $(TOY_OBJDIR): mkdir $(TOY_OBJDIR) -$(TOY_OBJDIR)/%.o: $(TOY_SOURCEDIR)/%.c - $(CC) -c -o $@ $< $(addprefix -I,$(TOY_SOURCEDIR)) $(CFLAGS) - #util commands .PHONY: clean clean: @@ -68,5 +65,3 @@ else @echo "Deletion failed - what platform is this?" endif -.PHONY: rebuild -rebuild: clean all diff --git a/repl/main.c b/repl/main.c index 4b2c429..13f1f04 100644 --- a/repl/main.c +++ b/repl/main.c @@ -3,12 +3,72 @@ #include #include +//utilities +unsigned char* readFile(char* path, int* size) { + //open the file + FILE* file = fopen(path, "rb"); + if (file == NULL) { + *size = -1; //missing file error + return NULL; + } + + //determine the file's length + fseek(file, 0L, SEEK_END); + *size = ftell(file); + rewind(file); + + //make some space + unsigned char* buffer = TOY_ALLOCATE(unsigned char, *size + 1); + if (buffer == NULL) { + fclose(file); + return NULL; + } + + // + if (fread(buffer, sizeof(unsigned char), *size, file) < *size) { + fclose(file); + *size = -2; //singal a read error + return NULL; + } + + fclose(file); + + buffer[(*size)++] = '\0'; + return buffer; +} + +int dir(char* dest, const char* src) { + //extract the directory from src, and store it in dest + +#if defined(_WIN32) || defined(_WIN64) + char* p = strrchr(src, '\\'); +#else + char* p = strrchr(src, '/'); +#endif + + int len = p != NULL ? p - src + 1 : 0; + strncpy(dest, src, len); + dest[len] = '\0'; + + return len; +} + +#define APPEND(dest, src) \ + memcpy((dest) + (strlen(dest)), (src), strlen((src))); + +#if defined(_WIN32) || defined(_WIN64) + #define FLIPSLASH(str) for (int i = 0; str[i]; i++) str[i] = str[i] == '/' ? '\\' : str[i]; +#else + #define FLIPSLASH(str) for (int i = 0; str[i]; i++) str[i] = str[i] == '\\' ? '/' : str[i]; +#endif + //handle command line arguments typedef struct CmdLine { bool error; bool help; bool version; - const char* infile; + char* infile; + int infileLength; } CmdLine; void usageCmdLine(int argc, const char* argv[]) { @@ -46,11 +106,11 @@ freely, subject to the following restrictions:\n\ misrepresented as being the original software.\n\ 3. This notice may not be removed or altered from any source distribution.\n\n"; - printf(license); + printf("%s",license); } CmdLine parseCmdLine(int argc, const char* argv[]) { - CmdLine cmd = { .error = false, .help = false, .version = false, .infile = NULL }; + CmdLine cmd = { .error = false, .help = false, .version = false, .infile = NULL, .infileLength = 0 }; for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { @@ -66,7 +126,18 @@ CmdLine parseCmdLine(int argc, const char* argv[]) { cmd.error = true; } else { - cmd.infile = argv[++i]; + if (cmd.infile != NULL) { //don't leak + TOY_FREE_ARRAY(char, cmd.infile, strlen(cmd.infile)); + } + + i++; + + //total space to reserve - it's actually longer than needed, due to the exe name being removed + cmd.infileLength = strlen(argv[0]) + strlen(argv[i]); + cmd.infile = TOY_ALLOCATE(char, cmd.infileLength); + dir(cmd.infile, argv[0]); + APPEND(cmd.infile, argv[i]); + FLIPSLASH(cmd.infile); } } @@ -78,49 +149,6 @@ CmdLine parseCmdLine(int argc, const char* argv[]) { return cmd; } -//utilities -unsigned char* readFile(const char* path, int* size) { - //open the file - FILE* file = fopen(path, "rb"); - if (file == NULL) { - *size = -1; //missing file error - return NULL; - } - - //determine the file's length - fseek(file, 0L, SEEK_END); - *size = ftell(file); - rewind(file); - - //make some space - unsigned char* buffer = TOY_ALLOCATE(unsigned char, *size); - if (buffer == NULL) { - fclose(file); - return NULL; - } - - // - if (fread(buffer, sizeof(unsigned char), *size, file) < *size) { - fclose(file); - *size = -2; //singal a read error - return NULL; - } - - fclose(file); - return buffer; -} - -void dir(char* dest, const char* src) { - //extract the directory from src, and store it in dest - const char* p = strrchr(src, '/'); - int len = p != NULL ? p - src + 1 : 0; - strncpy(dest, src, len); - dest[len] = '\0'; -} - -#define APPEND(dest, src) \ - sprintf(dest + strlen(dest), src) - //main file int main(int argc, const char* argv[]) { CmdLine cmd = parseCmdLine(argc, argv); @@ -139,6 +167,10 @@ int main(int argc, const char* argv[]) { int size; unsigned char* source = readFile(cmd.infile, &size); + TOY_FREE_ARRAY(char, cmd.infile, cmd.infileLength); //clean this up, since it's no longer needed + cmd.infile = NULL; + cmd.infileLength = 0; + //check the file if (source == NULL) { if (size == 0) { @@ -225,5 +257,4 @@ int main(int argc, const char* argv[]) { return 0; } - //TODO: simple and consistent way to print an AST and Toy_Value \ No newline at end of file diff --git a/repl/makefile b/repl/makefile index aeddc98..1738a97 100644 --- a/repl/makefile +++ b/repl/makefile @@ -2,7 +2,7 @@ CC=gcc CFLAGS+=-g -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable LIBS+=-lm -lToy -LDFLAGS+=-Wl,-R -Wl,'$$ORIGIN' +LDFLAGS+=-Wl,-rpath,'$$ORIGIN' #directories REPL_ROOTDIR=.. @@ -18,10 +18,10 @@ REPL_OBJFILES=$(addprefix $(REPL_OBJDIR)/,$(notdir $(REPL_REPLFILES:.c=.o))) REPL_TARGETNAME=repl.exe #linker fix -LDFLAGS+=-L$(realpath $(shell pwd)/$(REPL_OUTDIR)) +LDFLAGS+=-L$(realpath $(REPL_OUTDIR)) #build the object files, compile the test cases, and run -all: clean build link +all: build link #targets for each step .PHONY: build @@ -43,6 +43,12 @@ $(REPL_OBJDIR)/%.o: $(REPL_REPLDIR)/%.c $(REPL_OUTDIR)/$(REPL_TARGETNAME): $(REPL_OBJFILES) $(CC) -DTOY_IMPORT $(CFLAGS) -o $@ $(REPL_OBJFILES) $(LDFLAGS) $(LIBS) +ifeq ($(shell uname),Darwin) #dylib fix + otool -L $@ + install_name_tool -add_rpath @executable_path/. $@ + install_name_tool -change ../out/libToy.dylib @executable_path/libToy.dylib $@ + otool -L $@ +endif #util commands .PHONY: clean diff --git a/source/makefile b/source/makefile index e45e02e..e008fed 100644 --- a/source/makefile +++ b/source/makefile @@ -20,21 +20,21 @@ SRC_TARGETNAME=Toy #SRC_LIBLINE is a fancy way of making the linker work correctly ifeq ($(shell uname),Linux) SRC_TARGETEXT=.so - SRC_LIBLINE=-Wl,-rpath,. -Wl,--out-implib=$(SRC_OUTDIR)/lib$(SRC_TARGETNAME).a -Wl,--whole-archive $(SRC_OBJFILES) -Wl,--no-whole-archive + SRC_LIBLINE=-shared -Wl,-rpath,. -Wl,--out-implib=$(SRC_OUTDIR)/lib$(SRC_TARGETNAME).a -Wl,--whole-archive $(SRC_OBJFILES) -Wl,--no-whole-archive CFLAGS+=-fPIC -# else ifeq ($(OS),Windows_NT) -# SRC_TARGETEXT=.dll -# SRC_LIBLINE=-Wl,-rpath,. -Wl,--out-implib=$(SRC_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(SRC_OBJFILES) -Wl,--no-whole-archive -# else ifeq ($(shell uname),Darwin) -# SRC_TARGETEXT=.dylib -# SRC_LIBLINE=$(SRC_OBJFILES) +else ifeq ($(OS),Windows_NT) + SRC_TARGETEXT=.dll + SRC_LIBLINE=-shared -Wl,-rpath,. -Wl,--out-implib=$(SRC_OUTDIR)/lib$(SRC_TARGETNAME).a -Wl,--whole-archive $(SRC_OBJFILES) -Wl,--no-whole-archive -Wl,--export-all-symbols -Wl,--enable-auto-import +else ifeq ($(shell uname),Darwin) + SRC_TARGETEXT=.dylib + SRC_LIBLINE=-shared -Wl,-rpath,. $(SRC_OBJFILES) else @echo "Platform test failed - what platform is this?" exit 1 endif #build the object files, compile the test cases, and run -all: clean build link +all: build link #targets for each step .PHONY: build @@ -42,7 +42,7 @@ build: $(SRC_OUTDIR) $(SRC_OBJDIR) $(SRC_OBJFILES) .PHONY: link link: $(SRC_OUTDIR) - $(CC) -DTOY_EXPORT $(CFLAGS) -shared -o $(SRC_OUTDIR)/lib$(SRC_TARGETNAME)$(SRC_TARGETEXT) $(SRC_LIBLINE) + $(CC) -DTOY_EXPORT $(CFLAGS) -o $(SRC_OUTDIR)/lib$(SRC_TARGETNAME)$(SRC_TARGETEXT) $(SRC_LIBLINE) #util targets $(SRC_OUTDIR):