Skip to content

Commit

Permalink
Use @host instead of hostfunc. Symbols use . instead of #.
Browse files Browse the repository at this point in the history
  • Loading branch information
fubark committed Sep 23, 2023
1 parent 3e2530f commit fe8ae79
Show file tree
Hide file tree
Showing 39 changed files with 422 additions and 389 deletions.
8 changes: 4 additions & 4 deletions docs/hugo/content/docs/toc/data-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -489,14 +489,14 @@ print int(fruit) -- '3'
When the type of the value is known to be an enum, it can be assigned using a symbol literal.
```cy
var fruit = Fruit.kiwi
fruit = #orange
fruit = .orange
print(fruit == Fruit.orange) -- 'true'
```

## Symbols.
Symbol literals begin with `#`, followed by an identifier. They have their own global unique id.
Symbol literals begin with `.`, followed by an identifier. They have their own global unique id.
```cy
var currency = #usd
print(currency == #usd) -- 'true'
var currency = .usd
print(currency == .usd) -- 'true'
print int(currency) -- '123' or some arbitrary id.
```
6 changes: 6 additions & 0 deletions docs/hugo/content/docs/toc/metaprogramming.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ func id(self) int
```

## Annotations.
Annotations are used to attach modifiers to declarative statements. The `@host` annotation is used for [embedding]({{<relref "/docs/toc/embedding">}}) to bind a host function to a Cyber function:
```cy
@host func compute() float
```

Custom annotations.
> _Planned Feature_
## Runtime eval.
Expand Down
3 changes: 1 addition & 2 deletions 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 `34` keywords in Cyber. This list categorizes them and shows you when you might need them.
There are currently `33` 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,7 +169,6 @@ There are currently `34` 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
8 changes: 8 additions & 0 deletions src/api.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ pub const UserVM = struct {
vm.compiler.apiError = vm.alloc.dupe(u8, str) catch cy.fatal();
}

pub fn getPrint(self: *UserVM) cy.PrintFn {
return self.internal().print;
}

pub fn setPrint(self: *UserVM, print: cy.PrintFn) void {
self.internal().print = print;
}
Expand All @@ -53,6 +57,10 @@ pub const UserVM = struct {
self.constInternal().compiler.moduleLoader = loader;
}

pub fn getModuleResolver(self: *const UserVM) cy.ModuleResolverFn {
return self.constInternal().compiler.moduleResolver;
}

pub fn setModuleResolver(self: *const UserVM, resolver: cy.ModuleResolverFn) void {
self.constInternal().compiler.moduleResolver = resolver;
}
Expand Down
44 changes: 22 additions & 22 deletions src/builtins/builtins.cy
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
hostfunc arrayFill(val any, n int) List
hostfunc asciiCode(val any) any
hostfunc bool(val any) boolean
hostfunc char(val any) any
hostfunc copy(val any) any
hostfunc errorReport() string
hostfunc isAlpha(val int) boolean
hostfunc isDigit(val int) boolean
hostfunc must(val any) any
hostfunc opaque(val any) pointer
hostfunc panic(err any) none
hostfunc parseCyber(src any) Map
hostfunc parseCyon(src any) any
hostfunc performGC() Map
hostfunc print(str any) none
hostfunc prints(str any) none
hostfunc runestr(val int) string
hostfunc toCyon(val any) string
hostfunc typeid(val any) int
hostfunc valtag(val any) symbol
hostfunc typesym(val any) symbol
hostfunc typeof(val any) metatype
@host func arrayFill(val any, n int) List
@host func asciiCode(val any) any
@host func bool(val any) boolean
@host func char(val any) any
@host func copy(val any) any
@host func errorReport() string
@host func isAlpha(val int) boolean
@host func isDigit(val int) boolean
@host func must(val any) any
@host func opaque(val any) pointer
@host func panic(err any) none
@host func parseCyber(src any) Map
@host func parseCyon(src any) any
@host func performGC() Map
@host func print(str any) none
@host func prints(str any) none
@host func runestr(val int) string
@host func toCyon(val any) string
@host func typeid(val any) int
@host func valtag(val any) symbol
@host func typesym(val any) symbol
@host func typeof(val any) metatype
6 changes: 0 additions & 6 deletions src/builtins/builtins.zig
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,6 @@ fn parseCyberGenResult(vm: *cy.UserVM, parser: *const cy.Parser, res: cy.ParseRe
name = res.getFirstNodeString(header.head.funcHeader.name);
pos = res.tokens[node.start_token].pos();
},
.hostFunc => {
const node = nodes[decl.inner.hostFunc];
const header = nodes[node.head.func.header];
name = res.getFirstNodeString(header.head.funcHeader.name);
pos = res.tokens[node.start_token].pos();
},
.import => {
const node = nodes[decl.inner.import];
name = res.getFirstNodeString(node.head.left_right.left);
Expand Down
72 changes: 36 additions & 36 deletions src/builtins/math.cy
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
hostfunc abs(a float) float
hostfunc acos(a float) float
hostfunc acosh(a float) float
hostfunc asin(a float) float
hostfunc asinh(a float) float
hostfunc atan(a float) float
hostfunc atan2(a float, b float) float
hostfunc atanh(a float) float
hostfunc cbrt(a float) float
hostfunc ceil(a float) float
hostfunc clz32(a float) float
hostfunc cos(a float) float
hostfunc cosh(a float) float
hostfunc exp(a float) float
hostfunc expm1(a float) float
hostfunc floor(a float) float
hostfunc hypot(a float, b float) float
hostfunc isNaN(a float) boolean
hostfunc ln(a float) float
hostfunc log(a float, b float) float
hostfunc log10(a float) float
hostfunc log1p(a float) float
hostfunc log2(a float) float
hostfunc max(a float, b float) float
hostfunc min(a float, b float) float
hostfunc mul32(a float, b float) float
hostfunc pow(a float, b float) float
hostfunc random() float
hostfunc round(a float) float
hostfunc sign(a float) float
hostfunc sin(a float) float
hostfunc sinh(a float) float
hostfunc sqrt(a float) float
hostfunc tan(a float) float
hostfunc tanh(a float) float
hostfunc trunc(a float) float
@host func abs(a float) float
@host func acos(a float) float
@host func acosh(a float) float
@host func asin(a float) float
@host func asinh(a float) float
@host func atan(a float) float
@host func atan2(a float, b float) float
@host func atanh(a float) float
@host func cbrt(a float) float
@host func ceil(a float) float
@host func clz32(a float) float
@host func cos(a float) float
@host func cosh(a float) float
@host func exp(a float) float
@host func expm1(a float) float
@host func floor(a float) float
@host func hypot(a float, b float) float
@host func isNaN(a float) boolean
@host func ln(a float) float
@host func log(a float, b float) float
@host func log10(a float) float
@host func log1p(a float) float
@host func log2(a float) float
@host func max(a float, b float) float
@host func min(a float, b float) float
@host func mul32(a float, b float) float
@host func pow(a float, b float) float
@host func random() float
@host func round(a float) float
@host func sign(a float) float
@host func sin(a float) float
@host func sinh(a float) float
@host func sqrt(a float) float
@host func tan(a float) float
@host func tanh(a float) float
@host func trunc(a float) float
14 changes: 14 additions & 0 deletions src/chunk.zig
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,20 @@ pub const Chunk = struct {
}
}

pub fn setNodeFuncDecl(self: *Chunk, nodeId: cy.NodeId, declId: sema.FuncDeclId) void {
self.nodes[nodeId].head.func.semaDeclId = declId;
}

pub fn getNodeFuncDecl(self: *const Chunk, nodeId: cy.NodeId) sema.FuncDecl {
const node = self.nodes[nodeId];
return self.semaFuncDecls.items[node.head.func.semaDeclId];
}

pub fn getNodeFuncDeclPtr(self: *Chunk, nodeId: cy.NodeId) *sema.FuncDecl {
const node = self.nodes[nodeId];
return &self.semaFuncDecls.items[node.head.func.semaDeclId];
}

pub fn genEnsureRtFuncSym(self: *Chunk, funcSymId: sema.FuncSymId) !u32 {
const rFuncSym = self.compiler.sema.getFuncSym(funcSymId);
const rSym = self.compiler.sema.getSymbol(rFuncSym.getSymbolId());
Expand Down
11 changes: 5 additions & 6 deletions src/codegen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1367,8 +1367,8 @@ fn statement(c: *Chunk, nodeId: cy.NodeId) !void {
try c.buf.pushOp(.ret1);
}
},
.atStmt => {
try atStmt(c, nodeId);
.comptimeStmt => {
try comptimeStmt(c, nodeId);
},
else => {
return c.reportErrorAt("Unsupported statement: {}", &.{v(node.node_t)}, nodeId);
Expand Down Expand Up @@ -1670,10 +1670,9 @@ fn ifStmt(c: *cy.Chunk, nodeId: cy.NodeId) !void {
}
}

fn atStmt(c: *Chunk, nodeId: cy.NodeId) !void {
fn comptimeStmt(c: *Chunk, nodeId: cy.NodeId) !void {
const node = c.nodes[nodeId];
const atExpr = c.nodes[node.head.atStmt.expr];
const expr = c.nodes[atExpr.head.atExpr.child];
const expr = c.nodes[node.head.comptimeStmt.expr];
if (expr.node_t == .callExpr) {
const callee = c.nodes[expr.head.callExpr.callee];
const name = c.getNodeTokenString(callee);
Expand All @@ -1699,7 +1698,7 @@ fn atStmt(c: *Chunk, nodeId: cy.NodeId) !void {
return c.reportErrorAt("Unsupported annotation: {}", &.{v(name)}, nodeId);
}
} else {
return c.reportErrorAt("Unsupported atExpr: {}", &.{v(expr.node_t)}, nodeId);
return c.reportErrorAt("Unsupported expr: {}", &.{v(expr.node_t)}, nodeId);
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,7 @@ fn getStackFrame(vm: *cy.VM, sym: cy.DebugSym) StackFrame {
};
} else {
const chunk = vm.compiler.chunks.items[sym.file];
const frameNode = chunk.nodes[sym.frameLoc];
const func = chunk.semaFuncDecls.items[frameNode.head.func.semaDeclId];
const func = chunk.getNodeFuncDecl(sym.frameLoc);
const name = func.getName(&chunk);

const node = chunk.nodes[sym.loc];
Expand Down Expand Up @@ -441,8 +440,7 @@ pub fn pcToEndLocalsPc(vm: *const cy.VM, pc: usize) u32 {
pub fn debugSymToEndLocalsPc(vm: *const cy.VM, sym: cy.DebugSym) u32 {
if (sym.frameLoc != cy.NullId) {
const chunk = vm.compiler.chunks.items[sym.file];
const node = chunk.nodes[sym.frameLoc];
return chunk.semaFuncDecls.items[node.head.func.semaDeclId].genEndLocalsPc;
return chunk.getNodeFuncDecl(sym.frameLoc).genEndLocalsPc;
} else {
// Located in the main block.
const chunk = vm.compiler.chunks.items[0];
Expand Down
46 changes: 35 additions & 11 deletions src/include/cyber.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,37 +65,44 @@ typedef struct CsStr {
size_t len;
} CsStr;

typedef CsValue (*CsHostFuncFn)(CsVM* vm, CsValue* args, uint8_t nargs);

// Top level.
CsStr csGetFullVersion();
CsStr csGetVersion();
CsStr csGetBuild();
CsStr csGetCommit();

// @host func is binded to this function pointer signature.
typedef CsValue (*CsHostFuncFn)(CsVM* vm, CsValue* args, uint8_t nargs);

// Given the current module's resolved URI and the "to be" imported module specifier,
// write the resolved specifier in `outUri` and return true, otherwise return false.
// Most embedders do not need a resolver and can rely on the default resolver which
// simply returns `spec` without any adjustments.
typedef bool (*CsModuleResolverFn)(CsVM* vm, uint32_t chunkId, CsStr curUri, CsStr spec, CsStr* outUri);

// Callback invoked after all symbols in module's src are loaded.
// This would be a convenient time to inject symbols not declared in the module's src.
typedef void (*CsPostLoadModuleFn)(CsVM* vm, uint32_t modId);

// Callback invoked just before the module is destroyed.
// When you have explicity injected symbols into a module from `CsPostLoadModuleFn`,
// this can be a convenient time to do cleanup logic (eg. release objects).
typedef void (*CsModuleDestroyFn)(CsVM* vm, uint32_t modId);

// Info about a `hostfunc`.
// Info about a @host func.
typedef struct CsHostFuncInfo {
// The module it belongs to.
uint32_t modId;
// The name of the func.
CsStr name;
// The function's signature.
uint32_t funcSigId;
// A counter that tracks it's current position among all `hostfunc` in the module.
// This is useful if you want to bind an array of function pointers to `hostfunc`s.
// A counter that tracks it's current position among all @host funcs in the module.
// This is useful if you want to bind an array of function pointers to @host funcs.
uint32_t idx;
} CsHostFuncInfo;

// Given info about a function, return it's function pointer or null.
// Given info about a @host func, return it's function pointer or null.
typedef CsHostFuncFn (*CsHostFuncLoaderFn)(CsVM* vm, CsHostFuncInfo funcInfo);

// Module loader config.
Expand All @@ -104,35 +111,52 @@ typedef struct CsModuleLoaderResult {
CsStr src;
// Whether the provided `src` is from static memory or heap memory.
bool srcIsStatic;
// Callback to load `hostfunc`s or null.
// Pointer to callback or null.
CsHostFuncLoaderFn funcLoader;
// Callback after all symbols in module are loaded or null.
// Pointer to callback or null.
CsPostLoadModuleFn postLoad;
// Callback just before the module is destroyed or null.
// Pointer to callback or null.
CsModuleDestroyFn destroy;
} CsModuleLoaderResult;

// Given the resolved import specifier of the module, write the loader details in `out`
// and return true, otherwise return false.
typedef bool (*CsModuleLoaderFn)(CsVM* vm, CsStr resolvedSpec, CsModuleLoaderResult* out);

// Override the behavior of `print` from the `builtins` module.
// The default behavior is a no-op.
typedef void (*CsPrintFn)(CsVM* vm, CsStr str);

// Stats of a GC run.
typedef struct CsGCResult {
// Objects freed that were part of a reference cycle.
uint32_t numCycFreed;
// Total number of objects freed.
uint32_t numObjFreed;
} CsGCResult;

//
// [ VM ]
//
CsVM* csCreate();
void csDestroy(CsVM* vm);
CsModuleResolverFn csGetModuleResolver(CsVM* vm);
void csSetModuleResolver(CsVM* vm, CsModuleResolverFn resolver);
CsModuleLoaderFn csGetModuleLoader(CsVM* vm);
void csSetModuleLoader(CsVM* vm, CsModuleLoaderFn loader);
CsPrintFn csGetPrint(CsVM* vm);
void csSetPrint(CsVM* vm, CsPrintFn print);
CsResultCode csEval(CsVM* vm, CsStr src, CsValue* outVal);
CsResultCode csValidate(CsVM* vm, CsStr src);
CsStr csGetLastErrorReport(CsVM* vm);
void csRelease(CsVM* vm, CsValue val);
void csRetain(CsVM* vm, CsValue val);
void* csGetUserData(CsVM* vm);
void csSetUserData(CsVM* vm, void* userData);

// Memory.
void csRelease(CsVM* vm, CsValue val);
void csRetain(CsVM* vm, CsValue val);
CsGCResult csPerformGC(CsVM* vm);

// Modules.
void csSetModuleFunc(CsVM* vm, CsModuleId modId, CsStr name, uint32_t numParams, CsHostFuncFn func);
void csSetModuleVar(CsVM* vm, CsModuleId modId, CsStr name, CsValue val);
Expand Down
Loading

0 comments on commit fe8ae79

Please sign in to comment.