Skip to content

Commit

Permalink
symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
benStre committed Dec 4, 2023
1 parent b6dfb87 commit 47ea334
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 14 deletions.
13 changes: 9 additions & 4 deletions docs/manual/11 Types.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ Datex.Type.std.Any === any
Most builtin JavaScript types, like Map, Set or Array have equivalent types in the DATEX std library.
There are only a few types that are implemented specifically to match JS types:

### js:TransferableFunction
### js:Function

The `js:TransferableFunction` (`Datex.Type.js.TransferableFunction`) is a special wrapper
The `js:Function` (`Datex.Type.js.Function`) is a special wrapper
around a JavaScript function that can be transferred between endpoints.

In contrast to a normal function (`std:Function`) that can also be mapped to a JavaScript function,
a `js:TransferableFunction` is always executed on the endpoint where it is called, not on the origin endpoint.
a `js:Function` is always executed on the endpoint where it is called, not on the origin endpoint.

A transferable functions can be created from a normal JS function. Dependencies from the parent scope can be declared with a `use()` statement:

Expand All @@ -47,7 +47,7 @@ import { JSTransferableFunction } from "datex-core-legacy/types/js-function.ts";

const data = $$([1,2,3]);

// create a js:TransferableFunction
// create a js:Function
const transferableFn = JSTransferableFunction.create(() => {
use (data);

Expand All @@ -73,6 +73,11 @@ Examples for `js:Object`s:

The property values of a `js:Object` are never automatically bound to pointers when the object is bound to a pointer.


### js:Symbol

DATEX has no native symbol type. JavaScript symbols are mapped to `js:Symbol` values.

## Structs

The `struct` helper function allows you to define DATEX types with a
Expand Down
20 changes: 14 additions & 6 deletions runtime/pointers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -777,10 +777,14 @@ export type JSValueWith$<T> = ObjectRef<T>;

// convert from any JS/DATEX value to minimal representation with reference
export type MinimalJSRefGeneralTypes<T, _C = CollapsedValue<T>> =
JSPrimitiveToDatexRef<_C> extends never ? ObjectRef<_C> : JSPrimitiveToDatexRef<_C>
_C extends symbol ? symbol : (
JSPrimitiveToDatexRef<_C> extends never ? ObjectRef<_C> : JSPrimitiveToDatexRef<_C>
)
// same as MinimalJSRefGeneralTypes, but returns Pointer<2|5> instead of IntegerRef
export type MinimalJSRef<T, _C = CollapsedValue<T>> =
JSPrimitiveToDatexRef<_C> extends never ? ObjectRef<_C> : (Pointer<_C> & (_C extends boolean ? unknown : _C))
export type MinimalJSRef<T, _C = CollapsedValue<T>> =
_C extends symbol ? symbol : (
JSPrimitiveToDatexRef<_C> extends never ? ObjectRef<_C> : (Pointer<_C> & (_C extends boolean ? unknown : _C))
)

// return Pointer<T>&T for primitives (excluding boolean) and Pointer<T> otherwise
export type PointerWithPrimitive<T> = T extends number|string|boolean|bigint ? Pointer<T>&T : Pointer<T>
Expand Down Expand Up @@ -1839,7 +1843,7 @@ export class Pointer<T = any> extends Ref<T> {

#updateIsJSPrimitive(val:any = this.val) {
const type = this.#type ?? Type.ofValue(val);
this.#is_js_primitive = !(Object(val) === val && !type.is_js_pseudo_primitive && !(type == Type.js.NativeObject && globalThis.Element && val instanceof globalThis.Element))
this.#is_js_primitive = (typeof val !== "symbol") && !(Object(val) === val && !type.is_js_pseudo_primitive && !(type == Type.js.NativeObject && globalThis.Element && val instanceof globalThis.Element))
}

/**
Expand Down Expand Up @@ -2232,6 +2236,10 @@ export class Pointer<T = any> extends Ref<T> {

let val = Ref.collapseValue(v,true,true);

if (typeof val == "symbol" && Symbol.keyFor(val) !== undefined) {
throw new Error("Global and well-known symbols (e.g. Symbol.for('name') or Symbol.iterator) are no yet supported as pointer values")
}

// get transform wrapper
if (is_transform) val = this.getInitialTransformValue(val)

Expand Down Expand Up @@ -2272,7 +2280,7 @@ export class Pointer<T = any> extends Ref<T> {
// create proxy
const value = this.addObjProxy((val instanceof UnresolvedValue) ? val[DX_VALUE] : val);
// add $, $$
this.add$Properties(value);
if (typeof value !== "symbol") this.add$Properties(value);

// // add reference to this DatexPointer to the value
// if (!this.is_anonymous) {
Expand Down Expand Up @@ -3022,7 +3030,7 @@ export class Pointer<T = any> extends Ref<T> {
const res = JSInterface.createProxy(obj, this, this.type);
if (res != INVALID && res != NOT_EXISTING) return res; // proxy created successfully

if (obj instanceof Stream || obj instanceof DatexFunction || obj instanceof JSTransferableFunction) { // no proxy needed?!
if (typeof obj == "symbol" || obj instanceof Stream || obj instanceof DatexFunction || obj instanceof JSTransferableFunction) { // no proxy needed?!
return obj;
}

Expand Down
14 changes: 12 additions & 2 deletions runtime/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2094,8 +2094,8 @@ export class Runtime {

let new_value:any = UNKNOWN_TYPE;

// only handle std namespace / js:Object
if (type.namespace == "std" || type == Type.js.NativeObject) {
// only handle std namespace / js:Object / js:Symbol
if (type.namespace == "std" || type == Type.js.NativeObject || type == Type.js.Symbol) {
if (old_value instanceof Pointer) old_value = old_value.val;

// handle default casts
Expand Down Expand Up @@ -2175,6 +2175,12 @@ export class Runtime {
else new_value = INVALID;
break;
}
case Type.js.Symbol: {
if (old_value === VOID) new_value = Symbol();
else if (typeof old_value == "string") new_value = Symbol(old_value);
else new_value = INVALID;
break;
}
case Type.std.Tuple: {
if (old_value === VOID) new_value = new Tuple().seal();
else if (old_value instanceof Array){
Expand Down Expand Up @@ -2482,6 +2488,10 @@ export class Runtime {

// primitives
if (typeof value == "string" || typeof value == "boolean" || typeof value == "number" || typeof value == "bigint") return value;

// symbol
if (typeof value == "symbol") return value.toString().slice(7,-1) || undefined

// directly return, cannot be overwritten
if (value === VOID || value === null || value instanceof Endpoint || value instanceof Type) return value;
if (value instanceof Scope) return value;
Expand Down
6 changes: 4 additions & 2 deletions types/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ export class Type<T = any> extends ExtensibleFunction {
if (typeof value == "bigint") return <Type<T>>Type.std.integer;
if (typeof value == "number") return <Type<T>>Type.std.decimal;
if (typeof value == "boolean") return <Type<T>>Type.std.boolean;
if (typeof value == "symbol") return Type.std.void; // TODO?, ignores symbols
if (typeof value == "symbol") return Type.js.Symbol;

if (value instanceof ArrayBuffer || value instanceof TypedArray) return <Type<T>>Type.std.buffer;
if (value instanceof Tuple) return <Type<T>>Type.std.Tuple;
Expand Down Expand Up @@ -872,6 +872,7 @@ export class Type<T = any> extends ExtensibleFunction {
if (_forClass == BigInt || BigInt.isPrototypeOf(_forClass)) return <Type<T>>Type.std.integer;
if (_forClass == Number || Number.isPrototypeOf(_forClass)) return <Type<T>>Type.std.decimal;
if (_forClass == globalThis.Boolean || globalThis.Boolean.isPrototypeOf(_forClass)) return <Type<T>>Type.std.boolean;
if (_forClass == Symbol || Symbol.isPrototypeOf(_forClass)) return <Type<T>>Type.js.Symbol;

if (_forClass == ArrayBuffer || TypedArray.isPrototypeOf(_forClass)) return <Type<T>>Type.std.buffer;
if (_forClass == Tuple || Tuple.isPrototypeOf(_forClass)) return <Type<T>>Type.std.Tuple;
Expand Down Expand Up @@ -930,7 +931,8 @@ export class Type<T = any> extends ExtensibleFunction {
*/
static js = {
NativeObject: Type.get<object>("js:Object"), // special object type for non-plain objects (objects with prototype) - no automatic children pointer initialization
TransferableFunction: Type.get<JSTransferableFunction>("js:Function")
TransferableFunction: Type.get<JSTransferableFunction>("js:Function"),
Symbol: Type.get<symbol>("js:Symbol")
}

/**
Expand Down

0 comments on commit 47ea334

Please sign in to comment.