Skip to content

Commit

Permalink
hostfunc, reduce embedded footprint, fleshing out embedded API.
Browse files Browse the repository at this point in the history
  • Loading branch information
fubark committed Sep 22, 2023
1 parent f95cd18 commit 3e2530f
Show file tree
Hide file tree
Showing 39 changed files with 2,126 additions and 1,538 deletions.
66 changes: 47 additions & 19 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ const tcc_lib = @import("lib/tcc/lib.zig");
// FIND: v0.2
const Version = "0.2";

var useMalloc: bool = undefined;
var optMalloc: ?config.Allocator = undefined;
var selinux: bool = undefined;
var vmEngine: config.Engine = undefined;
var testFilter: ?[]const u8 = undefined;
var trace: bool = undefined;
var optFFI: ?bool = undefined;

var stdx: *std.build.Module = undefined;
var tcc: *std.build.Module = undefined;
Expand All @@ -23,8 +24,9 @@ pub fn build(b: *std.build.Builder) !void {

selinux = b.option(bool, "selinux", "Whether you are building on linux distro with selinux. eg. Fedora.") orelse false;
testFilter = b.option([]const u8, "test-filter", "Test filter.");
useMalloc = b.option(bool, "use-malloc", "Use C allocator.") orelse false;
vmEngine = b.option(config.Engine, "vm", "Build with `zig` or `c` VM.") orelse .c;
optMalloc = b.option(config.Allocator, "malloc", "Override default allocator: `malloc`, `mimalloc`, `zig`");
optFFI = b.option(bool, "ffi", "Override default FFI: true, false");
trace = b.option(bool, "trace", "Enable tracing features.") orelse (optimize == .Debug);

stdx = b.createModule(.{
Expand All @@ -36,7 +38,8 @@ pub fn build(b: *std.build.Builder) !void {
{
const step = b.step("cli", "Build main cli.");

const opts = getDefaultOptions(target, optimize);
var opts = getDefaultOptions(target, optimize);
opts.applyOverrides();

const exe = b.addExecutable(.{
.name = "cyber",
Expand All @@ -63,7 +66,7 @@ pub fn build(b: *std.build.Builder) !void {

// exe.linkLibC();
exe.addModule("stdx", stdx);
if (opts.useMimalloc) {
if (opts.malloc == .mimalloc) {
mimalloc_lib.addModule(exe, "mimalloc", mimalloc);
mimalloc_lib.buildAndLink(b, exe, .{});
}
Expand All @@ -78,7 +81,10 @@ pub fn build(b: *std.build.Builder) !void {
{
const step = b.step("lib", "Build as a library.");

const opts = getDefaultOptions(target, optimize);
var opts = getDefaultOptions(target, optimize);
opts.ffi = false;
opts.malloc = .malloc;
opts.applyOverrides();

const lib = b.addSharedLibrary(.{
.name = "cyber",
Expand All @@ -101,7 +107,7 @@ pub fn build(b: *std.build.Builder) !void {
try addBuildOptions(b, lib, opts);

lib.addModule("stdx", stdx);
if (opts.useMimalloc) {
if (opts.malloc == .mimalloc) {
mimalloc_lib.addModule(lib, "mimalloc", mimalloc);
mimalloc_lib.buildAndLink(b, lib, .{});
} else {
Expand All @@ -112,7 +118,7 @@ pub fn build(b: *std.build.Builder) !void {
try buildCVM(b.allocator, lib, opts);
}

if (!target.getCpuArch().isWasm()) {
if (opts.ffi) {
tcc_lib.addModule(lib, "tcc", tcc);
tcc_lib.buildAndLink(b, lib, .{
.selinux = selinux,
Expand All @@ -133,6 +139,7 @@ pub fn build(b: *std.build.Builder) !void {

var opts = getDefaultOptions(target, optimize);
opts.trackGlobalRc = true;
opts.applyOverrides();

var step = b.addTest(.{
// Lib test includes main tests.
Expand All @@ -148,7 +155,7 @@ pub fn build(b: *std.build.Builder) !void {
step.addModule("stdx", stdx);
step.rdynamic = true;

if (opts.useMimalloc) {
if (opts.malloc == .mimalloc) {
mimalloc_lib.addModule(step, "mimalloc", mimalloc);
mimalloc_lib.buildAndLink(b, step, .{});
}
Expand All @@ -159,7 +166,7 @@ pub fn build(b: *std.build.Builder) !void {

step.linkLibC();

if (!target.getCpuArch().isWasm()) {
if (opts.ffi) {
tcc_lib.addModule(step, "tcc", tcc);
tcc_lib.buildAndLink(b, step, .{
.selinux = selinux,
Expand All @@ -183,6 +190,7 @@ pub fn build(b: *std.build.Builder) !void {

var opts = getDefaultOptions(target, optimize);
opts.trackGlobalRc = true;
opts.applyOverrides();

var step = b.addTest(.{
.root_source_file = .{ .path = "./test/main_test.zig" },
Expand All @@ -197,7 +205,7 @@ pub fn build(b: *std.build.Builder) !void {
step.addModule("stdx", stdx);
step.rdynamic = true;

if (opts.useMimalloc) {
if (opts.malloc == .mimalloc) {
mimalloc_lib.addModule(step, "mimalloc", mimalloc);
mimalloc_lib.buildAndLink(b, step, .{});
}
Expand All @@ -221,6 +229,7 @@ pub fn build(b: *std.build.Builder) !void {

var opts = getDefaultOptions(target, optimize);
opts.trackGlobalRc = true;
opts.applyOverrides();

var step = b.addTest(.{
.root_source_file = .{ .path = "./test/lib_test.zig" },
Expand All @@ -235,7 +244,7 @@ pub fn build(b: *std.build.Builder) !void {
step.addModule("stdx", stdx);
step.rdynamic = true;

if (opts.useMimalloc) {
if (opts.malloc == .mimalloc) {
mimalloc_lib.addModule(step, "mimalloc", mimalloc);
mimalloc_lib.buildAndLink(b, step, .{});
}
Expand All @@ -259,6 +268,8 @@ pub fn build(b: *std.build.Builder) !void {
const mainStep = b.step("test-trace", "Run trace tests.");
var opts = getDefaultOptions(target, optimize);
opts.trackGlobalRc = true;
opts.applyOverrides();

const step = try addTraceTest(b, opts);
mainStep.dependOn(&b.addRunArtifact(step).step);
}
Expand All @@ -282,25 +293,43 @@ pub const Options = struct {
trace: bool,
target: std.zig.CrossTarget,
optimize: std.builtin.OptimizeMode,
useMimalloc: bool,
malloc: config.Allocator,
gc: bool,
ffi: bool,

fn applyOverrides(self: *Options) void {
if (optMalloc) |malloc| {
self.malloc = malloc;
}
if (optFFI) |ffi| {
self.ffi = ffi;
}
}
};

// deps: struct {
// tcc: *std.build.Module,
// },

fn getDefaultOptions(target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) Options {
var malloc: config.Allocator = .malloc;
// Use mimalloc for fast builds.
if (target.getCpuArch().isWasm()) {
malloc = .zig;
} else {
if (optimize == .ReleaseFast) {
malloc = .mimalloc;
}
}
return .{
.selinux = selinux,
.trackGlobalRc = optimize != .ReleaseFast,
.trace = trace,
.target = target,
.optimize = optimize,
.gc = true,

// Use mimalloc for fast builds.
.useMimalloc = optimize == .ReleaseFast and !target.getCpuArch().isWasm(),
.malloc = malloc,
.ffi = !target.getCpuArch().isWasm(),
};
}

Expand All @@ -323,14 +352,13 @@ fn createBuildOptions(b: *std.build.Builder, opts: Options) !*std.build.Step.Opt
build_options.addOption([]const u8, "version", Version);
build_options.addOption([]const u8, "build", buildTag);
build_options.addOption([]const u8, "commit", commitTag);
build_options.addOption(bool, "useMalloc", useMalloc);
build_options.addOption(bool, "useMimalloc", opts.useMimalloc);

build_options.addOption(config.Allocator, "malloc", opts.malloc);
build_options.addOption(config.Engine, "vmEngine", vmEngine);
build_options.addOption(bool, "trace", opts.trace);
build_options.addOption(bool, "trackGlobalRC", opts.trackGlobalRc);
build_options.addOption(bool, "is32Bit", is32Bit(opts.target));
build_options.addOption(bool, "gc", opts.gc);
build_options.addOption(bool, "ffi", opts.ffi);
build_options.addOption([]const u8, "full_version", b.fmt("Cyber {s} build-{s}-{s}", .{Version, buildTag, commitTag}));
return build_options;
}
Expand All @@ -356,7 +384,7 @@ fn addTraceTest(b: *std.build.Builder, opts: Options) !*std.build.LibExeObjStep
try addBuildOptions(b, step, newOpts);
step.addModule("stdx", stdx);

if (newOpts.useMimalloc) {
if (newOpts.malloc == .mimalloc) {
mimalloc_lib.addModule(step, "mimalloc", mimalloc);
mimalloc_lib.buildAndLink(b, step, .{});
}
Expand Down
51 changes: 27 additions & 24 deletions docs/hugo/content/docs/toc/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,42 +79,34 @@ The annotation `@hide` provides a hint to editors that the static symbol should
> _Planned Feature_

## Builtin Modules.
Builtin modules are the bare minimum that comes with Cyber. The [embeddable library]({{<relref "/docs/toc/embedding">}}) contains these modules and nothing more. They include:
- [builtins](#builtins): Cyber related functions and commonly used utilities.
- [math](#math): Math constants and functions.
> _Incomplete: The docs for builtin modules are not completely up-to-date. They will be auto generated in the future._

Cyber currently contains the builtin modules:
- [core](#core-module): Cyber related functions and commonly used utilities.
- [math](#math-module): Math constants and functions.
- [os](#os-module): System level functions.
- [test](#test-module): Utilities for testing.

> _Incomplete: The docs for builtins are not completely up-to-date. They will be auto generated in the future._

## Core Module.
The core module contains functions related to Cyber and common utilities. It is automatically imported into each script's namespace.
## builtins.
The `builtins` module contains functions related to Cyber and common utilities. It is automatically imported into each script's namespace.

Sample usage:
```cy
-- `print` and `typeid` are available without imports.
print 'hello'
var contents = readFile 'foo.txt'
print contents
var id = typeid('my str')
print id
```

| Function | Summary |
| ------------- | ----- |
| `arrayFill(val any, n int) List` | Creates a list with initial capacity of `n` and values set to `val`. If the value is an object, it is shallow copied `n` times. |
| `boolean(val any) boolean` | Converts a value to either `true` or `false`. |
| `cacheUrl(url string) string` | Returns the path of a locally cached file of `url`. If no such file exists locally, it's fetched from `url`. |
| `copy(val any) any` | Copies a primitive value or creates a shallow copy of an object value. |
| `error(e (enum \| symbol)) error` | Create an error from an enum or symbol. |
| `execCmd(args []string) Map{ out, err, exited }` | Runs a shell command and returns the stdout/stderr. |
| `exit(status int) noreturn` | Exits the program with a status code. |
| `evalJS(val string) none` | Evals JS from the host environment. This is only available in a web WASM build of Cyber. |
| `fetchUrl(url string) rawstring` | Fetches the contents at `url` using the HTTP GET request method. |
| `getInput() rawstring` | Reads stdin until a new line is reached. This is intended to read user input from the command line. For bulk reads from stdin, use `os.stdin`. |
| `float(val any) float` | Casts or converts the value to a `float`. Panics if type conversion fails. |
| `int(val any) int` | Converts a value to an 32-bit integer. |
| `isAlpha(val int) boolean` | Returns whether a rune is an alphabetic letter. |
| `isDigit(val int) boolean` | Returns whether a rune is a digit. |
| `must(val any) any \| noreturn` | If `val` is an error, `panic(val)` is invoked. Otherwise, `val` is returned. |
| `float(val any) float` | Casts or converts the value to a `float`. Panics if type conversion fails. |
| `panic(e symbol) noreturn` | Stop execution in the current fiber and starts unwinding the call stack. See [Unexpected Errors]({{<relref "/docs/toc/errors#unexpected-errors">}}). |
| `parseCyber(src any) map` | Parses Cyber source string into structured map object. Currently, only metadata about static declarations is made available but this will be extended to include an AST. |
| `parseCyon(src any) any` | Parses a CYON string into a value. |
Expand All @@ -123,16 +115,13 @@ print contents
| `print(s string) none` | Prints a value as a string to stdout. The new line is also printed. |
| `prints(s string) none` | Prints a value as a string to stdout. |
| `rawstring(str string) rawstring` | Converts a string to a `rawstring`. |
| `readAll() rawstring` | Reads stdin to the EOF as a `rawstring`. |
| `readFile(path string) rawstring` | Reads the file contents into a `rawstring` value. |
| `runestr(val int) string` | Converts a rune to a string. |
| `string(val any) string` | Converts a value to a string. |
| `toCyon(val any) string` | Encodes a value to CYON string. |
| `typeof(any) metatype` | Returns the value's type as a `metatype` object. |
| `typesym(any) symbol` | Returns the value's type as one of the predefined symbols: #float, #int, #boolean, #object, #list, #map, #string, #rawstring, #function, #fiber, #pointer, #symbol, #metatype, #none, #error |
| `writeFile(path string, contents string) none` | Writes a string value to a file. |

## Math Module.
## math.
The math module contains commonly used math constants and functions.

Sample usage:
Expand Down Expand Up @@ -195,7 +184,13 @@ print(m.pi * r^2)
| tanh(float) float | Returns the hyperbolic tangent of x. |
| trunc(float) float | Returns the integer portion of x, removing any fractional digits. |

## Os Module.
## Std Modules.
Std modules come with Cyber's CLI. They include:
- [os](#os): System level functions.
- [test](#test): Utilities for testing.
> _Incomplete: The docs for std modules are not completely up-to-date. They will be auto generated in the future._

## os.
Cyber's os module contains system level functions. It's still undecided as to how much should be included here so it's incomplete. You can still access os and libc functions yourself using Cyber's FFI or embedding API.

Sample usage:
Expand All @@ -222,29 +217,37 @@ for map each k, v:
| `args() List<string \| rawstring>` | Returns the command line arguments as a list. Each argument is validated and returned as a UTF-8 `string` or `rawstring` if the validation failed. |
| `bindLib(path any, decls [](CFunc\|CStruct)) Object \| Map` | Calls `bindLib(path, decls, {})`. |
| `bindLib(path any, decls [](CFunc\|CStruct), config: BindLibConfig) Object \| Map` | Creates an FFI binding to a dynamic library and it's symbols. By default, an anonymous object is returned with the C-functions binded as the object's methods. If `config` contains `genMap: true`, a `Map` is returned instead with C-functions binded as function values. |
| `cacheUrl(url string) string` | Returns the path of a locally cached file of `url`. If no such file exists locally, it's fetched from `url`. |
| `copyFile(srcPath any, dstPath any) none \| error` | Copies a file to a destination path. |
| `createDir(path any) true \| error` | Creates the directory at `path`. Returns `true` if successful. |
| `createFile(path any, truncate boolean) File \| error` | Creates and opens the file at `path`. If `truncate` is true, an existing file will be truncated. |
| `cstr(any) pointer` | Returns a null terminated C string. |
| `cwd() string` | Returns the current working directory. |
| `dirName(path any) string \| none` | Returns the given path with its last component removed. |
| `execCmd(args []string) Map{ out, err, exited }` | Runs a shell command and returns the stdout/stderr. |
| `exePath() string` | Returns the current executable's path. |
| `exit(status int) noreturn` | Exits the program with a status code. |
| `fetchUrl(url string) rawstring` | Fetches the contents at `url` using the HTTP GET request method. |
| `free(ptr pointer) none` | Frees the memory located at `ptr`. |
| `fromCstr(pointer) rawstring` | Returns a `rawstring` from a null terminated C string. |
| `getEnv(key any) string \| none` | Returns an environment value by key. |
| `getEnvAll() Map` | Returns all environment entries as a `Map`. |
| `getInput() rawstring` | Reads stdin until a new line is reached. This is intended to read user input from the command line. For bulk reads from stdin, use `os.stdin`. |
| `malloc(size int) pointer` | Allocates `size` bytes of memory and returns a pointer. |
| `milliTime() float` | Return the calendar timestamp, in milliseconds, relative to UTC 1970-01-01. |
| `openDir(path any) Dir \| error` | Invokes `openDir(path, false)`. |
| `openDir(path any, iterable boolean) Dir \| error` | Opens a directory at the given `path`. `iterable` indicates that the directory's entries can be iterated. |
| `openFile(path any, mode (#read \| #write \| #readWrite)) File \| error` | Opens a file at the given `path` with the `#read`, `#write`, or `#readWrite` mode. |
| `parseArgs(options list[ArgOption]) map` | Given expected `ArgOption`s, returns a map of the options and a `rest` entry which contains the non-option arguments. |
| `readAll() rawstring` | Reads stdin to the EOF as a `rawstring`. |
| `readFile(path string) rawstring` | Reads the file contents into a `rawstring` value. |
| `realPath(path any) string \| error` | Returns the absolute path of the given path. |
| `removeDir(path any) true \| error` | Removes an empty directory at `path`. Returns `true` if successful. |
| `removeFile(path any) true \| error` | Removes the file at `path`. Returns `true` if successful. |
| `setEnv(key any, value any) none` | Sets an environment value by key. |
| `sleep(ms float) none` | Pauses the current thread for given milliseconds. |
| `unsetEnv(key any) none` | Removes an environment value by key. |
| `writeFile(path string, contents string) none` | Writes a string value to a file. |
### `type File`
| Method | Summary |
Expand Down Expand Up @@ -287,7 +290,7 @@ for map each k, v:
| `'type' -> metatype(string \| float \| boolean)` | Parse as given value type. |
| `'default' -> any` | Optional: Default value if option is missing. `none` is used if this is not provided. |
## Test Module.
## test.
The `test` module contains utilities for testing.
Sample usage:
Expand Down
3 changes: 2 additions & 1 deletion docs/hugo/content/docs/toc/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ var myImage:
The final resulting value that is assigned to the static variable is provided by a `break` statement. If a `break` statement is not provided, `none` is assigned instead.
## Keywords.
There are currently `33` keywords in Cyber. This list categorizes them and shows you when you might need them.
There are currently `34` keywords in Cyber. This list categorizes them and shows you when you might need them.
- [Control Flow]({{<relref "/docs/toc/control-flow">}}): `if` `then` `else` `match` `while` `for` `each` `break` `continue` `pass` `some`
- [Operators](#operators): `or` `and` `not` `is`
Expand All @@ -169,6 +169,7 @@ There are currently `33` keywords in Cyber. This list categorizes them and shows
- [Data Types]({{<relref "/docs/toc/data-types">}}): `type` `object` `enum` `true` `false` `none`
- [Error Handling]({{<relref "/docs/toc/errors">}}): `try` `catch` `error` `throw`
- [Modules]({{<relref "/docs/toc/modules">}}): `import`
- [Embedding]({{<relref "/docs/toc/embedding">}}): `hostfunc`
## Operators.
Cyber supports the following operators. They are ordered from highest to lowest precedence.
Expand Down
Loading

0 comments on commit 3e2530f

Please sign in to comment.