diff --git a/Makefile b/Makefile index 39f7b0a..dd457e1 100644 --- a/Makefile +++ b/Makefile @@ -1,56 +1,89 @@ +OS_NAME:=$(shell uname -s | tr A-Z a-z) +ifeq ($(strip $(CC)),cc) +CC= +endif ifeq ($(strip $(CC)),) -CC=gcc + ifeq ($(OS_NAME),darwin) + CC=clang + else + CC=gcc + endif endif ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -DEFINES=-DNAN_TAGGING -DCOMPUTED_GOTO -DLX_BUILT_DIR=$(ROOT_DIR) -GCC_DEFINES=-D_GNU_SOURCE -GCC_CFLAGS=-std=c99 -Wall -Wextra -Wmissing-prototypes -Wno-shadow -Wvla -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-label -I. -Ivendor -pthread ${DEFINES} ${GCC_DEFINES} -GPP_CFLAGS=-std=c++11 -w -fpermissive -I. -Ivendor -pthread ${DEFINES} ${GCC_DEFINES} +DEFINES:=-DNAN_TAGGING -DCOMPUTED_GOTO -DLX_BUILT_DIR=$(ROOT_DIR) +GCC_DEFINES:=-D_GNU_SOURCE +GCC_CFLAGS:=-std=c99 -Wall -Wextra -Wmissing-prototypes -Wno-shadow -Wvla -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-label -I. -Ivendor -pthread ${DEFINES} ${GCC_DEFINES} +GPP_CFLAGS:=-std=c++11 -w -fpermissive -I. -Ivendor -pthread ${DEFINES} ${GCC_DEFINES} # NOTE: clang++ doesn't compile yet, too many C++ type errors -CLANGPP_CFLAGS=-std=c++11 -w -fpermissive -I. -Ivendor -pthread ${DEFINES} -CLANG_CFLAGS=-std=c99 -Wall -Wextra -Wmissing-prototypes -I. -Ivendor -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-label -pthread ${DEFINES} +CLANGPP_CFLAGS:=-std=c++11 -w -fpermissive -I. -Ivendor -pthread ${DEFINES} +CLANG_CFLAGS:=-std=c99 -Wall -Wextra -Wmissing-prototypes -I. -Ivendor -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-label -pthread ${DEFINES} ifneq (,$(findstring clang,$(CC))) ifneq (,$(findstring clang++,$(CC))) - CFLAGS=${CLANGPP_CFLAGS} + CFLAGS:=${CLANGPP_CFLAGS} else - CFLAGS=${CLANG_CFLAGS} + CFLAGS:=${CLANG_CFLAGS} endif else ifneq (,$(findstring g++,$(CC))) - CFLAGS=${GPP_CFLAGS} + CFLAGS:=${GPP_CFLAGS} else - CFLAGS=${GCC_CFLAGS} + CFLAGS:=${GCC_CFLAGS} endif endif -SRCS = main.c debug.c memory.c chunk.c value.c scanner.c compiler.c vm.c object.c string.c array.c map.c options.c vendor/vec.c nodes.c parser.c table.c runtime.c process.c signal.c io.c file.c dir.c thread.c block.c rand.c time.c repl.c debugger.c regex_lib.c regex.c socket.c errors.c binding.c vendor/linenoise.c -TEST_SRCS = debug.c memory.c chunk.c value.c scanner.c compiler.c vm.c object.c string.c array.c map.c options.c vendor/vec.c nodes.c parser.c table.c runtime.c process.c signal.c io.c file.c dir.c thread.c block.c rand.c time.c debugger.c regex_lib.c regex.c socket.c errors.c binding.c -TEST_FILES = test/test_object.c test/test_nodes.c test/test_compiler.c test/test_vm.c test/test_gc.c test/test_examples.c test/test_regex.c +SRCS=main.c debug.c memory.c chunk.c value.c scanner.c compiler.c vm.c object.c string.c array.c map.c options.c vendor/vec.c nodes.c parser.c table.c runtime.c process.c signal.c io.c file.c dir.c thread.c block.c rand.c time.c repl.c debugger.c regex_lib.c regex.c socket.c errors.c binding.c vendor/linenoise.c +TEST_SRCS=debug.c memory.c chunk.c value.c scanner.c compiler.c vm.c object.c string.c array.c map.c options.c vendor/vec.c nodes.c parser.c table.c runtime.c process.c signal.c io.c file.c dir.c thread.c block.c rand.c time.c debugger.c regex_lib.c regex.c socket.c errors.c binding.c +TEST_FILES=test/test_object.c test/test_nodes.c test/test_compiler.c test/test_vm.c test/test_gc.c test/test_examples.c test/test_regex.c DEBUG_FLAGS=-O2 -g -rdynamic GPROF_FLAGS=-O3 -pg -DNDEBUG TEST_FLAGS=-O0 -g -rdynamic -Itest/include -I. -DLOX_TEST -RELEASE_FLAGS=-O3 -DNDEBUG -Wno-unused-function +RELEASE_FLAGS=-O3 -DNDEBUG -Wno-unused-function -Wno-unused-variable BUILD_DIR=bin -BUILD_FILE_RELEASE=clox -BUILD_FILE_DEBUG=clox -SUFFIX = -ldl +BUILD_DEBUG_DIR:=${BUILD_DIR}/debug +BUILD_DEBUG_FILE=clox +BUILD_RELEASE_DIR:=${BUILD_DIR}/release +BUILD_RELEASE_FILE=clox +BUILD_TEST_DIR=${BUILD_DIR}/test +SUFFIX_FLAGS=-ldl +ifeq ($(PREFIX),) +PREFIX=/usr/local/bin +endif # default .PHONY: debug -debug: build - ${CC} ${CFLAGS} $(SRCS) ${DEBUG_FLAGS} -o ${BUILD_DIR}/${BUILD_FILE_DEBUG} ${SUFFIX} +debug: create_debug_dir + ${CC} ${CFLAGS} $(SRCS) ${DEBUG_FLAGS} -o ${BUILD_DEBUG_DIR}/${BUILD_DEBUG_FILE} ${SUFFIX_FLAGS} + +.PHONY: os +os: + @echo $(OS_NAME) -# default .PHONY: profile gprof: build - ${CC} ${CFLAGS} $(SRCS) ${GPROF_FLAGS} -o ${BUILD_DIR}/gprof ${SUFFIX} + ${CC} ${CFLAGS} $(SRCS) ${GPROF_FLAGS} -o ${BUILD_DIR}/gprof ${SUFFIX_FLAGS} .PHONY: release -release: build - ${CC} ${CFLAGS} $(SRCS) ${RELEASE_FLAGS} -o ${BUILD_DIR}/${BUILD_FILE_RELEASE} ${SUFFIX} +release: create_release_dir + ${CC} ${CFLAGS} $(SRCS) ${RELEASE_FLAGS} -o ${BUILD_RELEASE_DIR}/${BUILD_RELEASE_FILE} ${SUFFIX_FLAGS} + +.PHONY: create_prefix_dir +create_prefix_dir: + mkdir -p ${PREFIX} + +# Run with sudo +install: release create_prefix_dir + cp ${BUILD_RELEASE_DIR}/${BUILD_RELEASE_FILE} ${PREFIX}/clox + +.PHONY: create_debug_dir +create_debug_dir: + mkdir -p ${BUILD_DEBUG_DIR} + +.PHONY: create_release_dir +create_release_dir: + mkdir -p ${BUILD_RELEASE_DIR} -.PHONY: build -build: - mkdir -p ${BUILD_DIR} +.PHONY: create_test_dir +create_test_dir: + mkdir -p ${BUILD_TEST_DIR} .PHONY: clean clean: @@ -58,65 +91,65 @@ clean: rm -f *.o .PHONY: build_test_object -build_test_object: build - ${CC} ${CFLAGS} $(TEST_SRCS) test/test_object.c ${TEST_FLAGS} -o ${BUILD_DIR}/test_object ${SUFFIX} +build_test_object: create_test_dir + ${CC} ${CFLAGS} $(TEST_SRCS) test/test_object.c ${TEST_FLAGS} -o ${BUILD_TEST_DIR}/test_object ${SUFFIX_FLAGS} .PHONY: run_test_object run_test_object: - ./bin/test_object + ./${BUILD_TEST_DIR}/test_object .PHONY: build_test_nodes -build_test_nodes: build - ${CC} ${CFLAGS} $(TEST_SRCS) test/test_nodes.c ${TEST_FLAGS} -o ${BUILD_DIR}/test_nodes ${SUFFIX} +build_test_nodes: create_test_dir + ${CC} ${CFLAGS} $(TEST_SRCS) test/test_nodes.c ${TEST_FLAGS} -o ${BUILD_TEST_DIR}/test_nodes ${SUFFIX_FLAGS} .PHONY: run_test_nodes run_test_nodes: - ./bin/test_nodes + ./${BUILD_TEST_DIR}/test_nodes # NOTE: the compiler tests are deprecated, and not maintained .PHONY: build_test_compiler -build_test_compiler: build - ${CC} ${CFLAGS} $(TEST_SRCS) test/test_compiler.c ${TEST_FLAGS} -o ${BUILD_DIR}/test_compiler ${SUFFIX} +build_test_compiler: create_test_dir + ${CC} ${CFLAGS} $(TEST_SRCS) test/test_compiler.c ${TEST_FLAGS} -o ${BUILD_TEST_DIR}/test_compiler ${SUFFIX_FLAGS} .PHONY: run_test_compiler run_test_compiler: - ./bin/test_compiler + ./${BUILD_TEST_DIR}/test_compiler .PHONY: build_test_vm -build_test_vm: build - ${CC} ${CFLAGS} $(TEST_SRCS) test/test_vm.c ${TEST_FLAGS} -o ${BUILD_DIR}/test_vm ${SUFFIX} +build_test_vm: create_test_dir + ${CC} ${CFLAGS} $(TEST_SRCS) test/test_vm.c ${TEST_FLAGS} -o ${BUILD_TEST_DIR}/test_vm ${SUFFIX_FLAGS} .PHONY: run_test_vm run_test_vm: - ./bin/test_vm + ./${BUILD_TEST_DIR}/test_vm .PHONY: build_test_gc -build_test_gc: build - ${CC} ${CFLAGS} $(TEST_SRCS) test/test_gc.c ${TEST_FLAGS} -o ${BUILD_DIR}/test_gc ${SUFFIX} +build_test_gc: create_test_dir + ${CC} ${CFLAGS} $(TEST_SRCS) test/test_gc.c ${TEST_FLAGS} -o ${BUILD_TEST_DIR}/test_gc ${SUFFIX_FLAGS} .PHONY: run_test_gc run_test_gc: - ./bin/test_gc + ./${BUILD_TEST_DIR}/test_gc .PHONY: build_test_examples -build_test_examples: build - ${CC} ${CFLAGS} $(TEST_SRCS) test/test_examples.c ${TEST_FLAGS} -o ${BUILD_DIR}/test_examples ${SUFFIX} +build_test_examples: create_test_dir + ${CC} ${CFLAGS} $(TEST_SRCS) test/test_examples.c ${TEST_FLAGS} -o ${BUILD_TEST_DIR}/test_examples ${SUFFIX_FLAGS} .PHONY: run_test_examples run_test_examples: - ./bin/test_examples + ./${BUILD_TEST_DIR}/test_examples .PHONY: build_test_regex -build_test_regex: build - ${CC} ${CFLAGS} $(TEST_SRCS) test/test_regex.c ${TEST_FLAGS} -o ${BUILD_DIR}/test_regex ${SUFFIX} +build_test_regex: create_test_dir + ${CC} ${CFLAGS} $(TEST_SRCS) test/test_regex.c ${TEST_FLAGS} -o ${BUILD_TEST_DIR}/test_regex ${SUFFIX_FLAGS} .PHONY: run_test_regex run_test_regex: - ./bin/test_regex + ./${BUILD_TEST_DIR}/test_regex # NOTE: test_nodes and test_compiler aren't in the default tests right now .PHONY: build_tests -build_tests: build build_test_regex build_test_object build_test_vm build_test_gc build_test_examples +build_tests: build_test_regex build_test_object build_test_vm build_test_gc build_test_examples .PHONY: run_tests run_tests: diff --git a/README.md b/README.md index b8dc886..2b0a6fe 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,40 @@ OS/compiler support * Only tested on linux (Ubuntu 16.04) and mac OS, uses fork() and libpthread, as well as some C99 features * Tested with gcc and clang * Almost C++ compliant (g++ compiles, clang++ doesn't) -* There appear to be issues on macOS arm architectures, I'm working on fixing them soon + +Building +-------- + +Build a release version to bin/release/clox + +> make release + +Build a debug version to bin/debug/clox + +> make debug + +Running Tests +------------- + +> make test + +Install +------- + +Set the PREFIX environment variable or install by default to /usr/local/bin + +> sudo make install + +Usage +----- + +To run a file: + +> ./bin/release/clox -f my_file.lox + +For more details: + +> ./bin/release/clox -h Examples -------- @@ -98,16 +131,9 @@ Benchmark.start(name: "array", iterations: 1, &bench); ``` See the examples folder for more examples, and the lib folder for the standard library. -The files in the examples folder are also tests run by the ./bin/test\_examples +The files in the examples folder are also tests run by the ./bin/test/test\_examples binary (see Makefile for more details). -Use ---- - -To run a file: - -> ./bin/clox -f my_file.lox - Thanks ------ Thanks to Bob Nystrom for the book and github repo! diff --git a/lox b/lox deleted file mode 100755 index 974e7fd..0000000 --- a/lox +++ /dev/null @@ -1 +0,0 @@ -./bin/clox $@ diff --git a/scripts/run_all_tests b/scripts/run_all_tests index a8c265c..37e4772 100755 --- a/scripts/run_all_tests +++ b/scripts/run_all_tests @@ -5,11 +5,11 @@ counter=0; failures=() # each test file failure sets the next bit to 1 if it fails -./bin/test_regex || let "rc += 1 << $counter"; let counter+=1; -./bin/test_object || let "rc += 1 << $counter"; let counter+=1; -./bin/test_vm || let "rc += 1 << $counter"; let counter+=1; -./bin/test_gc || let "rc += 1 << $counter"; let counter+=1; -./bin/test_examples || let "rc += 1 << $counter"; let counter+=1; +./bin/test/test_regex || let "rc += 1 << $counter"; let counter+=1; +./bin/test/test_object || let "rc += 1 << $counter"; let counter+=1; +./bin/test/test_vm || let "rc += 1 << $counter"; let counter+=1; +./bin/test/test_gc || let "rc += 1 << $counter"; let counter+=1; +./bin/test/test_examples || let "rc += 1 << $counter"; let counter+=1; if ((($rc & 0x01) != 0)); then failures+=("test_regex") diff --git a/test/include/test.h b/test/include/test.h index bcf25e4..67fe945 100644 --- a/test/include/test.h +++ b/test/include/test.h @@ -6,6 +6,41 @@ #include "options.h" #include "debug.h" +/* + * Unit test library in a header file. Each test function that is registered + * is run in order, and any assertion that fails makes the execution jump + * out of the function and continue with the next one, recording it as a failed + * assertion and failed test. + * + * You can pass options to the test file when running it, like so: + * ./bin/test/test_example --only test_pass + * or: + * ./bin/test/test_example --skip test_fail + * + * You can pass --only and/or --skip multiple times + * + * Usage: + * + * static int test_pass(void) { + * T_ASSERT_EQ(true, true); + * return 0; + * } + * + * static int test_fail(void) { + * T_ASSERT_EQ(false, true); + * return 0; + * } + * + * int main(int argc, char *argv[]) { + * parseTestOptions(argc, argv); + * INIT_TESTS("test_example"); + * RUN_TEST(test_pass); + * RUN_TEST(test_fail); + * END_TESTS(); + * } + * + */ + #include "vec.h" #ifndef CLOX_TEST @@ -16,6 +51,7 @@ #define LOG_ERR(...) (fprintf(stderr, __VA_ARGS__)) #endif +// colors #define KNRM "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m"