From 25cb01aefe0920bc35115ea61cadfaf4be016304 Mon Sep 17 00:00:00 2001 From: John Haugeland Date: Sun, 5 May 2019 06:34:52 -0700 Subject: [PATCH] Considering taking out the type generalization --- src/js/jssm.ts | 114 ++++++++++++++++++++++---------------------- src/js/jssm_util.ts | 71 +++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 57 deletions(-) create mode 100644 src/js/jssm_util.ts diff --git a/src/js/jssm.ts b/src/js/jssm.ts index a720c84d..dab18e57 100644 --- a/src/js/jssm.ts +++ b/src/js/jssm.ts @@ -18,7 +18,7 @@ import { JssmArrow, JssmArrowDirection, JssmArrowKind, JssmLayout -} from './jssm-types'; +} from './jssm_types'; @@ -27,7 +27,7 @@ import { import { seq, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key -} from './jssm-util.js'; +} from './jssm_util'; @@ -249,7 +249,7 @@ function compile_rule_transition_step( -function compile_rule_handle_transition(rule: JssmCompileSeStart): mixed { // todo flow describe the parser representation of a transition +function compile_rule_handle_transition(rule: JssmCompileSeStart): any { // TODO FIXME no any // todo flow describe the parser representation of a transition return compile_rule_transition_step([], rule.from, rule.se.to, rule.se, rule.se.se); } @@ -328,7 +328,7 @@ function compile(tree: JssmParseTree): JssmGenericConfig { _reverse_actions : Map>; _reverse_action_targets : Map>; - _machine_author : ?Array; - _machine_comment : ?string; - _machine_contributor : ?Array; - _machine_definition : ?string; - _machine_language : ?string; - _machine_license : ?string; - _machine_name : ?string; - _machine_version : ?string; - _fsl_version : ?string; - _raw_state_declaration : ?Array; // eslint-disable-line flowtype/no-weak-types + _machine_author? : string | Array; + _machine_comment? : string; + _machine_contributor? : string | Array; + _machine_definition? : string; + _machine_language? : string; + _machine_license? : string; + _machine_name? : string; + _machine_version? : string; + _fsl_version? : string; + _raw_state_declaration? : Array; // eslint-disable-line flowtype/no-weak-types _state_declarations : Map>; _graph_layout : JssmLayout; @@ -538,7 +538,7 @@ class Machine { // forward mapping first by action name - let actionMap: ?Map = this._actions.get(tr.action); + let actionMap: Map = this._actions.get(tr.action); // TODO FIXME ?Map equiv if (!(actionMap)) { actionMap = new Map(); this._actions.set(tr.action, actionMap); @@ -552,7 +552,7 @@ class Machine { // reverse mapping first by state origin name - let rActionMap: ?Map = this._reverse_actions.get(tr.from); + let rActionMap: Map = this._reverse_actions.get(tr.from); // TODO FIXME ?Map equiv if (!(rActionMap)) { rActionMap = new Map(); this._reverse_actions.set(tr.from, rActionMap); @@ -628,43 +628,43 @@ class Machine { - machine_author(): ?Array { + machine_author(): Array { return this._machine_author; } - machine_comment(): ?string { + machine_comment(): string { return this._machine_comment; } - machine_contributor(): ?Array { + machine_contributor(): Array { return this._machine_contributor; } - machine_definition(): ?string { + machine_definition(): string { return this._machine_definition; } - machine_language(): ?string { + machine_language(): string { return this._machine_language; } - machine_license(): ?string { + machine_license(): string { return this._machine_license; } - machine_name(): ?string { + machine_name(): string { return this._machine_name; } - machine_version(): ?string { + machine_version(): string { return this._machine_version; } - raw_state_declarations(): ?Array { // eslint-disable-line flowtype/no-weak-types + raw_state_declarations(): Array { // eslint-disable-line flowtype/no-weak-types return this._raw_state_declaration; } - state_declaration(which: mNT): ?JssmStateDeclaration { + state_declaration(which: mNT): JssmStateDeclaration { return this._state_declarations.get(which); } @@ -672,7 +672,7 @@ class Machine { return this._state_declarations; } - fsl_version(): ?string { + fsl_version(): string { return this._fsl_version; } @@ -703,11 +703,11 @@ class Machine { states(): Array { - return [... this._states.keys()]; + return Array.from(this._states.keys()); } state_for(whichState: mNT): JssmGenericState { - const state: ?JssmGenericState = this._states.get(whichState); + const state: JssmGenericState = this._states.get(whichState); if (state) { return state; } else { throw new Error(`no such state ${JSON.stringify(state)}`); } } @@ -723,14 +723,14 @@ class Machine { } list_actions(): Array { - return [... this._actions.keys()]; + return Array.from(this._actions.keys()); } - get_transition_by_state_names(from: mNT, to: mNT): ?number { + get_transition_by_state_names(from: mNT, to: mNT): number { - const emg : ?Map = this._edge_map.get(from); + const emg : Map = this._edge_map.get(from); if (emg) { return emg.get(to); @@ -742,8 +742,8 @@ class Machine { - lookup_transition_for(from: mNT, to: mNT): ?JssmTransition { - const id : ?number = this.get_transition_by_state_names(from, to); + lookup_transition_for(from: mNT, to: mNT): JssmTransition { + const id : number = this.get_transition_by_state_names(from, to); return ((id === undefined) || (id === null))? undefined : this._edges[id]; } @@ -765,14 +765,14 @@ class Machine { probable_exits_for(whichState: mNT): Array< JssmTransition > { - const wstate: ?JssmGenericState = this._states.get(whichState); + const wstate: JssmGenericState = this._states.get(whichState); if (!(wstate)) { throw new Error(`No such state ${JSON.stringify(whichState)} in probable_exits_for`); } const wstate_to : Array< mNT > = wstate.to, wtf : Array< JssmTransition > // wstate_to_filtered -> wtf = wstate_to - .map( (ws) : ?JssmTransition => this.lookup_transition_for(this.state(), ws)) + .map( (ws) : JssmTransition => this.lookup_transition_for(this.state(), ws)) .filter(Boolean); return wtf; @@ -801,14 +801,14 @@ class Machine { actions(whichState: mNT = this.state() ): Array { - const wstate : ?Map = this._reverse_actions.get(whichState); - if (wstate) { return [... wstate.keys()]; } + const wstate : Map = this._reverse_actions.get(whichState); + if (wstate) { return Array.from(wstate.keys()); } else { throw new Error(`No such state ${JSON.stringify(whichState)}`); } } list_states_having_action(whichState: mNT): Array { - const wstate : ?Map = this._actions.get(whichState); - if (wstate) { return [... wstate.keys()]; } + const wstate : Map = this._actions.get(whichState); + if (wstate) { return Array.from(wstate.keys()); } else { throw new Error(`No such state ${JSON.stringify(whichState)}`); } } @@ -821,24 +821,24 @@ class Machine { .map( filtered => filtered.from ); } */ - list_exit_actions(whichState: mNT = this.state() ): Array { // these are mNT, not ?mNT - const ra_base: ?Map = this._reverse_actions.get(whichState); + list_exit_actions(whichState: mNT = this.state() ): Array { // these are mNT, not ?mNT + const ra_base: Map = this._reverse_actions.get(whichState); if (!(ra_base)) { throw new Error(`No such state ${JSON.stringify(whichState)}`); } - return [... ra_base.values()] - .map ( (edgeId: number) : JssmTransition => this._edges[edgeId] ) - .filter ( (o: JssmTransition) : boolean => o.from === whichState ) - .map ( (filtered: JssmTransition) : ?mNT => filtered.action ); + return Array.from(ra_base.values()) + .map ( (edgeId: number) : JssmTransition => this._edges[edgeId] ) + .filter ( (o: JssmTransition) : boolean => o.from === whichState ) + .map ( (filtered: JssmTransition) : mNT => filtered.action ); } - probable_action_exits(whichState: mNT = this.state() ) : Array { // these are mNT - const ra_base: ?Map = this._reverse_actions.get(whichState); + probable_action_exits(whichState: mNT = this.state() ) : Array { // these are mNT // TODO FIXME no any + const ra_base: Map = this._reverse_actions.get(whichState); if (!(ra_base)) { throw new Error(`No such state ${JSON.stringify(whichState)}`); } - return [... ra_base.values()] + return Array.from(ra_base.values()) .map ( (edgeId: number): JssmTransition => this._edges[edgeId] ) .filter ( (o: JssmTransition): boolean => o.from === whichState ) - .map ( (filtered): mixed => ( { action : filtered.action, + .map ( (filtered): any => ( { action : filtered.action, // TODO FIXME no any probability : filtered.probability } ) ); } @@ -876,7 +876,7 @@ class Machine { } state_is_complete(whichState: mNT) : boolean { - const wstate: ?JssmGenericState = this._states.get(whichState); + const wstate: JssmGenericState = this._states.get(whichState); if (wstate) { return wstate.complete; } else { throw new Error(`No such state ${JSON.stringify(whichState)}`); } } @@ -927,13 +927,13 @@ class Machine { - current_action_for(action: mNT): number | void { - const action_base: ?Map = this._actions.get(action); + current_action_for(action: mNT): number { + const action_base: Map = this._actions.get(action); return action_base? action_base.get(this.state()): undefined; } current_action_edge_for(action: mNT): JssmTransition { - const idx: ?number = this.current_action_for(action); + const idx: number = this.current_action_for(action); if ((idx === undefined) || (idx === null)) { throw new Error(`No such action ${JSON.stringify(action)}`); } return this._edges[idx]; } @@ -949,7 +949,7 @@ class Machine { // todo whargarbl implement hooks // todo whargarbl implement data stuff // todo major incomplete whargarbl comeback - const transition_for: ?JssmTransition = this.lookup_transition_for(this.state(), newState); + const transition_for: JssmTransition = this.lookup_transition_for(this.state(), newState); if (!(transition_for)) { return false; } if (transition_for.forced_only) { return false; } @@ -972,7 +972,7 @@ class Machine { -function sm(template_strings: Array /* , arguments */): Machine { +function sm(template_strings: Array, ... remainder /* , arguments */): Machine { // foo`a${1}b${2}c` will come in as (['a','b','c'],1,2) // this includes when a and c are empty strings @@ -986,7 +986,7 @@ function sm(template_strings: Array /* , arguments */): Machin /* eslint-disable fp/no-arguments */ /* eslint-disable prefer-rest-params */ - (acc, val, idx): string => `${acc}${arguments[idx]}${val}` // arguments[0] is never loaded, so args doesn't need to be gated + (acc, val, idx): string => `${acc}${remainder[idx]}${val}` // arguments[0] is never loaded, so args doesn't need to be gated /* eslint-enable prefer-rest-params */ /* eslint-enable fp/no-arguments */ diff --git a/src/js/jssm_util.ts b/src/js/jssm_util.ts new file mode 100644 index 00000000..3ffdf8b7 --- /dev/null +++ b/src/js/jssm_util.ts @@ -0,0 +1,71 @@ + +// @flow + + + + + +// this is explicitly about other peoples' data, so it has to be weakly typed +/* eslint-disable flowtype/no-weak-types */ +const weighted_rand_select: Function = (options: Array, probability_property: string = 'probability'): any => { + + if (!Array.isArray(options)) { + throw new TypeError('options must be a non-empty array of objects'); + } + + if (!(typeof options[0] === 'object')) { + throw new TypeError('options must be a non-empty array of objects'); + } + + const frand : Function = (cap): number => Math.random() * cap, + or_one : Function = (item): any => item === undefined? 1 : item, + prob_sum : number = options.reduce( (acc, val:any): number => acc + or_one(val[probability_property]), 0 ), + rnd : number = frand(prob_sum); + + let cursor : number = 0, + cursor_sum : number = 0; + + while ((cursor_sum += or_one((options:any)[cursor++][probability_property])) <= rnd) { } // eslint-disable-line no-empty,fp/no-loops + return options[cursor-1]; + +}; +/* eslint-enable flowtype/no-weak-types */ + + + + + +const seq: Function = (n: number): Array => + + (new Array(n)).fill(true) + .map( (_, i): number => i ); + + + + + +const histograph: Function = (a : Array): Map => // eslint-disable-line flowtype/no-weak-types + + a.sort().reduce( (m,v): Map => ( m.set(v, (m.has(v)? m.get(v)+1 : 1)) , m), new Map() ); // eslint-disable-line flowtype/no-weak-types,no-sequences + + + + + +const weighted_sample_select: Function = (n: number, options: Array, probability_property: string): Array => // eslint-disable-line flowtype/no-weak-types + + seq(n).map( (_i): any => weighted_rand_select(options, probability_property)); // eslint-disable-line flowtype/no-weak-types + + + + + +const weighted_histo_key: Function = (n: number, opts: Array, prob_prop: string, extract: string): Array => // eslint-disable-line flowtype/no-weak-types + + histograph(weighted_sample_select(n, opts, prob_prop).map( (s): any => s[extract])); // eslint-disable-line flowtype/no-weak-types + + + + + +export { seq, histograph, weighted_histo_key, weighted_rand_select, weighted_sample_select };