Skip to content

Commit

Permalink
Instantiate host objects. More endpoints. Update example.
Browse files Browse the repository at this point in the history
  • Loading branch information
fubark committed Sep 28, 2023
1 parent 2a7f334 commit 037607a
Show file tree
Hide file tree
Showing 18 changed files with 317 additions and 124 deletions.
1 change: 1 addition & 0 deletions docs/hugo/content/docs/toc/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ print id
| `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`. |
| `copy(val any) any` | Copies a primitive value or creates a shallow copy of an object value. |
| `dump(val any) none` | Prints the result of `toCyon` on a value. |
| `error(e (enum \| symbol)) error` | Create an error from an enum or symbol. |
| `evalJS(val string) none` | Evals JS from the host environment. This is only available in a web WASM build of Cyber. |
| `float(val any) float` | Casts or converts the value to a `float`. Panics if type conversion fails. |
Expand Down
109 changes: 94 additions & 15 deletions examples/c-embedded/bind_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,21 @@ CsValue add(CsVM* vm, const CsValue* args, uint8_t nargs) {
double res = csAsFloat(args[0]) + csAsFloat(args[1]);
return csFloat(res);
}
struct { char* n; CsHostFuncFn fn; } funcs[] = {

// Forward declaration.
CsValue myCollectionNew(CsVM* vm, const CsValue* args, uint8_t nargs);
CsValue myCollectionAsList(CsVM* vm, const CsValue* args, uint8_t nargs);

struct { char* n; CsFuncFn fn; } funcs[] = {
{"add", add},
{"new", myCollectionNew},
{"asList", myCollectionAsList},
};

bool funcLoader(CsVM* vm, CsHostFuncInfo funcInfo, CsHostFuncResult* out) {
bool funcLoader(CsVM* vm, CsFuncInfo info, CsFuncResult* out) {
// Check that the name matches before setting the function pointer.
if (strncmp(funcs[funcInfo.idx].n, funcInfo.name.buf, funcInfo.name.len) == 0) {
out->ptr = funcs[funcInfo.idx].fn;
if (strncmp(funcs[info.idx].n, info.name.buf, info.name.len) == 0) {
out->ptr = funcs[info.idx].fn;
return true;
} else {
return false;
Expand All @@ -35,27 +42,93 @@ bool funcLoader(CsVM* vm, CsHostFuncInfo funcInfo, CsHostFuncResult* out) {
typedef struct { char* n; CsValue v; } NameValue;
NameValue vars[2];

bool varLoader(CsVM* vm, CsHostVarInfo varInfo, CsValue* out) {
bool varLoader(CsVM* vm, CsVarInfo info, CsValue* out) {
// Check that the name matches before setting the value.
if (strncmp(vars[varInfo.idx].n, varInfo.name.buf, varInfo.name.len) == 0) {
if (strncmp(vars[info.idx].n, info.name.buf, info.name.len) == 0) {
// Objects are consumed by the module.
*out = vars[varInfo.idx].v;
*out = vars[info.idx].v;
return true;
} else {
return false;
}
}

// Binding a C struct with it's own children and finalizer.
// This struct retains 2 VM values and has 2 arbitrary data values unrelated to the VM.
typedef struct MyCollection {
CsValue val1;
CsValue val2;
int a;
double b;
} MyCollection;

CsTypeId myCollectionId;

// Implement the `new` function in MyCollection.
CsValue myCollectionNew(CsVM* vm, const CsValue* args, uint8_t nargs) {
// Instantiate our object.
CsValue new = csNewHostObject(vm, myCollectionId, sizeof(MyCollection));
MyCollection* my = (MyCollection*)csAsHostObject(new);

// Assign the constructor args passed in and retain them since our object now
// has shared ownership.
csRetain(vm, args[0]);
my->val1 = args[0];
csRetain(vm, args[1]);
my->val2 = args[1];

// Assign non VM values.
my->a = 123;
my->b = 9999.999;
return new;
}

// Implement the `asList` method in MyCollection.
CsValue myCollectionAsList(CsVM* vm, const CsValue* args, uint8_t nargs) {
// First argument is `self`.
MyCollection* my = (MyCollection*)csAsHostObject(args[0]);

CsValue vals[4] = {my->val1, my->val2, csInteger(my->a), csFloat(my->b)};
return csNewList(vm, &vals[0], 4);
}

CsValueSlice myCollectionGetChildren(CsVM* vm, void* obj) {
MyCollection* my = (MyCollection*)obj;
return (CsValueSlice){ .ptr = &my->val1, .len = 2 };
}

void myCollectionFinalizer(CsVM* vm, void* obj) {
printf("MyCollection finalizer was called.\n");
}

bool typeLoader(CsVM* vm, CsTypeInfo info, CsTypeResult* out) {
if (strncmp("MyCollection", info.name.buf, info.name.len) == 0) {
out->data.object.outTypeId = &myCollectionId;
out->data.object.getChildren = myCollectionGetChildren;
out->data.object.finalizer = myCollectionFinalizer;
return true;
} else {
return NULL;
return false;
}
}

// This module loader provides the source code and callbacks to load @host funcs, vars, and types.
bool modLoader(CsVM* vm, CsStr spec, CsModuleLoaderResult* out) {
if (strncmp("my_engine", spec.buf, spec.len) == 0) {
out->src = STR(
"@host func add(a float, b float) float\n"
"@host var MyConstant float\n"
"@host var MyList List\n"
"\n"
"@host\n"
"type MyCollection object:\n"
" @host func new(a, b) MyCollection\n"
" @host func asList(self) any"
);
out->srcIsStatic = true;
out->funcLoader = funcLoader;
out->varLoader = varLoader;
out->typeLoader = typeLoader;
return true;
} else {
// Fallback to the default module loader to load `builtins`.
Expand All @@ -75,23 +148,29 @@ int main() {

// Initialize var array for loader.
vars[0] = (NameValue){"MyConstant", csFloat(1.23)};
vars[1] = (NameValue){"MyList", csNewList(vm)};
CsValue myInt = csInteger(123);
vars[1] = (NameValue){"MyList", csNewList(vm, &myInt, 1)};

CsStr main = STR(
"import mod 'my_engine'\n"
"import eng 'my_engine'\n"
"\n"
"var a = 1.0\n"
"print mod.add(a, 2)\n"
"print(-mod.MyConstant)\n"
"mod.MyList.append(3)\n"
"print mod.MyList.len()\n"
"print eng.add(a, 2)\n"
"print(-eng.MyConstant)\n"
"\n"
"eng.MyList.append(3)\n"
"print eng.MyList.len()\n"
"\n"
"-- Instantiate a new MyCollection.\n"
"var myc = eng.MyCollection.new(1, 2)\n"
"dump myc.asList()"
);
CsValue resv;
CsResultCode res = csEval(vm, main, &resv);
if (res == CS_SUCCESS) {
printf("Success!\n");
} else {
CsStr err = csAllocLastErrorReport(vm);
CsStr err = csNewLastErrorReport(vm);
PRINTS(err);
csFreeStr(vm, err);
}
Expand Down
6 changes: 3 additions & 3 deletions src/arc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,10 @@ fn markValue(vm: *cy.VM, v: cy.Value) void {
}
},
rt.ListIteratorT => {
markValue(vm, cy.Value.initPtr(obj.listIter.list));
markValue(vm, cy.Value.initNoCycPtr(obj.listIter.list));
},
rt.MapIteratorT => {
markValue(vm, cy.Value.initPtr(obj.mapIter.map));
markValue(vm, cy.Value.initNoCycPtr(obj.mapIter.map));
},
rt.ClosureT => {
const vals = obj.closure.getCapturedValuesPtr()[0..obj.closure.numCaptured];
Expand Down Expand Up @@ -474,7 +474,7 @@ pub fn checkGlobalRC(vm: *cy.VM) !void {
const typeName = vm.getTypeName(it.key_ptr.*.getTypeId());
const msg = try std.fmt.bufPrint(&buf, "Init alloc: {*}, type: {s}, rc: {} at pc: {}\nval={s}", .{
it.key_ptr.*, typeName, it.key_ptr.*.head.rc, trace.allocPc,
vm.valueToTempString(cy.Value.initPtr(it.key_ptr.*)),
vm.valueToTempString(cy.Value.initNoCycPtr(it.key_ptr.*)),
});
try cy.debug.printTraceAtPc(vm, trace.allocPc, msg);
}
Expand Down
22 changes: 11 additions & 11 deletions src/builtins/bindings.zig
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ pub fn listJoinString(vm: *cy.UserVM, args: [*]const Value, _: u8) linksection(c
std.mem.copy(u8, buf[dst..dst+slice.len], slice);
dst += slice.len;
}
return Value.initPtr(newObj);
return Value.initNoCycPtr(newObj);
} else {
// Empty string.
return Value.initStaticAstring(0, 0);
Expand Down Expand Up @@ -768,7 +768,7 @@ pub fn stringUpper(comptime T: cy.StringType) cy.ZHostFuncFn {
const new = vm.allocUnsetRawStringObject(str.len) catch fatal();
const newBuf = new.rawstring.getSlice();
_ = std.ascii.upperString(newBuf, str);
return Value.initPtr(new);
return Value.initNoCycPtr(new);
} else fatal();
}
};
Expand All @@ -794,7 +794,7 @@ pub fn stringLower(comptime T: cy.StringType) cy.ZHostFuncFn {
const new = vm.allocUnsetRawStringObject(str.len) catch fatal();
const newBuf = new.rawstring.getSlice();
_ = std.ascii.lowerString(newBuf, str);
return Value.initPtr(new);
return Value.initNoCycPtr(new);
} else fatal();
}
};
Expand Down Expand Up @@ -985,7 +985,7 @@ fn rawStringInsertByteCommon(vm: *cy.UserVM, str: []const u8, indexv: Value, val
std.mem.copy(u8, buf[0..uidx], str[0..uidx]);
buf[uidx] = byte;
std.mem.copy(u8, buf[uidx+1..], str[uidx..]);
return Value.initPtr(new);
return Value.initNoCycPtr(new);
}

fn rawStringInsertByte(vm: *cy.UserVM, args: [*]const Value, _: u8) linksection(cy.Section) Value {
Expand Down Expand Up @@ -1070,7 +1070,7 @@ fn stringRepeat(comptime T: cy.StringType) cy.ZHostFuncFn {
dst += @intCast(str.len);
}

return Value.initPtr(new);
return Value.initNoCycPtr(new);
} else {
if (un == 0) {
if (isRawStringObject(T)) {
Expand All @@ -1081,7 +1081,7 @@ fn stringRepeat(comptime T: cy.StringType) cy.ZHostFuncFn {
} else {
if (isHeapString(T)) {
vm.retainObject(obj);
return Value.initPtr(obj);
return Value.initNoCycPtr(obj);
} else {
return args[0];
}
Expand Down Expand Up @@ -1307,7 +1307,7 @@ fn stringReplace(comptime T: cy.StringType) cy.ZHostFuncFn {
} else {
if (T != .staticAstring) {
vm.retainObject(obj);
return Value.initPtr(obj);
return Value.initNoCycPtr(obj);
} else {
return args[0];
}
Expand All @@ -1318,7 +1318,7 @@ fn stringReplace(comptime T: cy.StringType) cy.ZHostFuncFn {
} else {
if (T != .staticUstring) {
vm.retainObject(obj);
return Value.initPtr(obj);
return Value.initNoCycPtr(obj);
} else {
return args[0];
}
Expand All @@ -1337,10 +1337,10 @@ fn stringReplace(comptime T: cy.StringType) cy.ZHostFuncFn {
const newBuf = new.rawstring.getSlice();
const idxes = @as([*]const u32, @ptrCast(idxBuf.buf.ptr))[0..numIdxes];
cy.replaceAtIdxes(newBuf, str, @intCast(needle.len), replacement, idxes);
return Value.initPtr(new);
return Value.initNoCycPtr(new);
} else {
vm.retainObject(obj);
return Value.initPtr(obj);
return Value.initNoCycPtr(obj);
}
} else fatal();
}
Expand Down Expand Up @@ -1537,7 +1537,7 @@ fn stringInsert(comptime T: cy.StringType) cy.ZHostFuncFn {
std.mem.copy(u8, buf[0..uidx], str[0..uidx]);
std.mem.copy(u8, buf[uidx..uidx+insert.len], insert);
std.mem.copy(u8, buf[uidx+insert.len..], str[uidx..]);
return Value.initPtr(new);
return Value.initNoCycPtr(new);
} else fatal();
}
};
Expand Down
1 change: 1 addition & 0 deletions src/builtins/builtins.cy
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ type MapIterator object:
@host func bool(val any) boolean
@host func char(val any) any
@host func copy(val any) any
@host func dump(val any) string
@host func errorReport() string
@host func isAlpha(val int) boolean
@host func isDigit(val int) boolean
Expand Down
23 changes: 17 additions & 6 deletions src/builtins/builtins.zig
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ const funcs = [_]NameFunc{
.{"bool", btBool, .standard},
.{"char", char, .standard},
.{"copy", copy, .standard},
.{"dump", dump, .standard},
.{"errorReport", errorReport, .standard},
.{"isAlpha", isAlpha, .standard},
.{"isDigit", isDigit, .standard},
Expand Down Expand Up @@ -270,7 +271,22 @@ pub fn runestr(vm: *cy.UserVM, args: [*]const Value, _: u8) linksection(cy.StdSe
}
}

pub fn dump(vm: *cy.UserVM, args: [*]const Value, _: u8) linksection(cy.StdSection) Value {
const alloc = vm.allocator();
const res = allocToCyon(vm, alloc, args[0]) catch cy.fatal();
defer alloc.free(res);
vm.internal().print(vm, cy.Str.initSlice(res));
return Value.None;
}

pub fn toCyon(vm: *cy.UserVM, args: [*]const Value, _: u8) linksection(cy.StdSection) Value {
const alloc = vm.allocator();
const res = allocToCyon(vm, alloc, args[0]) catch cy.fatal();
defer alloc.free(res);
return vm.allocStringInfer(res) catch fatal();
}

fn allocToCyon(vm: *cy.UserVM, alloc: std.mem.Allocator, root: Value) ![]const u8 {
const S = struct {
fn encodeMap(ctx: *cy.EncodeMapContext, val: cy.Value) anyerror!void {
const uservm = cy.ptrAlignCast(*cy.UserVM, ctx.user_ctx);
Expand Down Expand Up @@ -370,12 +386,7 @@ pub fn toCyon(vm: *cy.UserVM, args: [*]const Value, _: u8) linksection(cy.StdSec
}
}
};
const root = args[0];
const alloc = vm.allocator();

const cyon = cy.encodeCyon(alloc, vm, root, S.encodeRoot) catch fatal();
defer alloc.free(cyon);
return vm.allocStringInfer(cyon) catch fatal();
return try cy.encodeCyon(alloc, vm, root, S.encodeRoot);
}

pub fn parseCyber(vm: *cy.UserVM, args: [*]const Value, _: u8) linksection(cy.StdSection) Value {
Expand Down
2 changes: 1 addition & 1 deletion src/cyber.zig
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ pub const HostTypeResult = extern struct {
data: extern union {
object: extern struct {
typeId: *rt.TypeId,
semaTypeId: *types.TypeId,
semaTypeId: ?*types.TypeId,
getChildren: ?ObjectGetChildrenFn,
finalizer: ?ObjectFinalizerFn,
},
Expand Down
Loading

0 comments on commit 037607a

Please sign in to comment.