mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Squashed: Added integration and standalone tests, read more
This wasn't an easy fix, as it was primarily the test pipelines that were failing. I resorted to using forced pushes to run the CI, to try and track down the problems. The primary cause seems to be the differences in how each supported platform handles file paths, specifically, slash vs. backslash. I've also added gdb scripts to set up automated breakpoints, and to run operations on them to check for issues - the 'gdb_init' files are mostly empty for the time being. commit a34b0ff5d407bbe7d70ff9504aa035ec6fbecb7c Author: Kayne Ruse <kayneruse@gmail.com> Date: Fri Oct 18 11:45:40 2024 +1100 Restored the workflows commit eb3d94f30d4dc4150139517f44cc874f2901124f Author: Kayne Ruse <kayneruse@gmail.com> Date: Fri Oct 18 11:35:39 2024 +1100 I think the library path on macos is fixed commit 964572b5e93c7cb464686f19ddbe3e9d315f391b Author: Kayne Ruse <kayneruse@gmail.com> Date: Fri Oct 18 11:22:56 2024 +1100 I think the file paths are fixed commit 1721f3da7252b4063f4347926e800ef4f7c9bf4c Author: Kayne Ruse <kayneruse@gmail.com> Date: Thu Oct 17 15:57:28 2024 +1100 Added standalone tests commit 90c783f4059d88f4a7bbaf18215a9b414f3ab66f Author: Kayne Ruse <kayneruse@gmail.com> Date: Thu Oct 17 15:01:18 2024 +1100 Trying to fix the integration test pipeline commit fccced1396568a55c1385e2f1b04fedf7c2585a5 Author: Kayne Ruse <kayneruse@gmail.com> Date: Wed Oct 16 00:31:39 2024 +1100 Workflow integration tests are not passing commit 6b1e0d1e0f89291e89768bf6102f4f7ed4581496 Author: Kayne Ruse <kayneruse@gmail.com> Date: Tue Oct 15 20:07:20 2024 +1100 Fixed file paths in workflow commit c0f1ec78fe79a5abb34c3e05308236cb18c23b97 Author: Kayne Ruse <kayneruse@gmail.com> Date: Tue Oct 15 19:46:14 2024 +1100 Moved example scripts into proper integration tests Also adjusted makefiles to allow easy invoking of the tests. Adjusted and updated CI to invoke tests correctly. Fixed #141
This commit is contained in:
67
.github/workflows/continuous-integration-v2.yml
vendored
67
.github/workflows/continuous-integration-v2.yml
vendored
@@ -14,48 +14,73 @@ on:
|
||||
- v2
|
||||
workflow_dispatch:
|
||||
|
||||
#CI workflows using a matrix
|
||||
#CI workflows using the matrix strategy, skipping GDB if it's not supported for the platform
|
||||
jobs:
|
||||
run-test-cases:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
platforms:
|
||||
- { os: ubuntu-latest, preinstall: sudo apt-get install gdb, gdb_skip: false }
|
||||
- { os: windows-latest, preinstall: , gdb_skip: false }
|
||||
- { os: macos-latest, preinstall: , gdb_skip: true }
|
||||
- { os: ubuntu-latest, preinstall: sudo apt-get install gdb, gdb_enabled: true }
|
||||
- { os: windows-latest, preinstall: , gdb_enabled: true }
|
||||
- { os: macos-latest, preinstall: , gdb_enabled: false }
|
||||
commands:
|
||||
- { exec: make tests, gdb: false }
|
||||
- { exec: make tests-gdb, gdb: true }
|
||||
- { exec: make test-cases, gdb: false }
|
||||
- { exec: make test-cases-gdb, gdb: true }
|
||||
|
||||
runs-on: ${{ matrix.platforms.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Preinstall dependencies
|
||||
if: (matrix.commands.gdb == true && matrix.platforms.gdb_enabled == false) != true
|
||||
run: ${{ matrix.platforms.preinstall }}
|
||||
- name: run the test cases
|
||||
if: matrix.commands.gdb == false || matrix.platforms.gdb_skip == false
|
||||
- name: run the tests
|
||||
if: (matrix.commands.gdb == true && matrix.platforms.gdb_enabled == false) != true
|
||||
run: ${{ matrix.commands.exec }}
|
||||
|
||||
#TODO: hook this up to real script files, preferably in the test section
|
||||
run-test-repl-scripts:
|
||||
continue-on-error: true
|
||||
run-test-integrations:
|
||||
needs: run-test-cases
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
platforms:
|
||||
- { os: ubuntu-latest }
|
||||
- { os: windows-latest }
|
||||
- { os: macos-latest }
|
||||
- { os: ubuntu-latest, preinstall: sudo apt-get install gdb, gdb_enabled: true }
|
||||
- { os: windows-latest, preinstall: , gdb_enabled: true }
|
||||
- { os: macos-latest, preinstall: , gdb_enabled: false }
|
||||
commands:
|
||||
- { build: make repl, run: out/repl.exe -f '../scripts/example.toy' }
|
||||
- { build: make repl, run: out/repl.exe -f '../scripts/example-print.toy' }
|
||||
- { build: make repl, run: out/repl.exe -f '../scripts/example-variables.toy' }
|
||||
- { exec: make test-integrations, gdb: false }
|
||||
- { exec: make test-integrations-gdb, gdb: true }
|
||||
|
||||
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 }}
|
||||
- name: Preinstall dependencies
|
||||
if: (matrix.commands.gdb == true && matrix.platforms.gdb_enabled == false) != true
|
||||
run: ${{ matrix.platforms.preinstall }}
|
||||
- name: run the tests
|
||||
if: (matrix.commands.gdb == true && matrix.platforms.gdb_enabled == false) != true
|
||||
run: ${{ matrix.commands.exec }}
|
||||
|
||||
run-test-benchmarks:
|
||||
if: false #Not ready yet
|
||||
needs: run-test-integrations
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
platforms:
|
||||
- { os: ubuntu-latest, preinstall: sudo apt-get install gdb, gdb_enabled: true }
|
||||
- { os: windows-latest, preinstall: , gdb_enabled: true }
|
||||
- { os: macos-latest, preinstall: , gdb_enabled: false }
|
||||
commands:
|
||||
- { exec: make test-benchmarks, gdb: false }
|
||||
- { exec: make test-benchmarks-gdb, gdb: true }
|
||||
|
||||
runs-on: ${{ matrix.platforms.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Preinstall dependencies
|
||||
if: (matrix.commands.gdb == true && matrix.platforms.gdb_enabled == false) != true
|
||||
run: ${{ matrix.platforms.preinstall }}
|
||||
- name: run the tests
|
||||
if: (matrix.commands.gdb == true && matrix.platforms.gdb_enabled == false) != true
|
||||
run: ${{ matrix.commands.exec }}
|
||||
|
||||
29
.github/workflows/standalone_tests.yml
vendored
Normal file
29
.github/workflows/standalone_tests.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Standalone Tests
|
||||
|
||||
#trigger when these occur
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
#These tests are more stand-alone than the others
|
||||
jobs:
|
||||
run-test-cases:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
platforms:
|
||||
- { os: ubuntu-latest, preinstall: sudo apt-get install gdb, gdb_enabled: true }
|
||||
- { os: windows-latest, preinstall: , gdb_enabled: true }
|
||||
- { os: macos-latest, preinstall: , gdb_enabled: false }
|
||||
commands:
|
||||
- { exec: make -C tests/standalone -k, gdb: false }
|
||||
- { exec: make -C tests/standalone gdb -k, gdb: true }
|
||||
|
||||
runs-on: ${{ matrix.platforms.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Preinstall dependencies
|
||||
if: (matrix.commands.gdb == true && matrix.platforms.gdb_enabled == false) != true
|
||||
run: ${{ matrix.platforms.preinstall }}
|
||||
- name: run the tests
|
||||
if: (matrix.commands.gdb == true && matrix.platforms.gdb_enabled == false) != true
|
||||
run: ${{ matrix.commands.exec }}
|
||||
@@ -16,7 +16,7 @@ v2 is a ground-up rewrite, with additions, changes and deletions to the language
|
||||
|
||||
The [Issue Tracker](https://github.com/Ratstail91/Toy/issues) is a good place to see what tasks and issues are currently waiting to be addressed. The [toy.h](https://github.com/Ratstail91/Toy/blob/v2/source/toy.h) source file is a quick way to see what building blocks are available in the source code. There are also a number of comments prepended with `TODO` scattered throughout the source code, as reminders of planned features.
|
||||
|
||||
The [test cases](https://github.com/Ratstail91/Toy/tree/v2/tests/cases), which test individual parts of the code in isolation, can be a good way to see how those parts are used. Likewise, the [REPL](https://github.com/Ratstail91/Toy/tree/v2/repl) shows a practical usage of Toy.
|
||||
The [tests directory](https://github.com/Ratstail91/Toy/tree/v2/tests), which holds a collection of automated tests for the CI pipeline, can be a good way to see how those parts are used. Likewise, the [REPL](https://github.com/Ratstail91/Toy/tree/v2/repl) shows a practical usage of Toy.
|
||||
|
||||
*v2 is under heavy development, and as such may not be in a working state yet. Your patience and feedback can help, but missing features such as a documentation website are coming, eventually.*
|
||||
|
||||
@@ -30,10 +30,10 @@ graph TB
|
||||
Toy_Value ---> Toy_String
|
||||
Toy_Value ---> Toy_Stack
|
||||
Toy_Value ---> Toy_Table
|
||||
Toy_Array
|
||||
Toy_Value ---> Toy_Array
|
||||
```
|
||||
|
||||
In addition, [toy_common.h](https://github.com/Ratstail91/Toy/blob/v2/source/toy_common.h) grants platform portability and version info, while [toy_console_colors.h](https://github.com/Ratstail91/Toy/blob/v2/source/toy_console_colors.h) provides string constants as macros that help with console output (where supported).
|
||||
In addition, [toy_common.h](https://github.com/Ratstail91/Toy/blob/v2/source/toy_common.h) grants platform portability and version info, while [toy_console_colors.h](https://github.com/Ratstail91/Toy/blob/v2/source/toy_console_colors.h) provides string constants as macros that can help with console output (where supported).
|
||||
|
||||
# Coding Habits
|
||||
|
||||
@@ -43,15 +43,29 @@ Here's a few coding habits that I use to keep the source code consistent. While
|
||||
|
||||
When adding a new piece of code, it must be thoroughly tested via a [test case](https://github.com/Ratstail91/Toy/tree/v2/tests/cases). If it has multiple features, they should be tested individually, and in combination with each other. Any kind of corner case which can cause an issue on any supported platform must be resolved (I'm happy to help with this, if needed).
|
||||
|
||||
Once a feature has been tested on its own, it can be added to or expanded in the [integration tests](https://github.com/Ratstail91/Toy/tree/v2/tests/integrations).
|
||||
|
||||
This is probably the most important habit listed here. While I'm not too fussy as to how the tests are written, they do need to prove that the code works flawlessly. Toy is intended to be used by others (potentially many others), so please write simple and straight forward tests to ensure correctness.
|
||||
|
||||
## Tabs, 4 Characters Wide
|
||||
|
||||
I use tabs over spaces, with a width of 4. I don't have a linter, please don't make me use one.
|
||||
I use tabs over spaces, with a width of 4. I don't have a linter, please don't make me use one. For those who care, here's my `.vimrc`:
|
||||
|
||||
```bash
|
||||
" Load the defaults
|
||||
runtime defaults.vim
|
||||
|
||||
" my custom stuff
|
||||
set tabstop=4
|
||||
set shiftwidth=4
|
||||
|
||||
set autoindent
|
||||
set smartindent
|
||||
```
|
||||
|
||||
## Error Messages
|
||||
|
||||
Fatal errors have this general format:
|
||||
Fatal errors in the source code have this general format:
|
||||
|
||||
```c
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: [Info]\n" TOY_CC_RESET);
|
||||
@@ -60,7 +74,7 @@ exit(-1);
|
||||
|
||||
The use of `fprintf()` will ensure the error is written to the console, and allows extra information to be printed - just replace `[Info]` with the relevant output. These kinds of fatal errors are intended to catch issues with the language itself, rather than errors in the Toy scripts.
|
||||
|
||||
In the test cases, the `exit(-1)` is instead replaced with `return -1` to allow `main()` to clean up that test set, and run others if needed.
|
||||
In the test cases, the `exit(-1)` is instead replaced with `return -1` to allow `main()` to clean up that test case, and run others if needed.
|
||||
|
||||
## Naming Things
|
||||
|
||||
@@ -124,5 +138,5 @@ The directories in the repository's root have certain intended uses. If you find
|
||||
| scripts | Storage for various example scripts written in Toy that can be loaded and executed by the repl. |
|
||||
| source | The source directory for the core of the Toy programming language. |
|
||||
| tests | The source directory for the testing systems. Within, `cases/` is used for test cases, `benchmarks/` for benchmarking, etc. |
|
||||
| tools | The source directory for various external tools. |
|
||||
| tools | The source directory for various standalone tools. |
|
||||
|
||||
|
||||
11
README.md
11
README.md
@@ -15,7 +15,7 @@ This repository holds the reference implementation for Toy version 2.x, written
|
||||
* Simple C-like syntax
|
||||
* Intermediate AST representation
|
||||
* Strong, but optional type system
|
||||
* First-class functions
|
||||
* First-class functions and types
|
||||
* Extensible via external libraries
|
||||
* Can re-direct output, error and assertion failure messages
|
||||
* Open source under the zlib license
|
||||
@@ -39,14 +39,13 @@ var foobar = 42;
|
||||
|
||||
Supported platforms are: `linux-latest`, `windows-latest`, `macos-latest`, using [GitHub's standard runners](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories).
|
||||
|
||||
To build the library, run `make source`.
|
||||
To build the library and repl, run `make repl`.
|
||||
To build and run the test cases, run `make tests`.
|
||||
To build and run the test cases under gdb, run `make tests-gdb`.
|
||||
To build the shared library, run `make source`.
|
||||
To build the shared library and repl, run `make repl`.
|
||||
To build and run the standard available tests, run `make tests`.
|
||||
|
||||
# Tools
|
||||
|
||||
*Coming Soon.*
|
||||
*Coming Soon, see #126 for details.*
|
||||
|
||||
# License
|
||||
|
||||
|
||||
42
makefile
42
makefile
@@ -6,11 +6,15 @@
|
||||
|
||||
#directories
|
||||
export TOY_SOURCEDIR=source
|
||||
export TOY_REPLDIR=repl
|
||||
export TOY_CASESDIR=tests/cases
|
||||
export TOY_INTEGRATIONSDIR=tests/integrations
|
||||
export TOY_BENCHMARKSDIR=tests/benchmarks
|
||||
export TOY_OUTDIR=out
|
||||
export TOY_OBJDIR=obj
|
||||
|
||||
#targets
|
||||
all:
|
||||
#all:
|
||||
|
||||
.PHONY: source
|
||||
source:
|
||||
@@ -20,13 +24,39 @@ source:
|
||||
repl: source
|
||||
$(MAKE) -C repl -k
|
||||
|
||||
#various kinds of available tests
|
||||
.PHONY: tests
|
||||
tests: clean
|
||||
$(MAKE) -C tests -k
|
||||
tests: clean test-cases test-integrations test-benchmarks
|
||||
|
||||
.PHONY: tests-gdb
|
||||
tests-gdb: clean
|
||||
$(MAKE) -C tests all-gdb -k
|
||||
.PHONY: test-cases
|
||||
test-cases:
|
||||
$(MAKE) -C $(TOY_CASESDIR) -k
|
||||
|
||||
.PHONY: test-integrations
|
||||
test-integrations:
|
||||
$(MAKE) -C $(TOY_INTEGRATIONSDIR) -k
|
||||
|
||||
.PHONY: test-benchmarks
|
||||
test-benchmarks:
|
||||
$(MAKE) -C $(TOY_BENCHMARKSDIR) -k
|
||||
|
||||
#same as above, but with GDB
|
||||
.PHONY: test-gdb
|
||||
test-gdb: clean test-cases-gdb test-integrations-gdb test-benchmarks-gdb
|
||||
|
||||
.PHONY: test-cases-gdb
|
||||
test-cases-gdb:
|
||||
$(MAKE) -C $(TOY_CASESDIR) gdb -k
|
||||
|
||||
.PHONY: test-integrations-gdb
|
||||
test-integrations-gdb:
|
||||
$(MAKE) -C $(TOY_INTEGRATIONSDIR) gdb -k
|
||||
|
||||
.PHONY: test-benchmarks-gdb
|
||||
test-benchmarks-gdb:
|
||||
$(MAKE) -C $(TOY_BENCHMARKSDIR) gdb -k
|
||||
|
||||
#TODO: mustfail tests
|
||||
|
||||
#util targets
|
||||
$(TOY_OUTDIR):
|
||||
|
||||
83
repl/main.c
83
repl/main.c
@@ -1,12 +1,27 @@
|
||||
#include "toy.h"
|
||||
#include "toy_print.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//utilities
|
||||
#define APPEND(dest, src) \
|
||||
strncpy((dest) + (strlen(dest)), (src), strlen((src)) + 1);
|
||||
|
||||
#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
|
||||
|
||||
unsigned char* readFile(char* path, int* size) {
|
||||
//BUGFIX: fix the path based on platform - it might be slower, but it's better than dealing with platform crap
|
||||
int pathLength = strlen(path);
|
||||
char realPath[pathLength + 1];
|
||||
strncpy(realPath, path, pathLength);
|
||||
realPath[pathLength] = '\0';
|
||||
FLIPSLASH(realPath);
|
||||
|
||||
//open the file
|
||||
FILE* file = fopen(path, "rb");
|
||||
if (file == NULL) {
|
||||
@@ -26,29 +41,38 @@ unsigned char* readFile(char* path, int* size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
//read the file
|
||||
if (fread(buffer, sizeof(unsigned char), *size, file) < *size) {
|
||||
fclose(file);
|
||||
*size = -2; //singal a read error
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
buffer[(*size)++] = '\0';
|
||||
|
||||
//clean up and return
|
||||
fclose(file);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int getDirPath(char* dest, const char* src) {
|
||||
//extract the directory from src, and store it in dest
|
||||
int getFilePath(char* dest, const char* src) {
|
||||
char* p = NULL;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
char* p = strrchr(src, '\\');
|
||||
#else
|
||||
char* p = strrchr(src, '/');
|
||||
#endif
|
||||
//find the last slash, regardless of platform
|
||||
p = strrchr(src, '\\');
|
||||
if (p == NULL) {
|
||||
p = strrchr(src, '/');
|
||||
}
|
||||
if (p == NULL) {
|
||||
int len = strlen(src);
|
||||
strncpy(dest, src, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
int len = p != NULL ? p - src + 1 : 0;
|
||||
//determine length of the path
|
||||
int len = p - src + 1;
|
||||
|
||||
//copy to the dest
|
||||
strncpy(dest, src, len);
|
||||
dest[len] = '\0';
|
||||
|
||||
@@ -56,30 +80,31 @@ int getDirPath(char* dest, const char* src) {
|
||||
}
|
||||
|
||||
int getFileName(char* dest, const char* src) {
|
||||
//extract the directory from src, and store it in dest
|
||||
char* p = NULL;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
char* p = strrchr(src, '\\') + 1;
|
||||
#else
|
||||
char* p = strrchr(src, '/') + 1;
|
||||
#endif
|
||||
//find the last slash, regardless of platform
|
||||
p = strrchr(src, '\\');
|
||||
if (p == NULL) {
|
||||
p = strrchr(src, '/');
|
||||
}
|
||||
if (p == NULL) {
|
||||
int len = strlen(src);
|
||||
strncpy(dest, src, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
p++; //skip the slash
|
||||
|
||||
//determine length of the file name
|
||||
int len = strlen(p);
|
||||
|
||||
//copy to the dest
|
||||
strncpy(dest, p, len);
|
||||
dest[len] = '\0';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#define APPEND(dest, src) \
|
||||
strncpy((dest) + (strlen(dest)), (src), strlen((src)) + 1);
|
||||
|
||||
#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;
|
||||
@@ -96,6 +121,8 @@ void usageCmdLine(int argc, const char* argv[]) {
|
||||
void helpCmdLine(int argc, const char* argv[]) {
|
||||
usageCmdLine(argc, argv);
|
||||
|
||||
printf("The Toy Programming Language, leave arguments blank for an interactive REPL.\n\n");
|
||||
|
||||
printf(" -h, --help\t\t\tShow this help then exit.\n");
|
||||
printf(" -v, --version\t\t\tShow version and copyright information then exit.\n");
|
||||
printf(" -f, --file infile\t\tParse, compile and execute the source file then exit.\n");
|
||||
@@ -159,7 +186,7 @@ CmdLine parseCmdLine(int argc, const char* argv[]) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
getDirPath(cmd.infile, argv[0]);
|
||||
getFilePath(cmd.infile, argv[0]);
|
||||
APPEND(cmd.infile, argv[i]);
|
||||
FLIPSLASH(cmd.infile);
|
||||
}
|
||||
|
||||
@@ -46,37 +46,6 @@ $(REPL_OUTDIR)/$(REPL_TARGETNAME): $(REPL_OBJFILES)
|
||||
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 $@
|
||||
install_name_tool -change $(REPL_OUTDIR)/libToy.dylib @executable_path/libToy.dylib $@
|
||||
otool -L $@
|
||||
endif
|
||||
|
||||
#util commands
|
||||
.PHONY: clean
|
||||
clean:
|
||||
ifeq ($(shell uname),Linux)
|
||||
find . -type f -name '*.o' -delete
|
||||
find . -type f -name '*.a' -delete
|
||||
find . -type f -name '*.exe' -delete
|
||||
find . -type f -name '*.dll' -delete
|
||||
find . -type f -name '*.lib' -delete
|
||||
find . -type f -name '*.so' -delete
|
||||
find . -type f -name '*.dylib' -delete
|
||||
find . -type d -name 'out' -delete
|
||||
find . -type d -name 'obj' -delete
|
||||
else ifeq ($(OS),Windows_NT)
|
||||
$(RM) *.o *.a *.exe *.dll *.lib *.so *.dylib
|
||||
$(RM) out
|
||||
$(RM) obj
|
||||
else ifeq ($(shell uname),Darwin)
|
||||
find . -type f -name '*.o' -delete
|
||||
find . -type f -name '*.a' -delete
|
||||
find . -type f -name '*.exe' -delete
|
||||
find . -type f -name '*.dll' -delete
|
||||
find . -type f -name '*.lib' -delete
|
||||
find . -type f -name '*.so' -delete
|
||||
find . -type f -name '*.dylib' -delete
|
||||
find . -type d -name 'out' -delete
|
||||
find . -type d -name 'obj' -delete
|
||||
else
|
||||
@echo "Deletion failed - what platform is this?"
|
||||
endif
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
//print statement
|
||||
print 42;
|
||||
|
||||
//it can handle complex expressions
|
||||
print 3 * 5;
|
||||
|
||||
//strings should work
|
||||
print "Hello world!";
|
||||
|
||||
//so should concat
|
||||
print "Hello" .. "world!";
|
||||
@@ -1,7 +0,0 @@
|
||||
//declare a variable
|
||||
var foobar = 42;
|
||||
|
||||
//defaults as null
|
||||
var empty;
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
//expression
|
||||
(1 + 2) * (3 + 4);
|
||||
@@ -53,34 +53,3 @@ $(SRC_OBJDIR):
|
||||
#compilation steps
|
||||
$(SRC_OBJDIR)/%.o: $(SRC_SOURCEDIR)/%.c
|
||||
$(CC) -c -o $@ $< $(addprefix -I,$(SRC_SOURCEDIR)) $(CFLAGS)
|
||||
|
||||
#util commands
|
||||
.PHONY: clean
|
||||
clean:
|
||||
ifeq ($(shell uname),Linux)
|
||||
find . -type f -name '*.o' -delete
|
||||
find . -type f -name '*.a' -delete
|
||||
find . -type f -name '*.exe' -delete
|
||||
find . -type f -name '*.dll' -delete
|
||||
find . -type f -name '*.lib' -delete
|
||||
find . -type f -name '*.so' -delete
|
||||
find . -type f -name '*.dylib' -delete
|
||||
find . -type d -name 'out' -delete
|
||||
find . -type d -name 'obj' -delete
|
||||
else ifeq ($(OS),Windows_NT)
|
||||
$(RM) *.o *.a *.exe *.dll *.lib *.so *.dylib
|
||||
$(RM) out
|
||||
$(RM) obj
|
||||
else ifeq ($(shell uname),Darwin)
|
||||
find . -type f -name '*.o' -delete
|
||||
find . -type f -name '*.a' -delete
|
||||
find . -type f -name '*.exe' -delete
|
||||
find . -type f -name '*.dll' -delete
|
||||
find . -type f -name '*.lib' -delete
|
||||
find . -type f -name '*.so' -delete
|
||||
find . -type f -name '*.dylib' -delete
|
||||
find . -type d -name 'out' -delete
|
||||
find . -type d -name 'obj' -delete
|
||||
else
|
||||
@echo "Deletion failed - what platform is this?"
|
||||
endif
|
||||
|
||||
@@ -59,6 +59,10 @@ Toy_Scope* Toy_pushScope(Toy_Bucket** bucketHandle, Toy_Scope* scope) {
|
||||
}
|
||||
|
||||
Toy_Scope* Toy_popScope(Toy_Scope* scope) {
|
||||
if (scope == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
decrementRefCount(scope);
|
||||
|
||||
if (scope->refCount == 0) {
|
||||
|
||||
@@ -24,7 +24,9 @@ Toy_Stack* Toy_allocateStack() {
|
||||
void Toy_freeStack(Toy_Stack* stack) {
|
||||
//TODO: slip in a call to free the complex values here
|
||||
|
||||
free(stack);
|
||||
if (stack != NULL) {
|
||||
free(stack);
|
||||
}
|
||||
}
|
||||
|
||||
void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value) {
|
||||
|
||||
2
tests/cases/gdb_init
Normal file
2
tests/cases/gdb_init
Normal file
@@ -0,0 +1,2 @@
|
||||
set breakpoint pending on
|
||||
|
||||
@@ -15,9 +15,9 @@ else
|
||||
endif
|
||||
|
||||
#directories
|
||||
TEST_ROOTDIR=..
|
||||
TEST_ROOTDIR=../..
|
||||
TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR)
|
||||
TEST_CASESDIR=cases
|
||||
TEST_CASESDIR=.
|
||||
|
||||
TEST_OUTDIR=out
|
||||
TEST_OBJDIR=obj
|
||||
@@ -27,7 +27,7 @@ TEST_SOURCEFILES=$(wildcard $(TEST_SOURCEDIR)/*.c)
|
||||
TEST_CASESFILES=$(wildcard $(TEST_CASESDIR)/test_*.c)
|
||||
|
||||
#build the object files, compile the test cases, and run
|
||||
all: clean build-source build-cases build-link build-run
|
||||
all: build-source build-cases build-link build-run
|
||||
|
||||
#targets for each step
|
||||
.PHONY: build-source
|
||||
@@ -64,42 +64,11 @@ $(TEST_OUTDIR)/%.run: $(TEST_OUTDIR)/%.exe
|
||||
$<
|
||||
|
||||
#debugging targets
|
||||
all-gdb: clean build-source build-cases build-link build-run-gdb
|
||||
gdb: build-source build-cases build-link build-run-gdb
|
||||
|
||||
.PHONY: build-run-gdb
|
||||
build-run-gdb: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run-gdb)))
|
||||
|
||||
.PRECIOUS: $(TEST_OUTDIR)/%.run-gdb
|
||||
$(TEST_OUTDIR)/%.run-gdb: $(TEST_OUTDIR)/%.exe
|
||||
gdb $< -ex "run" --batch
|
||||
|
||||
#util commands
|
||||
.PHONY: clean
|
||||
clean:
|
||||
ifeq ($(shell uname),Linux)
|
||||
find . -type f -name '*.o' -delete
|
||||
find . -type f -name '*.a' -delete
|
||||
find . -type f -name '*.exe' -delete
|
||||
find . -type f -name '*.dll' -delete
|
||||
find . -type f -name '*.lib' -delete
|
||||
find . -type f -name '*.so' -delete
|
||||
find . -type f -name '*.dylib' -delete
|
||||
find . -type d -name 'out' -delete
|
||||
find . -type d -name 'obj' -delete
|
||||
else ifeq ($(OS),Windows_NT)
|
||||
$(RM) *.o *.a *.exe *.dll *.lib *.so *.dylib
|
||||
$(RM) out
|
||||
$(RM) obj
|
||||
else ifeq ($(shell uname),Darwin)
|
||||
find . -type f -name '*.o' -delete
|
||||
find . -type f -name '*.a' -delete
|
||||
find . -type f -name '*.exe' -delete
|
||||
find . -type f -name '*.dll' -delete
|
||||
find . -type f -name '*.lib' -delete
|
||||
find . -type f -name '*.so' -delete
|
||||
find . -type f -name '*.dylib' -delete
|
||||
find . -type d -name 'out' -delete
|
||||
find . -type d -name 'obj' -delete
|
||||
else
|
||||
@echo "Deletion failed - what platform is this?"
|
||||
endif
|
||||
gdb $< -ix gdb_init -ex=run --batch --return-child-result --args "$<"
|
||||
12
tests/integrations/gdb_init
Normal file
12
tests/integrations/gdb_init
Normal file
@@ -0,0 +1,12 @@
|
||||
set breakpoint pending on
|
||||
|
||||
break main if argc > 1
|
||||
|
||||
command 1
|
||||
set $i=0
|
||||
while($i < argc)
|
||||
p argv[$i++]
|
||||
end
|
||||
continue
|
||||
end
|
||||
|
||||
58
tests/integrations/makefile
Normal file
58
tests/integrations/makefile
Normal file
@@ -0,0 +1,58 @@
|
||||
#compiler settings
|
||||
CC=gcc
|
||||
CFLAGS+=-std=c17 -g -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable -Wformat=2
|
||||
LIBS+=-lm
|
||||
LDFLAGS+=
|
||||
|
||||
ifeq ($(shell uname),Linux)
|
||||
LDFLAGS=-Wl,--gc-sections
|
||||
else ifeq ($(OS),Windows_NT)
|
||||
LDFLAGS=-Wl,--gc-sections
|
||||
else ifeq ($(shell uname),Darwin)
|
||||
LDFLAGS=-Wl,-dead_strip
|
||||
else
|
||||
@echo "LDFLAGS set failed - what platform is this?"
|
||||
endif
|
||||
|
||||
#directories
|
||||
TEST_ROOTDIR=../..
|
||||
TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR)
|
||||
TEST_REPLDIR=$(TEST_ROOTDIR)/$(TOY_REPLDIR)
|
||||
TEST_SCRIPTDIR=.
|
||||
|
||||
TEST_OUTDIR=out
|
||||
TEST_OBJDIR=obj
|
||||
|
||||
#file names
|
||||
TEST_SCRIPTFILES=$(wildcard $(TEST_SCRIPTDIR)/test_*.toy)
|
||||
TEST_REPLNAME=repl.exe
|
||||
|
||||
#build the source and repl, and run
|
||||
all: source repl run
|
||||
|
||||
run: $(TEST_SCRIPTFILES:.toy=.toy-run)
|
||||
|
||||
%.toy-run: %.toy
|
||||
$(TEST_OUTDIR)/$(TEST_REPLNAME) -f ../$<
|
||||
|
||||
#same as above, but with gdb
|
||||
gdb: source repl run-gdb
|
||||
|
||||
run-gdb: $(TEST_SCRIPTFILES:.toy=.toy-gdb)
|
||||
|
||||
%.toy-gdb: %.toy
|
||||
gdb $(TEST_OUTDIR)/$(TEST_REPLNAME) -ix gdb_init -ex=run --batch --return-child-result --args "$(TEST_OUTDIR)/$(TEST_REPLNAME)" "-f" "../$<"
|
||||
|
||||
#compile the source and repl first
|
||||
source: $(TEST_OBJDIR) $(TEST_OUTDIR)
|
||||
$(MAKE) SRC_OUTDIR=../$(TOY_INTEGRATIONSDIR)/$(TEST_OUTDIR) -C $(TEST_SOURCEDIR)
|
||||
|
||||
repl: $(TEST_OBJDIR) $(TEST_OUTDIR) source
|
||||
$(MAKE) REPL_TARGETNAME=$(TEST_REPLNAME) REPL_OUTDIR=../$(TOY_INTEGRATIONSDIR)/$(TEST_OUTDIR) -C $(TEST_REPLDIR)
|
||||
|
||||
#util targets
|
||||
$(TEST_OUTDIR):
|
||||
mkdir $(TEST_OUTDIR)
|
||||
|
||||
$(TEST_OBJDIR):
|
||||
mkdir $(TEST_OBJDIR)
|
||||
3
tests/integrations/test_expressions.toy
Normal file
3
tests/integrations/test_expressions.toy
Normal file
@@ -0,0 +1,3 @@
|
||||
//basic expressions with no side effects (other than debug stack dumps)
|
||||
(1 + 2) * (3 + 4);
|
||||
|
||||
15
tests/integrations/test_print.toy
Normal file
15
tests/integrations/test_print.toy
Normal file
@@ -0,0 +1,15 @@
|
||||
//basic print statement
|
||||
print 42;
|
||||
|
||||
//print complex expressions
|
||||
print 3 * 5;
|
||||
|
||||
//print a string
|
||||
print "Hello world!";
|
||||
|
||||
//print a concatenated string
|
||||
print "Hello" .. "world!";
|
||||
|
||||
//TODO: in the repl, -s to supress output, or -d to print debugging info
|
||||
|
||||
//TODO: the `assert` keyword will be useful for these
|
||||
6
tests/integrations/test_variables_and_scopes.toy
Normal file
6
tests/integrations/test_variables_and_scopes.toy
Normal file
@@ -0,0 +1,6 @@
|
||||
//declare a variable with an initial value
|
||||
var answer = 42;
|
||||
|
||||
//declare a variable without an initial value
|
||||
var empty;
|
||||
|
||||
0
tests/mustfails/.gitkeep
Normal file
0
tests/mustfails/.gitkeep
Normal file
1
tests/standalone/gdb_init
Normal file
1
tests/standalone/gdb_init
Normal file
@@ -0,0 +1 @@
|
||||
set breakpoint pending on
|
||||
60
tests/standalone/makefile
Normal file
60
tests/standalone/makefile
Normal file
@@ -0,0 +1,60 @@
|
||||
#compiler settings
|
||||
CC=gcc
|
||||
CFLAGS+=-std=c17 -g -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable -Wformat=2
|
||||
LIBS+=-lm
|
||||
LDFLAGS+=
|
||||
|
||||
ifeq ($(shell uname),Linux)
|
||||
LDFLAGS=-Wl,--gc-sections
|
||||
else ifeq ($(OS),Windows_NT)
|
||||
LDFLAGS=-Wl,--gc-sections
|
||||
else ifeq ($(shell uname),Darwin)
|
||||
LDFLAGS=-Wl,-dead_strip
|
||||
else
|
||||
@echo "LDFLAGS set failed - what platform is this?"
|
||||
endif
|
||||
|
||||
#directories
|
||||
TEST_SRCDIR=
|
||||
|
||||
TEST_OUTDIR=out/
|
||||
TEST_OBJDIR=obj/
|
||||
|
||||
#file names
|
||||
TEST_SRCFILES=$(wildcard $(TEST_SRCDIR)*.c)
|
||||
|
||||
#kick off
|
||||
all: $(TEST_OBJDIR) $(TEST_OUTDIR) build run
|
||||
|
||||
gdb: $(TEST_OBJDIR) $(TEST_OUTDIR) build gdb-run
|
||||
|
||||
#build
|
||||
build: $(TEST_OBJDIR)$(TEST_SRCFILES:.c=.o)
|
||||
|
||||
.PRECIOUS: $(TEST_OBJDIR)%.o
|
||||
$(TEST_OBJDIR)%.o: $(TEST_SRCDIR)%.c
|
||||
$(CC) -c -o $@ $< $(CFLAGS) -fdata-sections -ffunction-sections
|
||||
|
||||
|
||||
.PRECIOUS: $(TEST_OUTDIR)%.exe
|
||||
$(TEST_OUTDIR)%.exe: $(TEST_OBJDIR)%.o
|
||||
$(CC) -o $@ $< $(CFLAGS) $(LIBS) $(LDFLAGS)
|
||||
|
||||
#run
|
||||
run: $(addprefix $(TEST_OUTDIR),$(TEST_SRCFILES:.c=.exe-run))
|
||||
|
||||
$(TEST_OUTDIR)%.exe-run: $(TEST_OUTDIR)%.exe
|
||||
$<
|
||||
|
||||
#gdb-run
|
||||
gdb-run: $(addprefix $(TEST_OUTDIR),$(TEST_SRCFILES:.c=.exe-gdb-run))
|
||||
|
||||
$(TEST_OUTDIR)%.exe-gdb-run: $(TEST_OUTDIR)%.exe
|
||||
gdb $< -ix gdb_init -ex=run --batch --return-child-result
|
||||
|
||||
#util targets
|
||||
$(TEST_OUTDIR):
|
||||
mkdir $(TEST_OUTDIR)
|
||||
|
||||
$(TEST_OBJDIR):
|
||||
mkdir $(TEST_OBJDIR)
|
||||
147
tests/standalone/platform_behaviours.c
Normal file
147
tests/standalone/platform_behaviours.c
Normal file
@@ -0,0 +1,147 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//utilities
|
||||
#define APPEND(dest, src) \
|
||||
strncpy((dest) + (strlen(dest)), (src), strlen((src)) + 1);
|
||||
|
||||
#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
|
||||
|
||||
unsigned char* readFile(char* path, int* size) {
|
||||
//BUGFIX: fix the path based on platform - it might be slower, but it's better than dealing with platform crap
|
||||
int pathLength = strlen(path);
|
||||
char realPath[pathLength + 1];
|
||||
strncpy(realPath, path, pathLength);
|
||||
realPath[pathLength] = '\0';
|
||||
FLIPSLASH(realPath);
|
||||
|
||||
//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 = malloc(*size + 1);
|
||||
if (buffer == NULL) {
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//read the file
|
||||
if (fread(buffer, sizeof(unsigned char), *size, file) < *size) {
|
||||
fclose(file);
|
||||
*size = -2; //singal a read error
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer[(*size)++] = '\0';
|
||||
|
||||
//clean up and return
|
||||
fclose(file);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int getFilePath(char* dest, const char* src) {
|
||||
char* p = NULL;
|
||||
|
||||
//find the last slash, regardless of platform
|
||||
p = strrchr(src, '\\');
|
||||
if (p == NULL) {
|
||||
p = strrchr(src, '/');
|
||||
}
|
||||
if (p == NULL) {
|
||||
int len = strlen(src);
|
||||
strncpy(dest, src, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
//determine length of the path
|
||||
int len = p - src + 1;
|
||||
|
||||
//copy to the dest
|
||||
strncpy(dest, src, len);
|
||||
dest[len] = '\0';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int getFileName(char* dest, const char* src) {
|
||||
char* p = NULL;
|
||||
|
||||
//find the last slash, regardless of platform
|
||||
p = strrchr(src, '\\');
|
||||
if (p == NULL) {
|
||||
p = strrchr(src, '/');
|
||||
}
|
||||
if (p == NULL) {
|
||||
int len = strlen(src);
|
||||
strncpy(dest, src, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
p++; //skip the slash
|
||||
|
||||
//determine length of the file name
|
||||
int len = strlen(p);
|
||||
|
||||
//copy to the dest
|
||||
strncpy(dest, p, len);
|
||||
dest[len] = '\0';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int main() {
|
||||
//check the platform
|
||||
printf("Platform: ");
|
||||
#if defined(__linux__)
|
||||
printf("Linux");
|
||||
#elif defined(_WIN64)
|
||||
printf("Win64");
|
||||
#elif defined(_WIN32)
|
||||
printf("Win32");
|
||||
#elif defined(__APPLE__)
|
||||
printf("macOS");
|
||||
#else
|
||||
printf("Unknown");
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
|
||||
//run each test
|
||||
{
|
||||
char src[256] = "../folder/file.txt";
|
||||
char dest[256];
|
||||
getFilePath(dest, src);
|
||||
printf("Path: %s\n", dest);
|
||||
}
|
||||
|
||||
{
|
||||
char src[256] = "../folder/file.txt";
|
||||
char dest[256];
|
||||
getFileName(dest, src);
|
||||
printf("Name: %s\n", dest);
|
||||
}
|
||||
|
||||
{
|
||||
char src[256] = "../folder/file.txt";
|
||||
char dest[256];
|
||||
getFilePath(dest, src);
|
||||
APPEND(dest, "target.txt");
|
||||
printf("Target: %s\n", dest);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user