diff --git a/scripts/adlc b/scripts/adlc index c35ae98..bee46c6 100755 --- a/scripts/adlc +++ b/scripts/adlc @@ -5,7 +5,7 @@ set -e -adlversion=0.13.2 +adlversion=0.13.8 if [ "$(uname)" == "Darwin" ]; then platform=osx diff --git a/src/ADL/Sys/Adlast.hs b/src/ADL/Sys/Adlast.hs index 3203416..a5cb4de 100644 --- a/src/ADL/Sys/Adlast.hs +++ b/src/ADL/Sys/Adlast.hs @@ -17,6 +17,16 @@ module ADL.Sys.Adlast( TypeExpr(..), TypeRef(..), Union(..), + mkDecl, + mkField, + mkModule, + mkNewType, + mkScopedDecl, + mkScopedName, + mkStruct, + mkTypeDef, + mkTypeExpr, + mkUnion, ) where import ADL.Core diff --git a/src/ADL/Sys/Types.hs b/src/ADL/Sys/Types.hs index 41b529a..a178581 100644 --- a/src/ADL/Sys/Types.hs +++ b/src/ADL/Sys/Types.hs @@ -6,7 +6,9 @@ module ADL.Sys.Types( MapEntry(..), Maybe, Pair, + Result, Set, + mkMapEntry, ) where import ADL.Core @@ -61,4 +63,7 @@ type Maybe = Prelude.Maybe type Pair a b = (a,b) +type Result t e = Prelude.Either e t + + type Set v = Set.Set v \ No newline at end of file diff --git a/test/adl-gen/runtime/adl.ts b/test/adl-gen/runtime/adl.ts index 434a6fd..2566f71 100644 --- a/test/adl-gen/runtime/adl.ts +++ b/test/adl-gen/runtime/adl.ts @@ -13,7 +13,7 @@ export interface DeclResolver { }; export function declResolver(...astMaps : ({[key:string] : AST.ScopedDecl})[]) { - const astMap = {}; + const astMap : {[key:string] : AST.ScopedDecl} = {}; for (let map of astMaps) { for (let scopedName in map) { astMap[scopedName] = map[scopedName]; diff --git a/test/adl-gen/runtime/json.ts b/test/adl-gen/runtime/json.ts index 9fa5fd3..5b07895 100644 --- a/test/adl-gen/runtime/json.ts +++ b/test/adl-gen/runtime/json.ts @@ -3,8 +3,25 @@ import * as AST from './sys/adlast'; import * as b64 from 'base64-js'; import {isVoid, isEnum, scopedNamesEqual} from './utils'; -/** A type alias for json serialised values */ -type Json = {}|null; +/** A type for json serialised values */ + +export type Json = {} | null; +export type JsonObject = { [member: string]: Json }; +export type JsonArray = Json[]; + +function asJsonObject(jv: Json): JsonObject | undefined { + if (jv instanceof Object && !(jv instanceof Array)) { + return jv as JsonObject; + } + return undefined; +} + +function asJsonArray(jv: Json): JsonArray | undefined{ + if(jv instanceof Array) { + return jv as JsonArray; + } + return undefined; +} /** A type alias for values of an Unknown type */ type Unknown = {}|null; @@ -57,7 +74,7 @@ export interface JsonParseException { // Map a JsonException to an Error value export function mapJsonException(exception:{}): {} { - if (exception && exception['kind'] == "JsonParseException") { + if (exception && (exception as {kind:string})['kind'] == "JsonParseException") { const jserr: JsonParseException = exception as JsonParseException; return new Error(jserr.getMessage()); } else { @@ -161,14 +178,14 @@ function primitiveJsonBinding(dresolver : DeclResolver, ptype : string, params : function identityJsonBinding(expected : string, predicate : (json : Json) => boolean) : JsonBinding0{ function toJson(v : T) : Json { - return v; + return (v as Unknown as Json); } function fromJson(json : Json) : T { if( !predicate(json)) { throw jsonParseException("expected " + expected); } - return json as T; + return json as Unknown as T; } return {toJson, fromJson}; @@ -197,11 +214,12 @@ function vectorJsonBinding(dresolver : DeclResolver, texpr : AST.TypeExpr, bound } function fromJson(json : Json) : Unknown[] { - if (!(json instanceof Array)) { + const jarr = asJsonArray(json); + if (jarr == undefined) { throw jsonParseException('expected an array'); } let result : Unknown[] = []; - json.forEach( (eljson,i) => { + jarr.forEach( (eljson:Json,i:number) => { try { result.push(elementBinding().fromJson(eljson)); } catch(e) { @@ -223,7 +241,7 @@ function stringMapJsonBinding(dresolver : DeclResolver, texpr : AST.TypeExpr, bo const elementBinding = once(() => buildJsonBinding(dresolver, texpr, boundTypeParams)); function toJson(v : StringMap) : Json { - const result = {}; + const result: JsonObject = {}; for (let k in v) { result[k] = elementBinding().toJson(v[k]); } @@ -231,13 +249,14 @@ function stringMapJsonBinding(dresolver : DeclResolver, texpr : AST.TypeExpr, bo } function fromJson(json : Json) : StringMap { - if (!(json instanceof Object)) { + const jobj = asJsonObject(json); + if (!jobj) { throw jsonParseException('expected an object'); } - let result = {}; - for (let k in json) { + let result: JsonObject = {}; + for (let k in jobj) { try { - result[k] = elementBinding().fromJson(json[k]); + result[k] = elementBinding().fromJson(jobj[k]); } catch(e) { if (isJsonParseException(e)) { e.pushField(k); @@ -296,8 +315,9 @@ function structJsonBinding(dresolver : DeclResolver, struct : AST.Struct, params }); }); - function toJson(v: Unknown) : Json { - const json = {}; + function toJson(v0: Unknown) : Json { + const v = v0 as {[key:string]:Unknown}; + const json: JsonObject = {}; fieldDetails.forEach( (fd) => { json[fd.field.serializedName] = fd.jsonBinding().toJson(v && v[fd.field.name]); }); @@ -305,13 +325,14 @@ function structJsonBinding(dresolver : DeclResolver, struct : AST.Struct, params } function fromJson(json: Json): Unknown { - if (!(json instanceof Object)) { + const jobj = asJsonObject(json); + if (!jobj) { throw jsonParseException("expected an object"); } - const v = {}; + const v : {[member:string]: Unknown} = {}; fieldDetails.forEach( (fd) => { - if (json[fd.field.serializedName] === undefined) { + if (jobj[fd.field.serializedName] === undefined) { const defaultv = fd.buildDefault(); if (defaultv === null) { throw jsonParseException("missing struct field " + fd.field.serializedName ); @@ -320,7 +341,7 @@ function structJsonBinding(dresolver : DeclResolver, struct : AST.Struct, params } } else { try { - v[fd.field.name] = fd.jsonBinding().fromJson(json[fd.field.serializedName]); + v[fd.field.name] = fd.jsonBinding().fromJson(jobj[fd.field.serializedName]); } catch(e) { if (isJsonParseException(e)) { e.pushField(fd.field.serializedName); @@ -337,7 +358,7 @@ function structJsonBinding(dresolver : DeclResolver, struct : AST.Struct, params function enumJsonBinding(_dresolver : DeclResolver, union : AST.Union, _params : AST.TypeExpr[], _boundTypeParams : BoundTypeParams ) : JsonBinding0 { const fieldSerializedNames : string[] = []; - const fieldNumbers = {}; + const fieldNumbers : {[key:string]:number} = {}; union.fields.forEach( (field,i) => { fieldSerializedNames.push(field.serializedName); fieldNumbers[field.serializedName] = i; @@ -361,12 +382,18 @@ function enumJsonBinding(_dresolver : DeclResolver, union : AST.Union, _params : return {toJson, fromJson}; } +interface FieldDetails { + field : AST.Field; + isVoid : boolean; + jsonBinding : () => JsonBinding0; +}; + function unionJsonBinding(dresolver : DeclResolver, union : AST.Union, params : AST.TypeExpr[], boundTypeParams : BoundTypeParams ) : JsonBinding0 { const newBoundTypeParams = createBoundTypeParams(dresolver, union.typeParams, params, boundTypeParams); - const detailsByName = {}; - const detailsBySerializedName = {}; + const detailsByName : {[key: string]: FieldDetails} = {}; + const detailsBySerializedName : {[key: string]: FieldDetails} = {}; union.fields.forEach( (field) => { const details = { field : field, @@ -383,7 +410,7 @@ function unionJsonBinding(dresolver : DeclResolver, union : AST.Union, params : if (details.isVoid) { return details.field.serializedName; } else { - const result = {}; + const result: JsonObject = {}; result[details.field.serializedName] = details.jsonBinding().toJson(v.value); return result; } @@ -404,13 +431,15 @@ function unionJsonBinding(dresolver : DeclResolver, union : AST.Union, params : throw jsonParseException("union field " + json + "needs an associated value"); } return { kind : details.field.name }; - } else if (json instanceof Object) { - for (let k in json) { + } + const jobj = asJsonObject(json); + if (jobj) { + for (let k in jobj) { let details = lookupDetails(k); try { return { kind : details.field.name, - value : details.jsonBinding().fromJson(json[k]) + value : details.jsonBinding().fromJson(jobj[k]) } } catch(e) { if (isJsonParseException(e)) { diff --git a/test/adl-gen/runtime/sys/adlast.ts b/test/adl-gen/runtime/sys/adlast.ts index e2a40cc..eb391ad 100644 --- a/test/adl-gen/runtime/sys/adlast.ts +++ b/test/adl-gen/runtime/sys/adlast.ts @@ -40,6 +40,14 @@ export interface TypeRef_Reference { export type TypeRef = TypeRef_Primitive | TypeRef_TypeParam | TypeRef_Reference; +export interface TypeRefOpts { + primitive: Ident; + typeParam: Ident; + reference: ScopedName; +} + +export function makeTypeRef(kind: K, value: TypeRefOpts[K]) { return {kind, value}; } + export interface TypeExpr { typeRef: TypeRef; parameters: TypeExpr[]; @@ -173,6 +181,15 @@ export interface DeclType_Newtype_ { export type DeclType = DeclType_Struct_ | DeclType_Union_ | DeclType_Type_ | DeclType_Newtype_; +export interface DeclTypeOpts { + struct_: Struct; + union_: Union; + type_: TypeDef; + newtype_: NewType; +} + +export function makeDeclType(kind: K, value: DeclTypeOpts[K]) { return {kind, value}; } + export interface Decl { name: Ident; version: sys_types.Maybe; @@ -226,6 +243,13 @@ export interface Import_ScopedName { export type Import = Import_ModuleName | Import_ScopedName; +export interface ImportOpts { + moduleName: ModuleName; + scopedName: ScopedName; +} + +export function makeImport(kind: K, value: ImportOpts[K]) { return {kind, value}; } + export interface Module { name: ModuleName; imports: Import[]; diff --git a/test/adl-gen/runtime/sys/types.ts b/test/adl-gen/runtime/sys/types.ts index 98a54f1..95da107 100644 --- a/test/adl-gen/runtime/sys/types.ts +++ b/test/adl-gen/runtime/sys/types.ts @@ -29,6 +29,13 @@ export interface Either_Right<_T1, T2> { export type Either = Either_Left | Either_Right; +export interface EitherOpts { + left: T1; + right: T2; +} + +export function makeEither>(kind: K, value: EitherOpts[K]) { return {kind, value}; } + export interface Maybe_Nothing<_T> { kind: 'nothing'; } @@ -39,6 +46,13 @@ export interface Maybe_Just { export type Maybe = Maybe_Nothing | Maybe_Just; +export interface MaybeOpts { + nothing: null; + just: T; +} + +export function makeMaybe>(kind: K, value: MaybeOpts[K]) { return {kind, value}; } + export interface Error_Value { kind: 'value'; value: T; @@ -50,6 +64,31 @@ export interface Error_Error<_T> { export type Error = Error_Value | Error_Error; +export interface ErrorOpts { + value: T; + error: string; +} + +export function makeError>(kind: K, value: ErrorOpts[K]) { return {kind, value}; } + +export interface Result_Ok { + kind: 'ok'; + value: T; +} +export interface Result_Error<_T, E> { + kind: 'error'; + value: E; +} + +export type Result = Result_Ok | Result_Error; + +export interface ResultOpts { + ok: T; + error: E; +} + +export function makeResult>(kind: K, value: ResultOpts[K]) { return {kind, value}; } + export interface MapEntry { key: K; value: V; diff --git a/test/adl-gen/sys/types.ts b/test/adl-gen/sys/types.ts index eb06808..1300ceb 100644 --- a/test/adl-gen/sys/types.ts +++ b/test/adl-gen/sys/types.ts @@ -108,6 +108,33 @@ export function texprError(texprT : ADL.ATypeExpr): ADL.ATypeExpr return {value : {typeRef : {kind: "reference", value : {moduleName : "sys.types",name : "Error"}}, parameters : [texprT.value]}}; } +export interface Result_Ok { + kind: 'ok'; + value: T; +} +export interface Result_Error<_T, E> { + kind: 'error'; + value: E; +} + +export type Result = Result_Ok | Result_Error; + +export interface ResultOpts { + ok: T; + error: E; +} + +export function makeResult>(kind: K, value: ResultOpts[K]) { return {kind, value}; } + +const Result_AST : ADL.ScopedDecl = + {"moduleName":"sys.types","decl":{"annotations":[],"type_":{"kind":"union_","value":{"typeParams":["T","E"],"fields":[{"annotations":[],"serializedName":"ok","default":{"kind":"nothing"},"name":"ok","typeExpr":{"typeRef":{"kind":"typeParam","value":"T"},"parameters":[]}},{"annotations":[],"serializedName":"error","default":{"kind":"nothing"},"name":"error","typeExpr":{"typeRef":{"kind":"typeParam","value":"E"},"parameters":[]}}]}},"name":"Result","version":{"kind":"nothing"}}}; + +export const snResult: ADL.ScopedName = {moduleName:"sys.types", name:"Result"}; + +export function texprResult(texprT : ADL.ATypeExpr, texprE : ADL.ATypeExpr): ADL.ATypeExpr> { + return {value : {typeRef : {kind: "reference", value : {moduleName : "sys.types",name : "Result"}}, parameters : [texprT.value, texprE.value]}}; +} + export interface MapEntry { key: K; value: V; @@ -161,6 +188,7 @@ export const _AST_MAP: { [key: string]: ADL.ScopedDecl } = { "sys.types.Either" : Either_AST, "sys.types.Maybe" : Maybe_AST, "sys.types.Error" : Error_AST, + "sys.types.Result" : Result_AST, "sys.types.MapEntry" : MapEntry_AST, "sys.types.Map" : Map_AST, "sys.types.Set" : Set_AST