diff --git a/.gitignore b/.gitignore
index de47c87..0588520 100644
--- a/.gitignore
+++ b/.gitignore
@@ -325,3 +325,7 @@ binding/GravityObjC/GravityObjC.xcodeproj/project.xcworkspace/xcshareddata/IDEWo
gravity.xcodeproj/xcuserdata/marco.xcuserdatad/xcschemes/gravity.xcscheme
*.xcscheme
*.xcscheme
+
+## Zig
+**/zig-cache
+**/zig-out
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index ef1fb47..38d5538 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,9 @@
language: c
os:
- - osx
- - linux
+ - windows
+ - osx
+ - linux
compiler:
- - gcc
- - clang
+ - zig
script:
- - make
- - test/unittest/run_all.sh
+ - zig build
diff --git a/README.md b/README.md
index 781c6d2..0ce8e64 100644
--- a/README.md
+++ b/README.md
@@ -41,57 +41,74 @@ class Vector {
func main() {
// initialize a new vector object
var v1 = Vector(1,2,3);
-
+
// initialize a new vector object
var v2 = Vector(4,5,6);
-
+
// call + function in the vector object
var v3 = v1 + v2;
-
+
// returns string "[1,2,3] + [4,5,6] = [5,7,9]"
return "\(v1) + \(v2) = \(v3)";
}
- ```
+```
## Features
-* multipass compiler
-* dynamic typing
-* classes and inheritance
-* higher-order functions and classes
-* lexical scoping
-* coroutines (via fibers)
-* nested classes
-* closures
-* garbage collection
-* operator overriding
-* powerful embedding API
-* built-in unit tests
-* built-in JSON serializer/deserializer
-* **optional semicolons**
+
+- multipass compiler
+- dynamic typing
+- classes and inheritance
+- higher-order functions and classes
+- lexical scoping
+- coroutines (via fibers)
+- nested classes
+- closures
+- garbage collection
+- operator overriding
+- powerful embedding API
+- built-in unit tests
+- built-in JSON serializer/deserializer
+- **optional semicolons**
## Special thanks
+
Gravity was supported by a couple of open-source projects. The inspiration for closures comes from the elegant Lua programming language; specifically from the document Closures in Lua. For fibers, upvalues handling and some parts of the garbage collector, my gratitude goes to Bob Nystrom and his excellent Wren programming language. A very special thanks should also go to my friend **Andrea Donetti** who helped me debugging and testing various aspects of the language.
## Documentation
+
The Getting Started page is a guide for downloading and compiling the language. There is also a more extensive language documentation. Official [wiki](https://github.com/marcobambini/gravity/wiki) is used to collect related projects and tools.
## Where Gravity is used
-* Gravity is the core language built into Creo (https://creolabs.com)
-* Gravity is the scripting language for the Untold game engine (https://youtu.be/OGrWq8jpK14?t=58)
+
+- Gravity is the core language built into Creo (https://creolabs.com)
+- Gravity is the scripting language for the Untold game engine (https://youtu.be/OGrWq8jpK14?t=58)
## Community
+
Seems like a good idea to make a group chat for people to discuss Gravity.
[](https://gitter.im/gravity-lang/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Contributing
+
Contributions to Gravity are welcomed and encouraged!
More information is available in the official [CONTRIBUTING](CONTRIBUTING.md) file.
-* Open an issue:
- * if you need help
- * if you find a bug
- * if you have a feature request
- * to ask a general question
-* Submit a pull request:
- * if you want to contribute
+
+- Open an issue:
+ - if you need help
+ - if you find a bug
+ - if you have a feature request
+ - to ask a general question
+- Submit a pull request:
+ - if you want to contribute
## License
+
Gravity is available under the permissive MIT license.
+
+## Let's get ziggy
+
+I made a thin wrapper for gravity in zig, you can fetch it like any other zig packages,
+you can pass an optional parameter to the build options: "shared"
+
+- If set to true, the "gravity" artifact will be dynamically linked
+- If set to false, it will be statically linked
+- If not set, both of them will be created: "gravity" and "gravity_s", "gravity" is dynamic, "gravity_s" is static
diff --git a/bootstrap.zig b/bootstrap.zig
new file mode 100644
index 0000000..20c1251
--- /dev/null
+++ b/bootstrap.zig
@@ -0,0 +1,36 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+extern fn c_main(argc: c_int, argv: [*c]const [*c]const u8) c_int;
+
+const DEBUG = builtin.mode == .Debug;
+const BACK_ALLOCATOR = std.heap.c_allocator;
+
+pub fn main() u8 {
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = BACK_ALLOCATOR };
+ defer if (DEBUG) {
+ _ = gpa.deinit();
+ };
+ const allocator = if (DEBUG) gpa.allocator() else BACK_ALLOCATOR;
+
+ var args_list = std.ArrayList([*c]const u8).init(allocator);
+ defer {
+ for (args_list.items) |arg| {
+ allocator.free(std.mem.span(arg));
+ }
+ args_list.deinit();
+ }
+
+ var args_it = std.process.argsWithAllocator(allocator) catch return 1;
+ defer args_it.deinit();
+
+ while (args_it.next()) |arg| {
+ args_list.append(@ptrCast(allocator.dupeZ(u8, arg) catch return 1)) catch return 1;
+ }
+
+ args_list.ensureTotalCapacity(args_list.items.len + 1) catch return 1;
+ args_list.append(null) catch unreachable;
+
+ const argv: [*c]const [*c]const u8 = @ptrCast(args_list.allocatedSlice());
+ return @intCast(c_main(@intCast(args_list.items.len), argv) & 0xFF);
+}
diff --git a/build.zig b/build.zig
new file mode 100644
index 0000000..6372105
--- /dev/null
+++ b/build.zig
@@ -0,0 +1,131 @@
+const std = @import("std");
+
+const GRAVITY_SRC_PATH: []const u8 = "src/";
+
+const COMPILER_DIR: []const u8 = GRAVITY_SRC_PATH ++ "compiler/";
+const RUNTIME_DIR: []const u8 = GRAVITY_SRC_PATH ++ "runtime/";
+const SHARED_DIR: []const u8 = GRAVITY_SRC_PATH ++ "shared/";
+const UTILS_DIR: []const u8 = GRAVITY_SRC_PATH ++ "utils/";
+const OPT_DIR: []const u8 = GRAVITY_SRC_PATH ++ "optionals/";
+const SRC: []const []const u8 = &.{
+ // COMPILER_DIR/*.c
+ COMPILER_DIR ++ "gravity_ast.c",
+ COMPILER_DIR ++ "gravity_codegen.c",
+ COMPILER_DIR ++ "gravity_compiler.c",
+ COMPILER_DIR ++ "gravity_ircode.c",
+ COMPILER_DIR ++ "gravity_lexer.c",
+ COMPILER_DIR ++ "gravity_optimizer.c",
+ COMPILER_DIR ++ "gravity_optimizer.c",
+ COMPILER_DIR ++ "gravity_parser.c",
+ COMPILER_DIR ++ "gravity_semacheck1.c",
+ COMPILER_DIR ++ "gravity_semacheck2.c",
+ COMPILER_DIR ++ "gravity_symboltable.c",
+ COMPILER_DIR ++ "gravity_token.c",
+ COMPILER_DIR ++ "gravity_visitor.c",
+ // RUNTIME_DIR/*.c
+ RUNTIME_DIR ++ "gravity_core.c",
+ RUNTIME_DIR ++ "gravity_vm.c",
+ // SHARED_DIR/*.c
+ SHARED_DIR ++ "gravity_hash.c",
+ SHARED_DIR ++ "gravity_memory.c",
+ SHARED_DIR ++ "gravity_value.c",
+ // UTILS_DIR/*.c
+ UTILS_DIR ++ "gravity_debug.c",
+ UTILS_DIR ++ "gravity_json.c",
+ UTILS_DIR ++ "gravity_utils.c",
+ // OPT_DIR/*.c
+ OPT_DIR ++ "gravity_opt_env.c",
+ OPT_DIR ++ "gravity_opt_file.c",
+ OPT_DIR ++ "gravity_opt_json.c",
+ OPT_DIR ++ "gravity_opt_math.c",
+};
+const INCLUDE: []const []const u8 = &.{
+ "-I", COMPILER_DIR,
+ "-I", RUNTIME_DIR,
+ "-I", SHARED_DIR,
+ "-I", UTILS_DIR,
+ "-I", OPT_DIR,
+};
+const CFLAGS: []const []const u8 = @as([]const []const u8, &.{
+ "-std=gnu99",
+ "-fgnu89-inline",
+ "-fPIC",
+ "-fno-sanitize=undefined",
+});
+
+pub fn build(b: *std.Build) void {
+ const target = b.standardTargetOptions(.{});
+ const optimize = b.standardOptimizeOption(.{});
+
+ const lib_s = b.addStaticLibrary(.{
+ .name = "gravity_s",
+ .target = target,
+ .optimize = optimize,
+ .link_libc = true,
+ });
+ inline for (INCLUDE) |I| {
+ if (comptime std.mem.eql(u8, I, "-I"))
+ continue;
+ lib_s.addIncludePath(b.path(I));
+ lib_s.installHeadersDirectory(b.path(I), ".", .{});
+ }
+ lib_s.linkSystemLibrary("m");
+ switch (target.result.os.tag) {
+ .windows => lib_s.linkSystemLibrary("Shlwapi"),
+ .openbsd, .freebsd, .netbsd, .dragonfly => {},
+ else => if (!target.result.isDarwin()) lib_s.linkSystemLibrary("rt"),
+ }
+ lib_s.addCSourceFiles(.{
+ .root = b.path("."),
+ .files = SRC,
+ .flags = INCLUDE ++ CFLAGS ++ @as([]const []const u8, &.{"-DBUILD_GRAVITY_API"}),
+ });
+
+ const lib = b.addSharedLibrary(.{
+ .name = "gravity",
+ .target = target,
+ .optimize = optimize,
+ .link_libc = true,
+ });
+ inline for (INCLUDE) |I| {
+ if (comptime std.mem.eql(u8, I, "-I"))
+ continue;
+ lib.addIncludePath(b.path(I));
+ lib.installHeadersDirectory(b.path(I), ".", .{});
+ }
+ lib.linkSystemLibrary("m");
+ switch (target.result.os.tag) {
+ .windows => lib.linkSystemLibrary("Shlwapi"),
+ .openbsd, .freebsd, .netbsd, .dragonfly => {},
+ else => if (!target.result.isDarwin()) lib.linkSystemLibrary("rt"),
+ }
+ lib.addCSourceFiles(.{
+ .root = b.path("."),
+ .files = SRC,
+ .flags = INCLUDE ++ CFLAGS ++ @as([]const []const u8, &.{"-DBUILD_GRAVITY_API"}),
+ });
+
+ b.installArtifact(lib);
+ b.installArtifact(lib_s);
+
+ const exe = b.addExecutable(.{
+ .name = "gravity",
+ .root_source_file = b.path("bootstrap.zig"),
+ .target = target,
+ .optimize = optimize,
+ });
+ exe.linkLibrary(lib_s);
+ exe.addCSourceFiles(.{
+ .root = b.path("."),
+ .files = &.{"src/cli/gravity.c"},
+ .flags = CFLAGS ++ @as([]const []const u8, &.{"-DZIG_BOOTSTRAP"}),
+ });
+ b.installArtifact(exe);
+
+ const run_cmd = b.addRunArtifact(exe);
+ run_cmd.step.dependOn(b.getInstallStep());
+ run_cmd.addArgs(b.args orelse &.{});
+
+ const run_step = b.step("run", "Run the app");
+ run_step.dependOn(&run_cmd.step);
+}
diff --git a/build.zig.zon b/build.zig.zon
new file mode 100644
index 0000000..bdee155
--- /dev/null
+++ b/build.zig.zon
@@ -0,0 +1,12 @@
+.{
+ .name = "gravity",
+ .version = "0.8.5-build+1eb6d5ab98b9df4909513612a2bb9238a8304422",
+
+ .dependencies = .{},
+
+ .paths = .{
+ "src/",
+ "build.zig",
+ "build.zig.zon",
+ },
+}
diff --git a/src/cli/gravity.c b/src/cli/gravity.c
index 0f122fc..70ffb4e 100644
--- a/src/cli/gravity.c
+++ b/src/cli/gravity.c
@@ -7,35 +7,36 @@
//
#include "gravity_compiler.h"
+#include "gravity_core.h"
+#include "gravity_opt_env.h"
#include "gravity_optionals.h"
#include "gravity_utils.h"
-#include "gravity_core.h"
#include "gravity_vm.h"
-#include "gravity_opt_env.h"
+
#define DEFAULT_OUTPUT "gravity.g"
typedef struct {
- bool processed;
- bool is_fuzzy;
-
- uint32_t ncount;
- uint32_t nsuccess;
- uint32_t nfailure;
-
- error_type_t expected_error;
- gravity_value_t expected_value;
- int32_t expected_row;
- int32_t expected_col;
+ bool processed;
+ bool is_fuzzy;
+
+ uint32_t ncount;
+ uint32_t nsuccess;
+ uint32_t nfailure;
+
+ error_type_t expected_error;
+ gravity_value_t expected_value;
+ int32_t expected_row;
+ int32_t expected_col;
} unittest_data;
-typedef enum {
- OP_COMPILE, // just compile source code and exit
- OP_RUN, // just run an already compiled file
- OP_COMPILE_RUN, // compile source code and run it
- OP_INLINE_RUN, // compile and execute source passed inline
- OP_REPL, // run a read eval print loop
- OP_UNITTEST // unit test mode
+typedef enum {
+ OP_COMPILE, // just compile source code and exit
+ OP_RUN, // just run an already compiled file
+ OP_COMPILE_RUN, // compile source code and run it
+ OP_INLINE_RUN, // compile and execute source passed inline
+ OP_REPL, // run a read eval print loop
+ OP_UNITTEST // unit test mode
} op_type;
static const char *input_file = NULL;
@@ -44,469 +45,519 @@ static const char *unittest_folder = NULL;
static const char *test_folder_path = NULL;
static bool quiet_flag = false;
-static void report_error (gravity_vm *vm, error_type_t error_type, const char *message, error_desc_t error_desc, void *xdata) {
- (void) vm, (void) xdata;
- const char *type = "N/A";
- switch (error_type) {
- case GRAVITY_ERROR_NONE: type = "NONE"; break;
- case GRAVITY_ERROR_SYNTAX: type = "SYNTAX"; break;
- case GRAVITY_ERROR_SEMANTIC: type = "SEMANTIC"; break;
- case GRAVITY_ERROR_RUNTIME: type = "RUNTIME"; break;
- case GRAVITY_WARNING: type = "WARNING"; break;
- case GRAVITY_ERROR_IO: type = "I/O"; break;
- }
-
- if (error_type == GRAVITY_ERROR_RUNTIME) printf("RUNTIME ERROR: ");
- else printf("%s ERROR on %d (%d,%d): ", type, error_desc.fileid, error_desc.lineno, error_desc.colno);
- printf("%s\n", message);
+static void report_error(gravity_vm *vm, error_type_t error_type,
+ const char *message, error_desc_t error_desc,
+ void *xdata) {
+ (void)vm, (void)xdata;
+ const char *type = "N/A";
+ switch (error_type) {
+ case GRAVITY_ERROR_NONE:
+ type = "NONE";
+ break;
+ case GRAVITY_ERROR_SYNTAX:
+ type = "SYNTAX";
+ break;
+ case GRAVITY_ERROR_SEMANTIC:
+ type = "SEMANTIC";
+ break;
+ case GRAVITY_ERROR_RUNTIME:
+ type = "RUNTIME";
+ break;
+ case GRAVITY_WARNING:
+ type = "WARNING";
+ break;
+ case GRAVITY_ERROR_IO:
+ type = "I/O";
+ break;
+ }
+
+ if (error_type == GRAVITY_ERROR_RUNTIME)
+ printf("RUNTIME ERROR: ");
+ else
+ printf("%s ERROR on %d (%d,%d): ", type, error_desc.fileid,
+ error_desc.lineno, error_desc.colno);
+ printf("%s\n", message);
}
-static const char *load_file (const char *file, size_t *size, uint32_t *fileid, void *xdata, bool *is_static) {
- (void) fileid, (void) xdata;
-
- // this callback is called each time an import statement is parsed
- // file arg represents what user wrote after the import keyword, for example:
- // import "file2"
- // import "file2.gravity"
- // import "../file2"
- // import "/full_path_to_file2"
-
- // it is callback's responsibility to resolve file path based on current working directory
- // or based on user defined search paths
- // and returns:
- // size of file in *size
- // fileid (if any) in *fileid
- // content of file as return value of the function
-
- // fileid will then be used each time an error is reported by the compiler
- // so it is responsibility of this function to map somewhere the association
- // between fileid and real file/path name
-
- // fileid is not used in this example
- // xdata not used here but it the xdata field set in the delegate
- // please note than in this simple example the imported file must be
- // in the same folder as the main input file
-
- if (is_static) *is_static = false;
- if (!file_exists(file)) return NULL;
- return file_read(file, size);
+static const char *load_file(const char *file, size_t *size, uint32_t *fileid,
+ void *xdata, bool *is_static) {
+ (void)fileid, (void)xdata;
+
+ // this callback is called each time an import statement is parsed
+ // file arg represents what user wrote after the import keyword, for example:
+ // import "file2"
+ // import "file2.gravity"
+ // import "../file2"
+ // import "/full_path_to_file2"
+
+ // it is callback's responsibility to resolve file path based on current
+ // working directory or based on user defined search paths and returns: size
+ // of file in *size fileid (if any) in *fileid content of file as return value
+ // of the function
+
+ // fileid will then be used each time an error is reported by the compiler
+ // so it is responsibility of this function to map somewhere the association
+ // between fileid and real file/path name
+
+ // fileid is not used in this example
+ // xdata not used here but it the xdata field set in the delegate
+ // please note than in this simple example the imported file must be
+ // in the same folder as the main input file
+
+ if (is_static)
+ *is_static = false;
+ if (!file_exists(file))
+ return NULL;
+ return file_read(file, size);
}
// MARK: - Unit Test -
-static void unittest_init (const char *target_file, unittest_data *data) {
- (void) target_file;
- ++data->ncount;
- data->processed = false;
+static void unittest_init(const char *target_file, unittest_data *data) {
+ (void)target_file;
+ ++data->ncount;
+ data->processed = false;
}
-static void unittest_cleanup (const char *target_file, unittest_data *data) {
- (void) target_file, (void) data;
+static void unittest_cleanup(const char *target_file, unittest_data *data) {
+ (void)target_file, (void)data;
}
-static void unittest_callback (gravity_vm *vm, error_type_t error_type, const char *description, const char *notes, gravity_value_t value, int32_t row, int32_t col, void *xdata) {
- (void) vm;
- unittest_data *data = (unittest_data *)xdata;
- data->expected_error = error_type;
- data->expected_value = value;
- data->expected_row = row;
- data->expected_col = col;
-
- if (notes) printf("\tNOTE: %s\n", notes);
- printf("\t%s\n", description);
+static void unittest_callback(gravity_vm *vm, error_type_t error_type,
+ const char *description, const char *notes,
+ gravity_value_t value, int32_t row, int32_t col,
+ void *xdata) {
+ (void)vm;
+ unittest_data *data = (unittest_data *)xdata;
+ data->expected_error = error_type;
+ data->expected_value = value;
+ data->expected_row = row;
+ data->expected_col = col;
+
+ if (notes)
+ printf("\tNOTE: %s\n", notes);
+ printf("\t%s\n", description);
}
-static void unittest_error (gravity_vm *vm, error_type_t error_type, const char *message, error_desc_t error_desc, void *xdata) {
- (void) vm;
-
- unittest_data *data = (unittest_data *)xdata;
- if (data->processed == true) return; // ignore 2nd error
- data->processed = true;
-
- const char *type = "NONE";
- if (error_type == GRAVITY_ERROR_SYNTAX) type = "SYNTAX";
- else if (error_type == GRAVITY_ERROR_SEMANTIC) type = "SEMANTIC";
- else if (error_type == GRAVITY_ERROR_RUNTIME) type = "RUNTIME";
- else if (error_type == GRAVITY_WARNING) type = "WARNING";
-
- if (error_type == GRAVITY_ERROR_RUNTIME) printf("\tRUNTIME ERROR: ");
- else printf("\t%s ERROR on %d (%d,%d): ", type, error_desc.fileid, error_desc.lineno, error_desc.colno);
- printf("%s\n", message);
-
- bool same_error = (data->expected_error == error_type);
- bool same_row = (data->expected_row != -1) ? (data->expected_row == error_desc.lineno) : true;
- bool same_col = (data->expected_col != -1) ? (data->expected_col == error_desc.colno) : true;
-
- if (data->is_fuzzy) {
- ++data->nsuccess;
- printf("\tSUCCESS\n");
- return;
- }
-
- if (same_error && same_row && same_col) {
- ++data->nsuccess;
- printf("\tSUCCESS\n");
- } else {
- ++data->nfailure;
- printf("\tFAILURE\n");
- }
+static void unittest_error(gravity_vm *vm, error_type_t error_type,
+ const char *message, error_desc_t error_desc,
+ void *xdata) {
+ (void)vm;
+
+ unittest_data *data = (unittest_data *)xdata;
+ if (data->processed == true)
+ return; // ignore 2nd error
+ data->processed = true;
+
+ const char *type = "NONE";
+ if (error_type == GRAVITY_ERROR_SYNTAX)
+ type = "SYNTAX";
+ else if (error_type == GRAVITY_ERROR_SEMANTIC)
+ type = "SEMANTIC";
+ else if (error_type == GRAVITY_ERROR_RUNTIME)
+ type = "RUNTIME";
+ else if (error_type == GRAVITY_WARNING)
+ type = "WARNING";
+
+ if (error_type == GRAVITY_ERROR_RUNTIME)
+ printf("\tRUNTIME ERROR: ");
+ else
+ printf("\t%s ERROR on %d (%d,%d): ", type, error_desc.fileid,
+ error_desc.lineno, error_desc.colno);
+ printf("%s\n", message);
+
+ bool same_error = (data->expected_error == error_type);
+ bool same_row = (data->expected_row != -1)
+ ? (data->expected_row == error_desc.lineno)
+ : true;
+ bool same_col = (data->expected_col != -1)
+ ? (data->expected_col == error_desc.colno)
+ : true;
+
+ if (data->is_fuzzy) {
+ ++data->nsuccess;
+ printf("\tSUCCESS\n");
+ return;
+ }
+
+ if (same_error && same_row && same_col) {
+ ++data->nsuccess;
+ printf("\tSUCCESS\n");
+ } else {
+ ++data->nfailure;
+ printf("\tFAILURE\n");
+ }
}
-static const char *unittest_read (const char *path, size_t *size, uint32_t *fileid, void *xdata, bool *is_static) {
- (void) fileid, (void) xdata;
- if (is_static) *is_static = false;
-
- if (file_exists(path)) return file_read(path, size);
-
- // this unittest is able to resolve path only next to main test folder (not in nested folders)
- const char *newpath = file_buildpath(path, test_folder_path);
- if (!newpath) return NULL;
-
- const char *buffer = file_read(newpath, size);
- mem_free(newpath);
-
- return buffer;
+static const char *unittest_read(const char *path, size_t *size,
+ uint32_t *fileid, void *xdata,
+ bool *is_static) {
+ (void)fileid, (void)xdata;
+ if (is_static)
+ *is_static = false;
+
+ if (file_exists(path))
+ return file_read(path, size);
+
+ // this unittest is able to resolve path only next to main test folder (not in
+ // nested folders)
+ const char *newpath = file_buildpath(path, test_folder_path);
+ if (!newpath)
+ return NULL;
+
+ const char *buffer = file_read(newpath, size);
+ mem_free(newpath);
+
+ return buffer;
}
-static void unittest_scan (const char *folder_path, unittest_data *data) {
- DIRREF dir = directory_init(folder_path);
- if (!dir) return;
- #ifdef WIN32
- char outbuffer[MAX_PATH];
- #else
- char *outbuffer = NULL;
- #endif
- const char *target_file;
- while ((target_file = directory_read(dir, outbuffer))) {
-
- // if file is a folder then start recursion
- const char *full_path = file_buildpath(target_file, folder_path);
- if (is_directory(full_path)) {
- // skip disabled folder
- if (strcmp(target_file, "disabled") == 0) continue;
- unittest_scan(full_path, data);
- continue;
- }
-
- // test only files with a .gravity extension
- if (strstr(full_path, ".gravity") == NULL) continue;
- data->is_fuzzy = (strstr(full_path, "/fuzzy/") != NULL);
-
- // load source code
- size_t size = 0;
- const char *source_code = file_read(full_path, &size);
- assert(source_code);
-
- // start unit test
- unittest_init(target_file, data);
-
- // compile and run source code
- printf("\n%d\tTest file: %s\n", data->ncount, target_file);
- printf("\tTest path: %s\n", full_path);
- mem_free(full_path);
-
- // initialize compiler and delegates
- gravity_delegate_t delegate = {
- .xdata = (void *)data,
- .error_callback = unittest_error,
- .unittest_callback = unittest_callback,
- .loadfile_callback = unittest_read
- };
-
- gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
- gravity_closure_t *closure = gravity_compiler_run(compiler, source_code, size, 0, false, false);
- gravity_vm *vm = gravity_vm_new(&delegate);
- gravity_compiler_transfer(compiler, vm);
- gravity_compiler_free(compiler);
-
- if (closure) {
- if (gravity_vm_runmain(vm, closure)) {
- data->processed = true;
- gravity_value_t result = gravity_vm_result(vm);
- if (data->is_fuzzy || gravity_value_equals(result, data->expected_value)) {
- ++data->nsuccess;
- printf("\tSUCCESS\n");
- } else {
- ++data->nfailure;
- printf("\tFAILURE\n");
- }
- gravity_value_free(NULL, data->expected_value);
- }
- }
- gravity_vm_free(vm);
-
- // case for empty files or simple declarations test
- if (!data->processed) {
- ++data->nsuccess;
- printf("\tSUCCESS\n");
+static void unittest_scan(const char *folder_path, unittest_data *data) {
+ DIRREF dir = directory_init(folder_path);
+ if (!dir)
+ return;
+#ifdef WIN32
+ char outbuffer[MAX_PATH];
+#else
+ char *outbuffer = NULL;
+#endif
+ const char *target_file;
+ while ((target_file = directory_read(dir, outbuffer))) {
+
+ // if file is a folder then start recursion
+ const char *full_path = file_buildpath(target_file, folder_path);
+ if (is_directory(full_path)) {
+ // skip disabled folder
+ if (strcmp(target_file, "disabled") == 0)
+ continue;
+ unittest_scan(full_path, data);
+ continue;
+ }
+
+ // test only files with a .gravity extension
+ if (strstr(full_path, ".gravity") == NULL)
+ continue;
+ data->is_fuzzy = (strstr(full_path, "/fuzzy/") != NULL);
+
+ // load source code
+ size_t size = 0;
+ const char *source_code = file_read(full_path, &size);
+ assert(source_code);
+
+ // start unit test
+ unittest_init(target_file, data);
+
+ // compile and run source code
+ printf("\n%d\tTest file: %s\n", data->ncount, target_file);
+ printf("\tTest path: %s\n", full_path);
+ mem_free(full_path);
+
+ // initialize compiler and delegates
+ gravity_delegate_t delegate = {.xdata = (void *)data,
+ .error_callback = unittest_error,
+ .unittest_callback = unittest_callback,
+ .loadfile_callback = unittest_read};
+
+ gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
+ gravity_closure_t *closure =
+ gravity_compiler_run(compiler, source_code, size, 0, false, false);
+ gravity_vm *vm = gravity_vm_new(&delegate);
+ gravity_compiler_transfer(compiler, vm);
+ gravity_compiler_free(compiler);
+
+ if (closure) {
+ if (gravity_vm_runmain(vm, closure)) {
+ data->processed = true;
+ gravity_value_t result = gravity_vm_result(vm);
+ if (data->is_fuzzy ||
+ gravity_value_equals(result, data->expected_value)) {
+ ++data->nsuccess;
+ printf("\tSUCCESS\n");
+ } else {
+ ++data->nfailure;
+ printf("\tFAILURE\n");
}
-
- // cleanup unitest
- unittest_cleanup(target_file, data);
+ gravity_value_free(NULL, data->expected_value);
+ }
}
+ gravity_vm_free(vm);
+
+ // case for empty files or simple declarations test
+ if (!data->processed) {
+ ++data->nsuccess;
+ printf("\tSUCCESS\n");
+ }
+
+ // cleanup unitest
+ unittest_cleanup(target_file, data);
+ }
}
// MARK: - General -
-static void print_version (void) {
- printf("Gravity version %s (%s)\n", GRAVITY_VERSION, GRAVITY_BUILD_DATE);
+static void print_version(void) {
+ printf("Gravity version %s (%s)\n", GRAVITY_VERSION, GRAVITY_BUILD_DATE);
}
-static void print_help (void) {
- printf("Usage: gravity [options] [arguments...]\n");
- printf("\n");
- printf("To start the REPL (not yet supported):\n");
- printf(" gravity\n");
- printf("\n");
- printf("To compile and execute file:\n");
- printf(" gravity example.gravity\n");
- printf("\n");
- printf("Available options are:\n");
- printf(" --version show version information and exit\n");
- printf(" --help show command line usage and exit\n");
- printf(" -c input_file compile input_file\n");
- printf(" -o output_file specify output file name (default to gravity.json)\n");
- printf(" -x input_file execute input_file (JSON format expected)\n");
- printf(" -i source_code compile and execute source_code string\n");
- printf(" -q don't print result and execution time\n");
- printf(" -t folder run unit tests from folder\n");
+static void print_help(void) {
+ printf("Usage: gravity [options] [arguments...]\n");
+ printf("\n");
+ printf("To start the REPL (not yet supported):\n");
+ printf(" gravity\n");
+ printf("\n");
+ printf("To compile and execute file:\n");
+ printf(" gravity example.gravity\n");
+ printf("\n");
+ printf("Available options are:\n");
+ printf(" --version show version information and exit\n");
+ printf(" --help show command line usage and exit\n");
+ printf(" -c input_file compile input_file\n");
+ printf(" -o output_file specify output file name (default to "
+ "gravity.json)\n");
+ printf(" -x input_file execute input_file (JSON format expected)\n");
+ printf(" -i source_code compile and execute source_code string\n");
+ printf(" -q don't print result and execution time\n");
+ printf(" -t folder run unit tests from folder\n");
}
-static op_type parse_args (int argc, const char* argv[]) {
- if (argc == 1) return OP_REPL;
+static op_type parse_args(int argc, const char *argv[]) {
+ if (argc == 1)
+ return OP_REPL;
- if (argc == 2 && strcmp(argv[1], "--version") == 0) {
- print_version();
- exit(0);
- }
-
- if (argc == 2 && strcmp(argv[1], "--help") == 0) {
- print_help();
- exit(0);
- }
+ if (argc == 2 && strcmp(argv[1], "--version") == 0) {
+ print_version();
+ exit(0);
+ }
- op_type type = OP_RUN;
- for (int i=1; i ", &length)) != NULL) {
- // to be implemented
- // gravity_compiler_eval(compiler, vm, line, length);
- free(line);
- }
+ /*
+ // setup compiler/VM delegate
+ gravity_delegate_t delegate = {
+ .error_callback = report_error,
+ };
- gravity_compiler_free(compiler);
- gravity_vm_free(vm);
- */
+ gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
+ gravity_vm *vm = gravity_vm_new(&delegate);
+ char *line = NULL;
+ int length = 0;
+
+ printf("Welcome to Gravity v%s\n", GRAVITY_VERSION);
+ while((line = readline("> ", &length)) != NULL) {
+ // to be implemented
+ // gravity_compiler_eval(compiler, vm, line, length);
+ free(line);
+ }
+
+ gravity_compiler_free(compiler);
+ gravity_vm_free(vm);
+ */
}
-static void gravity_unittest (void) {
- unittest_data data = {
- .ncount = 0,
- .nsuccess = 0,
- .nfailure = 0
- };
-
- if (unittest_folder == NULL) {
- printf("Usage: gravity -t /path/to/unitest/\n");
- exit(-1);
- }
-
- // print console header
- printf("==============================================\n");
- printf("Gravity Unit Test Mode\n");
- printf("Gravity version %s\n", GRAVITY_VERSION);
- printf("Build date: %s\n", GRAVITY_BUILD_DATE);
- printf("==============================================\n");
-
- mem_init();
- nanotime_t tstart = nanotime();
- test_folder_path = unittest_folder;
- unittest_scan(unittest_folder, &data);
- nanotime_t tend = nanotime();
-
- double result = ((double)((data.nsuccess * 100)) / (double)data.ncount);
- printf("\n\n");
- printf("==============================================\n");
- printf("Total Tests: %d\n", data.ncount);
- printf("Total Successes: %d\n", data.nsuccess);
- printf("Total Failures: %d\n", data.nfailure);
- printf("Result: %.2f %%\n", result);
- printf("Time: %.4f ms\n", millitime(tstart, tend));
- printf("==============================================\n");
- printf("\n");
-
- // If we have 1 or more failures, return an error.
- if (data.nfailure != 0) {
- exit(1);
- }
-
- exit(0);
+static void gravity_unittest(void) {
+ unittest_data data = {.ncount = 0, .nsuccess = 0, .nfailure = 0};
+
+ if (unittest_folder == NULL) {
+ printf("Usage: gravity -t /path/to/unitest/\n");
+ exit(-1);
+ }
+
+ // print console header
+ printf("==============================================\n");
+ printf("Gravity Unit Test Mode\n");
+ printf("Gravity version %s\n", GRAVITY_VERSION);
+ printf("Build date: %s\n", GRAVITY_BUILD_DATE);
+ printf("==============================================\n");
+
+ mem_init();
+ nanotime_t tstart = nanotime();
+ test_folder_path = unittest_folder;
+ unittest_scan(unittest_folder, &data);
+ nanotime_t tend = nanotime();
+
+ double result = ((double)((data.nsuccess * 100)) / (double)data.ncount);
+ printf("\n\n");
+ printf("==============================================\n");
+ printf("Total Tests: %d\n", data.ncount);
+ printf("Total Successes: %d\n", data.nsuccess);
+ printf("Total Failures: %d\n", data.nfailure);
+ printf("Result: %.2f %%\n", result);
+ printf("Time: %.4f ms\n", millitime(tstart, tend));
+ printf("==============================================\n");
+ printf("\n");
+
+ // If we have 1 or more failures, return an error.
+ if (data.nfailure != 0) {
+ exit(1);
+ }
+
+ exit(0);
}
// MARK: -
-int main (int argc, const char* argv[]) {
- // parse arguments and return operation type
- op_type type = parse_args(argc, argv);
+int
+#ifdef ZIG_BOOTSTRAP
+c_main
+#else
+main
+#endif
+(int argc, const char* argv[]) {
+ // parse arguments and return operation type
+ op_type type = parse_args(argc, argv);
- // special repl case
- if (type == OP_REPL) gravity_repl();
-
- // special unit test mode
- if (type == OP_UNITTEST) gravity_unittest();
+ // special repl case
+ if (type == OP_REPL)
+ gravity_repl();
- // initialize memory debugger (if activated)
- mem_init();
+ // special unit test mode
+ if (type == OP_UNITTEST)
+ gravity_unittest();
- // closure to execute/serialize
- gravity_closure_t *closure = NULL;
+ // initialize memory debugger (if activated)
+ mem_init();
- // optional compiler
- gravity_compiler_t *compiler = NULL;
+ // closure to execute/serialize
+ gravity_closure_t *closure = NULL;
- // setup compiler/VM delegate
- gravity_delegate_t delegate = {
- .error_callback = report_error,
- .loadfile_callback = load_file
- };
+ // optional compiler
+ gravity_compiler_t *compiler = NULL;
- // create VM
- gravity_vm *vm = gravity_vm_new(&delegate);
+ // setup compiler/VM delegate
+ gravity_delegate_t delegate = {.error_callback = report_error,
+ .loadfile_callback = load_file};
- // pass argc and argv to the ENV class
- gravity_env_register_args(vm, argc, argv);
+ // create VM
+ gravity_vm *vm = gravity_vm_new(&delegate);
- // check if input file is source code that needs to be compiled
- if ((type == OP_COMPILE) || (type == OP_COMPILE_RUN) || (type == OP_INLINE_RUN)) {
+ // pass argc and argv to the ENV class
+ gravity_env_register_args(vm, argc, argv);
- // load source code
- size_t size = 0;
- const char *source_code = NULL;
+ // check if input file is source code that needs to be compiled
+ if ((type == OP_COMPILE) || (type == OP_COMPILE_RUN) ||
+ (type == OP_INLINE_RUN)) {
- if (type == OP_INLINE_RUN) {
- source_code = input_file;
- size = strlen(input_file);
- } else {
- source_code = file_read(input_file, &size);
- }
-
- // sanity check
- if (!source_code || !size) {
- printf("Error loading %s %s\n", (type == OP_INLINE_RUN) ? "source" : "file", input_file);
- goto cleanup;
- }
+ // load source code
+ size_t size = 0;
+ const char *source_code = NULL;
- // create closure to execute inline code
- if (type == OP_INLINE_RUN) {
- char *buffer = mem_alloc(NULL, size+1024);
- assert(buffer);
- size = snprintf(buffer, size+1024, "func main() {%s};", input_file);
- source_code = buffer;
- }
+ if (type == OP_INLINE_RUN) {
+ source_code = input_file;
+ size = strlen(input_file);
+ } else {
+ source_code = file_read(input_file, &size);
+ }
- // create compiler
- compiler = gravity_compiler_create(&delegate);
+ // sanity check
+ if (!source_code || !size) {
+ printf("Error loading %s %s\n",
+ (type == OP_INLINE_RUN) ? "source" : "file", input_file);
+ goto cleanup;
+ }
- // compile source code into a closure
- closure = gravity_compiler_run(compiler, source_code, size, 0, false, true);
- if (!closure) goto cleanup;
+ // create closure to execute inline code
+ if (type == OP_INLINE_RUN) {
+ char *buffer = mem_alloc(NULL, size + 1024);
+ assert(buffer);
+ size = snprintf(buffer, size + 1024, "func main() {%s};", input_file);
+ source_code = buffer;
+ }
- // check if closure needs to be serialized
- if (type == OP_COMPILE) {
- bool result = gravity_compiler_serialize_infile(compiler, closure, output_file);
- if (!result) printf("Error serializing file %s\n", output_file);
- goto cleanup;
- }
+ // create compiler
+ compiler = gravity_compiler_create(&delegate);
+
+ // compile source code into a closure
+ closure = gravity_compiler_run(compiler, source_code, size, 0, false, true);
+ if (!closure)
+ goto cleanup;
+
+ // check if closure needs to be serialized
+ if (type == OP_COMPILE) {
+ bool result =
+ gravity_compiler_serialize_infile(compiler, closure, output_file);
+ if (!result)
+ printf("Error serializing file %s\n", output_file);
+ goto cleanup;
+ }
- // op is OP_COMPILE_RUN so transfer memory from compiler to VM
- gravity_compiler_transfer(compiler, vm);
+ // op is OP_COMPILE_RUN so transfer memory from compiler to VM
+ gravity_compiler_transfer(compiler, vm);
- } else if (type == OP_RUN) {
- // unserialize file
- closure = gravity_vm_loadfile(vm, input_file);
- if (!closure) {
- printf("Error while loading compile file %s\n", input_file);
- goto cleanup;
- }
+ } else if (type == OP_RUN) {
+ // unserialize file
+ closure = gravity_vm_loadfile(vm, input_file);
+ if (!closure) {
+ printf("Error while loading compile file %s\n", input_file);
+ goto cleanup;
}
+ }
- // sanity check
- assert(closure);
+ // sanity check
+ assert(closure);
- if (gravity_vm_runmain(vm, closure)) {
- gravity_value_t result = gravity_vm_result(vm);
- double t = gravity_vm_time(vm);
+ if (gravity_vm_runmain(vm, closure)) {
+ gravity_value_t result = gravity_vm_result(vm);
+ double t = gravity_vm_time(vm);
- char buffer[512];
- gravity_value_dump(vm, result, buffer, sizeof(buffer));
- if (!quiet_flag) {
- printf("RESULT: %s (in %.4f ms)\n\n", buffer, t);
- }
+ char buffer[512];
+ gravity_value_dump(vm, result, buffer, sizeof(buffer));
+ if (!quiet_flag) {
+ printf("RESULT: %s (in %.4f ms)\n\n", buffer, t);
}
+ }
cleanup:
- if (compiler) gravity_compiler_free(compiler);
- if (vm) gravity_vm_free(vm);
- gravity_core_free();
-
- #if GRAVITY_MEMORY_DEBUG
- size_t current_memory = mem_leaks();
- if (current_memory != 0) {
- printf("--> VM leaks: %zu bytes\n", current_memory);
- mem_stat();
- } else {
- printf("\tNo VM leaks found!\n");
- }
- #endif
-
- return 0;
+ if (compiler)
+ gravity_compiler_free(compiler);
+ if (vm)
+ gravity_vm_free(vm);
+ gravity_core_free();
+
+#if GRAVITY_MEMORY_DEBUG
+ size_t current_memory = mem_leaks();
+ if (current_memory != 0) {
+ printf("--> VM leaks: %zu bytes\n", current_memory);
+ mem_stat();
+ } else {
+ printf("\tNo VM leaks found!\n");
+ }
+#endif
+
+ return 0;
}
diff --git a/src/compiler/gravity_ircode.c b/src/compiler/gravity_ircode.c
index d0366b4..b53f93e 100644
--- a/src/compiler/gravity_ircode.c
+++ b/src/compiler/gravity_ircode.c
@@ -52,7 +52,7 @@ ircode_t *ircode_create (uint16_t nlocals) {
marray_init(code->context);
// init state array (register 0 is reserved)
- bzero(code->state, MAX_REGISTERS * sizeof(bool));
+ memset(code->state, 0, MAX_REGISTERS * sizeof(bool));
code->state[0] = true;
for (uint32_t i=0; istate[i] = true;
diff --git a/src/compiler/gravity_lexer.c b/src/compiler/gravity_lexer.c
index 9d6bf86..0c9ea08 100644
--- a/src/compiler/gravity_lexer.c
+++ b/src/compiler/gravity_lexer.c
@@ -533,7 +533,7 @@ gravity_lexer_t *gravity_lexer_create (const char *source, size_t len, uint32_t
gravity_lexer_t *lexer = mem_alloc(NULL, sizeof(gravity_lexer_t));
if (!lexer) return NULL;
- bzero(lexer, sizeof(gravity_lexer_t));
+ memset(lexer, 0, sizeof(gravity_lexer_t));
lexer->is_static = is_static;
lexer->lineno = 1;
lexer->buffer = source;
diff --git a/src/runtime/gravity_core.h b/src/runtime/gravity_core.h
index 956f361..d6d4ce9 100644
--- a/src/runtime/gravity_core.h
+++ b/src/runtime/gravity_core.h
@@ -30,8 +30,8 @@ gravity_value_t convert_value2int (gravity_vm *vm, gravity_value_t v);
gravity_value_t convert_value2string (gravity_vm *vm, gravity_value_t v);
// internal functions
-gravity_closure_t *computed_property_create (gravity_vm *vm, gravity_function_t *getter_func, gravity_function_t *setter_func);
-void computed_property_free (gravity_class_t *c, const char *name, bool remove_flag);
+GRAVITY_API gravity_closure_t *computed_property_create (gravity_vm *vm, gravity_function_t *getter_func, gravity_function_t *setter_func);
+GRAVITY_API void computed_property_free (gravity_class_t *c, const char *name, bool remove_flag);
#ifdef __cplusplus
}
diff --git a/src/shared/gravity_config.h b/src/shared/gravity_config.h
index b539ff6..f1d951d 100644
--- a/src/shared/gravity_config.h
+++ b/src/shared/gravity_config.h
@@ -19,29 +19,29 @@
#endif
#if (!defined(HAVE_SNPRINTF) || !defined(snprintf))
-#define snprintf _snprintf
+#define snprintf _snprintf
#endif
-typedef SSIZE_T ssize_t;
-typedef int mode_t;
+typedef SSIZE_T ssize_t;
+typedef int mode_t;
-#define open _open
-#define close _close
-#define read _read
-#define write _write
-#define __func__ __FUNCTION__
-#define PATH_SEPARATOR '\\'
+#define open _open
+#define close _close
+#define read _read
+#define write _write
+#define __func__ __FUNCTION__
+#define PATH_SEPARATOR '\\'
#else
#include
-#define PATH_SEPARATOR '/'
+#define PATH_SEPARATOR '/'
#endif
// check if the compiler supports designated initializers when using c++
#ifndef GRAVITY_USE_HIDDEN_INITIALIZERS
- #if __cplusplus && (__cplusplus < 202002L)
- // C++ di requires C++20
- #define GRAVITY_USE_HIDDEN_INITIALIZERS 1
- #endif // __cplusplus
+#if __cplusplus && (__cplusplus < 202002L)
+// C++ di requires C++20
+#define GRAVITY_USE_HIDDEN_INITIALIZERS 1
+#endif // __cplusplus
#endif // GRAVITY_USE_HIDDEN_INITIALIZERS
#endif // __GRAVITY_CONFIG__