diff --git a/compiler/compiler.ts b/compiler/compiler.ts index 4963adb8..4ff3aca7 100644 --- a/compiler/compiler.ts +++ b/compiler/compiler.ts @@ -310,6 +310,7 @@ export class Compiler { static MIN_INT_16 = -32_768; static MAX_UINT_16 = 65_535; + static MAX_UINT_32 = 4_294_967_295; static readonly signature_size = 96 // 256; @@ -1482,7 +1483,7 @@ export class Compiler { // insert at top of scope dxb if new if (insert_new) { // pointer - if (base_type == BinaryCode.POINTER) Compiler.builder.addPointerByID(SCOPE.extract_var_scope, v_name, ACTION_TYPE.GET); // sync + if (base_type == BinaryCode.POINTER) Compiler.builder.addPointerByID(SCOPE.extract_var_scope, v_name, ACTION_TYPE.GET, undefined, undefined, NOT_EXISTING); // sync // variable/label else Compiler.builder.insertVariable(SCOPE.extract_var_scope, v_name, ACTION_TYPE.GET, undefined, base_type) } @@ -1681,11 +1682,14 @@ export class Compiler { SCOPE.uint8[SCOPE.b_index++] = i < 0 ? 0 : 1; // 0 for negative, 1 for positive (and 0) const bigint_buffer = Quantity.bigIntToBuffer(BigInt(i < 0 ? -i : i)); - Compiler.builder.handleRequiredBufferSize(SCOPE.b_index+(Uint16Array.BYTES_PER_ELEMENT*2)+bigint_buffer.byteLength, SCOPE); + Compiler.builder.handleRequiredBufferSize(SCOPE.b_index+Uint32Array.BYTES_PER_ELEMENT+bigint_buffer.byteLength, SCOPE); + + // invalid bigint size + if (bigint_buffer.byteLength > Compiler.MAX_UINT_32) throw new CompilerError("Integer too big"); // buffer size - SCOPE.data_view.setUint16(SCOPE.b_index, bigint_buffer.byteLength, true) - SCOPE.b_index+=Uint16Array.BYTES_PER_ELEMENT; + SCOPE.data_view.setUint32(SCOPE.b_index, bigint_buffer.byteLength, true) + SCOPE.b_index+=Uint32Array.BYTES_PER_ELEMENT; // bigint SCOPE.uint8.set(bigint_buffer, SCOPE.b_index); @@ -2175,7 +2179,7 @@ export class Compiler { } }, - addPointerByID: (SCOPE:compiler_scope|extract_var_scope, id:string|Uint8Array, action_type:ACTION_TYPE = ACTION_TYPE.GET, action_specifier?:BinaryCode, init_brackets = false, value:any = NOT_EXISTING):Promise|void => { + addPointerByID: (SCOPE:compiler_scope|extract_var_scope, id:string|Uint8Array, action_type:ACTION_TYPE = ACTION_TYPE.GET, action_specifier?:BinaryCode, init_brackets = false, value?:any):Promise|void => { // insert preemptive pointer const id_buffer = typeof id == "string" ? hex2buffer(id, Pointer.MAX_POINTER_ID_SIZE, true) : id; @@ -2205,7 +2209,7 @@ export class Compiler { }, // just $aabbcc = - addPointerNormal: (SCOPE:compiler_scope|extract_var_scope, id:string|Uint8Array, action_type:ACTION_TYPE = ACTION_TYPE.GET, action_specifier?:BinaryCode, init_brackets = false, value:any = NOT_EXISTING, transform_scope?: Scope):Promise|void => { + addPointerNormal: (SCOPE:compiler_scope|extract_var_scope, id:string|Uint8Array, action_type:ACTION_TYPE = ACTION_TYPE.GET, action_specifier?:BinaryCode, init_brackets = false, value?:any, transform_scope?: Scope):Promise|void => { Compiler.builder.handleRequiredBufferSize(SCOPE.b_index+1, SCOPE); Compiler.builder.valueIndex(SCOPE); @@ -2259,7 +2263,7 @@ export class Compiler { Compiler.builder.addPointerNormal(SCOPE, id, ACTION_TYPE.INIT, undefined, true, ptr.val, (ptr.force_local_transform && ptr.transform_scope) ? ptr.transform_scope : undefined); // sync Compiler.builder.handleRequiredBufferSize(SCOPE.b_index+1, SCOPE); SCOPE.uint8[SCOPE.b_index++] = BinaryCode.CLOSE_AND_STORE; - Compiler.builder.addPointerNormal(SCOPE, id, ACTION_TYPE.GET); // sync + Compiler.builder.addPointerNormal(SCOPE, id, ACTION_TYPE.GET, undefined, undefined, ptr.val); // sync Compiler.builder.handleRequiredBufferSize(SCOPE.b_index+1, SCOPE); SCOPE.uint8[SCOPE.b_index++] = BinaryCode.SUBSCOPE_END; @@ -2289,7 +2293,7 @@ export class Compiler { deferSizeIndex = SCOPE.b_index; SCOPE.b_index += Uint32Array.BYTES_PER_ELEMENT; } - Compiler.builder.addPointerNormal(SCOPE, id, ACTION_TYPE.GET); // sync + Compiler.builder.addPointerNormal(SCOPE, id, ACTION_TYPE.GET, undefined, undefined, NOT_EXISTING); // sync if (defer) SCOPE.data_view.setUint32(deferSizeIndex, SCOPE.b_index-deferSizeIndex-Uint32Array.BYTES_PER_ELEMENT, true); } }, @@ -2315,7 +2319,7 @@ export class Compiler { Compiler.builder.insertExtractedVariable(SCOPE, BinaryCode.POINTER, buffer2hex(p.id_buffer)); } // add normally - else return Compiler.builder.addPointerByID (SCOPE, p.id_buffer, action_type, action_specifier) + else return Compiler.builder.addPointerByID (SCOPE, p.id_buffer, action_type, action_specifier, undefined, NOT_EXISTING) }, // add @@ -4592,7 +4596,7 @@ export class Compiler { Compiler.builder.insertExtractedVariable(SCOPE, BinaryCode.POINTER, id) } // insert normally - else await Compiler.builder.addPointerByID(SCOPE, id, action_type, action_specifier, init_brackets) + else await Compiler.builder.addPointerByID(SCOPE, id, action_type, action_specifier, init_brackets, NOT_EXISTING) isEffectiveValue = true; } diff --git a/runtime/pointers.ts b/runtime/pointers.ts index b7586475..a90d6151 100644 --- a/runtime/pointers.ts +++ b/runtime/pointers.ts @@ -28,6 +28,7 @@ import { IterableWeakSet } from "../utils/iterable-weak-set.ts"; import { IterableWeakMap } from "../utils/iterable-weak-map.ts"; import { LazyPointer } from "./lazy-pointer.ts"; import { ReactiveArrayMethods } from "../types/reactive-methods/array.ts"; +import { Assertion } from "../types/assertion.ts"; export type observe_handler = (value:V extends RefLike ? T : V, key?:K, type?:Ref.UPDATE_TYPE, transform?:boolean, is_child_update?:boolean, previous?: any, atomic_id?:symbol)=>void|boolean export type observe_options = {types?:Ref.UPDATE_TYPE[], ignore_transforms?:boolean, recursive?:boolean} @@ -1998,6 +1999,20 @@ export class Pointer extends Ref { else return val[propName] } + #typeAssertions?: Conjunction + + /** + * Add an assertion that is validated when the pointer value is changed + * Only works for primitive pointers + * @param assertion + */ + public assert(assertion:(val:any)=>boolean|string|undefined|null) { + if (!this.is_js_primitive) throw new PointerError("Assertions are not yet supported for non-primitive pointer") + if (!this.#typeAssertions) this.#typeAssertions = new Conjunction(); + this.#typeAssertions.add(Assertion.get(undefined, assertion, false)); + return this; + } + /** * Changes the id of the pointer to point to the new origin (and also changes the .origin) * @param new_owner @@ -2504,7 +2519,19 @@ export class Pointer extends Ref { throw new ValueError("Invalid value type for transform pointer "+this.idString()+": " + newType + (error ? " - " + error : "")); } } - else if ((v!==null&&v!==undefined) && !Type.matchesType(newType, this.type)) throw new ValueError("Invalid value type for pointer "+this.idString()+": " + newType + " - must be " + this.type); + else if ((v!==null&&v!==undefined)) { + if ( + // validate pointer type + !Type.matchesType(newType, this.type, val, true) || + // validate custom type assertions + ( + this.#typeAssertions && + !Type.matchesType(newType, this.#typeAssertions, val, true) + ) + ) { + throw new ValueError("Invalid value type for pointer "+this.idString()+": " + newType + " - must be " + this.type); + } + } let updatePromise: Promise|void; diff --git a/runtime/runtime.ts b/runtime/runtime.ts index b7d8d4c1..33430fa3 100644 --- a/runtime/runtime.ts +++ b/runtime/runtime.ts @@ -6694,9 +6694,13 @@ export class Runtime { const sign = SCOPE.buffer_views.uint8[SCOPE.current_index++] == 0 ? -1n : 1n; // 0 for negative, 1 for positive (and 0) // buffer size - const size = SCOPE.buffer_views.data_view.getUint16(SCOPE.current_index, true) - SCOPE.current_index+=Uint16Array.BYTES_PER_ELEMENT; + const size = SCOPE.buffer_views.data_view.getUint32(SCOPE.current_index, true) + SCOPE.current_index+=Uint32Array.BYTES_PER_ELEMENT; + /** wait for buffer */ + if (SCOPE.current_index+size > SCOPE.buffer_views.uint8.byteLength) return Runtime.runtime_actions.waitForBuffer(SCOPE); + /********************/ + // bigint from buffer const bigint_buffer = SCOPE.buffer_views.uint8.subarray(SCOPE.current_index, SCOPE.current_index+=size); const bigint = Quantity.bufferToBigInt(bigint_buffer) * sign; diff --git a/wasm/adapter/pkg/datex_wasm_bg.wasm b/wasm/adapter/pkg/datex_wasm_bg.wasm index b3e3b221..1cb3ad2a 100644 Binary files a/wasm/adapter/pkg/datex_wasm_bg.wasm and b/wasm/adapter/pkg/datex_wasm_bg.wasm differ