AT(..) now supports patterns in keys or paths + docs...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-09-06 04:32:01 +03:00
parent a559ed7aeb
commit a70605f742
2 changed files with 96 additions and 17 deletions

View File

@ -554,6 +554,22 @@ Matches a *container* if it contains `A`.
`AT(K, A)`
Matches a *container* if it contains `A` *at* index/key `K`
If `K` is a pattern or a path containing a pattern then matching is done as follows:
1. select all keys/paths that match `K`
2. get all values at the selected keys/paths
3. match iff *all* of the selected values match `A`
Note that to use an explicit array for `K`, wrap it in an array, e.g. to use `[item, ..]` as key write: `AT([[item, ..]], ..)`.
`AT(K)`
Matches if a *container* has an index/key `K`.
This is equivalent to `AT(K, ANY)`.
~~`ORDERED(A, B)`~~
~~`ADJACENT(A, B, ...)`~~
~~`OF(A, N)`~~

97
diff.js
View File

@ -667,10 +667,11 @@ object.makeConstructor('TEST', Object.assign(Object.create(LogicType.prototype),
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// IN(A) == L iff A in L
// IN(A) == L iff A contained in L
//
// NOTE: since this can do a search using cmp(..) thid will be slow on
// large containers...
// NOTE: to test if a key exists use AT(key)
var IN =
module.IN =
object.makeConstructor('IN', Object.assign(Object.create(LogicType.prototype), {
@ -678,7 +679,7 @@ object.makeConstructor('IN', Object.assign(Object.create(LogicType.prototype), {
// XXX should we check inherited stuff???
__cmp__: function(obj, cmp, context){
var p = this.value
return (obj instanceof Map || obj instanceof Set ?
return ((obj instanceof Map || obj instanceof Set) ?
[...obj.values()]
: [])
.concat(Object.values(obj))
@ -693,7 +694,13 @@ object.makeConstructor('IN', Object.assign(Object.create(LogicType.prototype), {
}))
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AT(A, K) == L iff A in L and L[K] == A
// AT(K, A) == L iff A in L and L[K] == A
//
// If K is a pattern or a path containing a pattern this works in the
// following stages:
// 1) select all the keys/paths that match K
// 2) get all the values at the matching paths
// 3) return true if ALL the values match A
//
// NOTE: this also supports path keys -- i.e. array of path elements that
// will be traversed and the last one checked...
@ -701,10 +708,10 @@ object.makeConstructor('IN', Object.assign(Object.create(LogicType.prototype), {
// an array:
// AT([[123]], ...)
//
// XXX .key can't be a pattern at this point...
// ...to implement this we would need to do:
// 1) a search for a matching pattern...
// 2) handle multiple matches in some manner (first, all?)...
// XXX pattern keys are still experimental, and the exact matching rules
// may still change...
// ...not yet sure if on step #3 we should require ALL or at least
// one match, though I'm leaning towards ALL...
// XXX this falls into recursion on:
// X = AT('moo')
// X.value = OR(123, X)
@ -717,23 +724,79 @@ module.AT =
object.makeConstructor('AT', Object.assign(Object.create(LogicType.prototype), {
__cmp__: function(obj, cmp, context){
var key = this.key instanceof Array ? this.key : [this.key]
var no_result = {}
obj = key
var value = this.value
//return key
var res = key
.reduce(function(o, k){
return (o == null || o === no_result) ?
no_result
: o[k] }, obj)
if(obj !== no_result && cmp(obj, this.value, context)){
return true
}
return false
return o
.map(function(o){
return o == null ?
[]
// pattern key,,,
: k instanceof LogicType ?
Object.entries(o)
.filter(function(e){
return cmp(k, e[0], context) })
.map(function(e){
return e[1] })
// normal key...
// NOTE: we are not using 'k in o' here because
// only objects are supported by the in
// operator and we can get any value...
: Object.keys(o).indexOf(k) >= 0 ?
[o[k]]
// key not in container...
: [] })
// flatten the list of candidates...
.reduce(function(o, e){
return o.concat(e) }, []) }, [obj])
/*
.filter(function(e){
return cmp(e, value, context)})
// at least one must match...
.length > 0
//*/
return obj != null
&& res.length > 0
&& res
.filter(function(e){
return cmp(e, value, context)})
// all must match...
.length == res.length
},
__init__: function(key, value){
this.key = key
this.value = value
this.value = arguments.length < 2 ? ANY : value
},
}))
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// XXX ORDERED(A, B, ..) == L iff A is before B, B is before C, ... etc.
var ORDERED =
module.ORDERED =
object.makeConstructor('ORDERED', Object.assign(Object.create(LogicType.prototype), {
__cmp__: function(obj, cmp){
// XXX
},
__init__: function(...items){
this.items = items
},
}))
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// XXX ADJACENT(A, B, ..) == L iff A directly before B, B directly before C, ...
var ADJACENT =
module.ADJACENT =
object.makeConstructor('ADJACENT', Object.assign(Object.create(LogicType.prototype), {
__cmp__: function(obj, cmp){
// XXX
},
__init__: function(...items){
this.items = items
},
}))
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// XXX OF(A, N) == L iff L contains N occurrences of A
// XXX this is a potential problem as it would require us to look ahead