work in progress [might break]
This commit is contained in:
parent
315e67ce05
commit
7d95ec66b6
14 changed files with 30196 additions and 1 deletions
1
.vimrc
Normal file
1
.vimrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
noremap <silent> <F5> :!./make && ./make runtest \| most<CR>
|
||||||
11
README.md
11
README.md
|
|
@ -1 +1,10 @@
|
||||||
# xrfragment
|
# usage
|
||||||
|
|
||||||
|
|
||||||
|
# development
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./make install
|
||||||
|
$ ./make
|
||||||
|
$ ./make runtest
|
||||||
|
```
|
||||||
|
|
|
||||||
83
build.hxml
Normal file
83
build.hxml
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
-dce no
|
||||||
|
-cp src
|
||||||
|
|
||||||
|
xrfragment.Query
|
||||||
|
-D shallow-expose
|
||||||
|
--resource stub/stub.js@stub
|
||||||
|
-js dist/xrfragment.js
|
||||||
|
|
||||||
|
--next
|
||||||
|
|
||||||
|
-dce no
|
||||||
|
-cp src
|
||||||
|
|
||||||
|
Test
|
||||||
|
-D shallow-expose
|
||||||
|
-m Test
|
||||||
|
-js test/generated/test.js
|
||||||
|
|
||||||
|
--next
|
||||||
|
|
||||||
|
-dce no
|
||||||
|
-cp src
|
||||||
|
|
||||||
|
xrfragment.Query
|
||||||
|
-lua dist/xrfragment.lua
|
||||||
|
|
||||||
|
--next
|
||||||
|
|
||||||
|
-dce no
|
||||||
|
-cp src
|
||||||
|
|
||||||
|
xrfragment.Query
|
||||||
|
-python dist/xrfragment.py
|
||||||
|
|
||||||
|
--next
|
||||||
|
|
||||||
|
-dce no
|
||||||
|
-cp src
|
||||||
|
|
||||||
|
Test
|
||||||
|
-m Test
|
||||||
|
-python test/generated/test.py
|
||||||
|
|
||||||
|
#--next
|
||||||
|
#
|
||||||
|
#-dce no
|
||||||
|
#-cp src
|
||||||
|
#
|
||||||
|
#xrfragment.Query
|
||||||
|
#-php dist/xrfragment.php5
|
||||||
|
#
|
||||||
|
#--next
|
||||||
|
#
|
||||||
|
#-dce no
|
||||||
|
#-cp src
|
||||||
|
#
|
||||||
|
#xrfragment.Query
|
||||||
|
#-cpp dist/xrfragment.cpp
|
||||||
|
#
|
||||||
|
#--next
|
||||||
|
#
|
||||||
|
#-dce no
|
||||||
|
#-cp src
|
||||||
|
#
|
||||||
|
#xrfragment.Query
|
||||||
|
#-cppia dist/xrfragment.cppia
|
||||||
|
#
|
||||||
|
#--next
|
||||||
|
#
|
||||||
|
#-dce no
|
||||||
|
#-cp src
|
||||||
|
#
|
||||||
|
#xrfragment.Query
|
||||||
|
#-cs dist/xrfragment.csharp
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#--next
|
||||||
|
#
|
||||||
|
#-dce no
|
||||||
|
#-cp src
|
||||||
|
#
|
||||||
|
#xrfragment.Query
|
||||||
|
#-java xrfragment.jdk
|
||||||
2257
dist/xrfragment.js
vendored
Normal file
2257
dist/xrfragment.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
10028
dist/xrfragment.lua
vendored
Normal file
10028
dist/xrfragment.lua
vendored
Normal file
File diff suppressed because it is too large
Load diff
7433
dist/xrfragment.py
vendored
Normal file
7433
dist/xrfragment.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
26
make
Executable file
26
make
Executable file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
try(){ set +e; "$@" 2>/dev/null; set -e; }
|
||||||
|
|
||||||
|
install(){
|
||||||
|
which haxe || {
|
||||||
|
echo " 1. install haxe from haxe.org"
|
||||||
|
echo "[2.] download neko for cpp output"
|
||||||
|
echo "[3.] install mono openjdk14 for csharp + java output"
|
||||||
|
}
|
||||||
|
haxelib setup
|
||||||
|
haxelib install hxcpp
|
||||||
|
haxelib install hxjava
|
||||||
|
haxelib install hxcs
|
||||||
|
haxelib install hscript
|
||||||
|
}
|
||||||
|
|
||||||
|
runtest(){
|
||||||
|
set -x
|
||||||
|
which python3 && python3 test/generated/test.py | awk '{ print "py: "$0 } END{ print "\n"}'
|
||||||
|
which node && node test/generated/test.js | awk '{ print "js: "$0 } END{ print "\n"}'
|
||||||
|
}
|
||||||
|
|
||||||
|
test -z $1 && { try rm dist/* ; haxe build.hxml; exit $?; }
|
||||||
|
test -z $1 || "$@"
|
||||||
118
src/Test.hx
Normal file
118
src/Test.hx
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
import xrfragment.Query;
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
|
||||||
|
static public function main():Void {
|
||||||
|
trace("starting tests");
|
||||||
|
|
||||||
|
var Query = xrfragment.Query;
|
||||||
|
|
||||||
|
trace( (new Query("foo or bar")).toObject() );
|
||||||
|
trace( (new Query("class:fopoer or bar foo:bar")).toObject().or[0] );
|
||||||
|
trace( (new Query("-skybox class:foo")).toObject().or[0] );
|
||||||
|
trace( (new Query("foo/flop moo or bar")).toObject().or[0] );
|
||||||
|
trace( (new Query("-foo/flop moo or bar")).toObject().or[0] );
|
||||||
|
trace( (new Query("price:>4 moo or bar")).toObject().or[0] );
|
||||||
|
trace( (new Query("price:>=4 moo or bar")).toObject().or[0] );
|
||||||
|
trace( (new Query("price:<=4 moo or bar")).toObject().or[0] );
|
||||||
|
trace( (new Query("price:!=4 moo or bar")).toObject().or[0] );
|
||||||
|
|
||||||
|
var q:Dynamic = new Query("price:!=4 moo or bar");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
q.test( "price", 4);
|
||||||
|
var ok = !q.qualify("slkklskdf");
|
||||||
|
if( !ok ) throw 'node should not be allowed';
|
||||||
|
|
||||||
|
q = new Query("price:!=3 moo or bar");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
q.test( "price", 4);
|
||||||
|
var ok = q.qualify("slkklskdf");
|
||||||
|
if( !ok ) throw 'non-mentioned node should be allowed';
|
||||||
|
|
||||||
|
q = new Query("moo or bar");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
var ok = !q.qualify("slkklskdf");
|
||||||
|
if( !ok ) throw 'node should not be allowed';
|
||||||
|
obj = q.toObject();
|
||||||
|
var ok = q.qualify("moo");
|
||||||
|
if( !ok ) throw 'moo should be allowed';
|
||||||
|
var ok = q.qualify("bar");
|
||||||
|
if( !ok ) throw 'bar should be allowed';
|
||||||
|
|
||||||
|
q = new Query("price:>3 moo or bar");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
q.test( "price", 4);
|
||||||
|
var ok = q.qualify("foo");
|
||||||
|
if( !ok ) throw 'node should be allowed';
|
||||||
|
var ok = q.qualify("bar");
|
||||||
|
if( !ok ) throw 'node should be allowed';
|
||||||
|
var ok = q.qualify("moo");
|
||||||
|
if( !ok ) throw 'node should be allowed';
|
||||||
|
|
||||||
|
q = new Query("price:>3 price:<10 -bar");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
q.test( "price", 4);
|
||||||
|
var ok = q.qualify("foo");
|
||||||
|
if( !ok ) throw 'node should be allowed';
|
||||||
|
var ok = !q.qualify("bar");
|
||||||
|
if( !ok ) throw 'bar should not be allowed';
|
||||||
|
q.test("price", 20);
|
||||||
|
var ok = !q.qualify("foo");
|
||||||
|
if( !ok ) throw 'price 20 should not be allowed';
|
||||||
|
|
||||||
|
q = new Query("-bar");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
var ok = q.qualify("foo");
|
||||||
|
if( !ok ) throw 'node should be allowed';
|
||||||
|
var ok = !q.qualify("bar");
|
||||||
|
if( !ok ) throw 'bar should not be allowed';
|
||||||
|
|
||||||
|
q = new Query("title:*");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
var ok = !q.qualify("foo");
|
||||||
|
if( !ok ) throw 'node should not be allowed';
|
||||||
|
q.test("foo","bar");
|
||||||
|
var ok = !q.qualify("foo");
|
||||||
|
if( !ok ) throw 'node should not be allowed';
|
||||||
|
q.test("title","bar");
|
||||||
|
var ok = q.qualify("foo");
|
||||||
|
if( !ok ) throw 'node should be allowed';
|
||||||
|
|
||||||
|
q = new Query("-bar +bar");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
var ok = q.qualify("foo");
|
||||||
|
if( !ok ) throw 'node should be allowed';
|
||||||
|
var ok = q.qualify("bar");
|
||||||
|
if( !ok ) throw 'bar should be allowed';
|
||||||
|
|
||||||
|
q = new Query("?discount");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
q.test("?discount","-foo");
|
||||||
|
var ok = !q.qualify("foo");
|
||||||
|
if( !ok ) throw 'foo should not be allowed';
|
||||||
|
|
||||||
|
q = new Query("?");
|
||||||
|
q.test("?","-foo");
|
||||||
|
var ok = !q.qualify("foo");
|
||||||
|
if( !ok ) throw 'foo should not be allowed';
|
||||||
|
|
||||||
|
q = new Query("?");
|
||||||
|
var ok = q.qualify("foo");
|
||||||
|
if( !ok ) throw 'foo should not be allowed';
|
||||||
|
|
||||||
|
q = new Query("?discount");
|
||||||
|
q.test("?discount","-foo");
|
||||||
|
var ok = !q.qualify("foo");
|
||||||
|
if( !ok ) throw 'foo should not be allowed';
|
||||||
|
|
||||||
|
q = new Query("?discount +foo");
|
||||||
|
var obj:Dynamic = q.toObject();
|
||||||
|
q.test("?discount","-foo");
|
||||||
|
var ok = !q.qualify("foo");
|
||||||
|
if( !ok ) throw 'foo should not be allowed';
|
||||||
|
var ok = !q.qualify("foo");
|
||||||
|
if( !ok ) throw 'foo should not be allowed';
|
||||||
|
|
||||||
|
trace("all tests passed");
|
||||||
|
}
|
||||||
|
}
|
||||||
175
src/xrfragment/Query.hx
Normal file
175
src/xrfragment/Query.hx
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
package xrfragment;
|
||||||
|
|
||||||
|
@:expose // <- makes the class reachable from plain JavaScript
|
||||||
|
@:keep // <- avoids accidental removal by dead code elimination
|
||||||
|
|
||||||
|
#if js
|
||||||
|
var ok:Bool = js.Syntax.code('
|
||||||
|
// haxe workarounds
|
||||||
|
|
||||||
|
Array.prototype.contains = Array.prototype.includes
|
||||||
|
|
||||||
|
if (typeof Array.prototype.remove !== "function") {
|
||||||
|
Array.prototype.remove = function (item) {
|
||||||
|
const oldLength = this.length
|
||||||
|
let newLength = 0
|
||||||
|
|
||||||
|
for (let i = 0; i < oldLength; i++) {
|
||||||
|
const entry = this[i]
|
||||||
|
if (entry === item) {
|
||||||
|
let newLength = i++
|
||||||
|
|
||||||
|
while (i !== this.length) {
|
||||||
|
const entry = this[i]
|
||||||
|
if (entry !== item) this[newLength++] = entry
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
this.length = newLength
|
||||||
|
for (let i = newLength; i < oldLength; i++) delete this[i]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
');
|
||||||
|
#end
|
||||||
|
|
||||||
|
class Query {
|
||||||
|
|
||||||
|
private var str:String = "";
|
||||||
|
private var q:Dynamic = {};
|
||||||
|
private var include:Array<String> = new Array();
|
||||||
|
private var exclude:Array<String> = new Array();
|
||||||
|
private var accept:Bool = false;
|
||||||
|
private var preset:String = "";
|
||||||
|
|
||||||
|
public function new(str:String){
|
||||||
|
if( str != null ) this.parse(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toObject() : Dynamic {
|
||||||
|
return this.q;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function qualify( nodename:String ): Bool {
|
||||||
|
if( this.q.copy_all ) this.accept = true;
|
||||||
|
if( this.include.contains(nodename) ) this.accept = true;
|
||||||
|
if( this.exclude.contains(nodename) ) this.accept = false;
|
||||||
|
return this.accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse(str:String,recurse:Bool = false) : Dynamic {
|
||||||
|
|
||||||
|
var copyAll:Bool = recurse ? this.q.copy_all : str.substr(0,1) == "-" || str.substr(0,1) == "?" || str == "";
|
||||||
|
var isOr:EReg = ~/^or$/;
|
||||||
|
var isProp:EReg = ~/.*:[><=!]?/;
|
||||||
|
var isName:EReg = ~/[^:\/]/;
|
||||||
|
var isExclude:EReg = ~/^-/;
|
||||||
|
var isInclude:EReg = ~/^\+/;
|
||||||
|
var isPreset:EReg = ~/^\?/;
|
||||||
|
|
||||||
|
var token = str.split(" ");
|
||||||
|
var ors = new Array();
|
||||||
|
var q:haxe.DynamicAccess<Dynamic> = {};
|
||||||
|
|
||||||
|
function composeQuery() : Dynamic {
|
||||||
|
q = {};
|
||||||
|
q.set("object", new Array() );
|
||||||
|
q.set("-object", new Array() );
|
||||||
|
ors.push(q);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
composeQuery();
|
||||||
|
|
||||||
|
function match(str,prefix = ""){
|
||||||
|
if( isPreset.match(str) && !recurse ){
|
||||||
|
this.preset = str;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( isExclude.match(str) || isInclude.match(str) ){
|
||||||
|
var t = str.substr(1);
|
||||||
|
match(t, str.substr(0,1) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( isProp.match(str) ){
|
||||||
|
var skip = 0;
|
||||||
|
var type = "=";
|
||||||
|
if( str.indexOf("*") != -1 ) type = "*";
|
||||||
|
if( str.indexOf(">") != -1 ) type = ">";
|
||||||
|
if( str.indexOf("<") != -1 ) type = "<";
|
||||||
|
if( str.indexOf("!=") != -1 ) type = "!=";
|
||||||
|
if( str.indexOf(">=") != -1 ) type = ">=";
|
||||||
|
if( str.indexOf("<=") != -1 ) type = "<=";
|
||||||
|
if( type != "=" ) skip += type.length;
|
||||||
|
var property = str.split(":")[0];
|
||||||
|
var value:haxe.DynamicAccess<Dynamic>;
|
||||||
|
if( q.get(prefix+property) ) value = q.get(prefix+property);
|
||||||
|
else value = {};
|
||||||
|
value[ type ] = str.split(":")[1].substr(skip);
|
||||||
|
q.set(prefix+property,value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( isName.match(str) ){
|
||||||
|
if( prefix == '-' ){
|
||||||
|
q["-object"].push(str);
|
||||||
|
while( q["object"].contains(str) == true) {
|
||||||
|
q["object"].remove(str);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
q["object"].push(str);
|
||||||
|
while( q["-object"].contains(str) == true ){
|
||||||
|
q["-object"].remove(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i in 0...token.length ) {
|
||||||
|
if( isOr.match(token[i]) ){
|
||||||
|
composeQuery();
|
||||||
|
}else match(token[i]);
|
||||||
|
}
|
||||||
|
for ( i in 0...ors.length ) {
|
||||||
|
var or:Dynamic = ors[i];
|
||||||
|
if( Reflect.field(or,'object') != null ) this.include = this.include.concat( Reflect.field(or,'object') );
|
||||||
|
if( Reflect.field(or,'-object') != null ) this.exclude = this.exclude.concat( Reflect.field(or,'-object') );
|
||||||
|
}
|
||||||
|
this.q = { or: ors, copy_all: copyAll };
|
||||||
|
return this.q;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test( property:String, ?value:Dynamic ):Void{
|
||||||
|
if( this.preset == property ){
|
||||||
|
this.parse( value, true );
|
||||||
|
}
|
||||||
|
for ( i in 0...this.q.or.length ) {
|
||||||
|
var or:Dynamic = this.q.or[i];
|
||||||
|
var conds:Int = 0;
|
||||||
|
var fails:Int = 0;
|
||||||
|
var pass:Int = 0;
|
||||||
|
|
||||||
|
var when = function(expr:Bool) : Bool {
|
||||||
|
conds+=1;
|
||||||
|
fails+= expr ? 0 : 1;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( k in Reflect.fields(or) ){
|
||||||
|
var orval:Dynamic = Reflect.field(or,k);
|
||||||
|
if( k != property ) continue;
|
||||||
|
if( Reflect.field(orval,'=') != null && when( value == Reflect.field(orval,'=') ) ) pass += 1;
|
||||||
|
if( Reflect.field(orval,'*') != null && when( value != null ) ) pass += 1;
|
||||||
|
if( Reflect.field(orval,'>') != null && when( value > Std.parseInt(Reflect.field(orval,'>' )) ) ) pass += 1;
|
||||||
|
if( Reflect.field(orval,'<') != null && when( value < Std.parseInt(Reflect.field(orval,'<' )) ) ) pass += 1;
|
||||||
|
if( Reflect.field(orval,'>=') != null && when( value >= Std.parseInt(Reflect.field(orval,'>=')) ) ) pass += 1;
|
||||||
|
if( Reflect.field(orval,'<=') != null && when( value >= Std.parseInt(Reflect.field(orval,'<=')) ) ) pass += 1;
|
||||||
|
if( Reflect.field(orval,'!=') != null && when( value != Std.parseInt(Reflect.field(orval,'!=')) ) ) pass += 1;
|
||||||
|
}
|
||||||
|
if( this.accept && conds > 0 && fails > 0 ) this.accept = false;
|
||||||
|
if( conds > 0 && pass > 0 && fails == 0 ) this.accept = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2432
test/generated/test.js
Normal file
2432
test/generated/test.js
Normal file
File diff suppressed because it is too large
Load diff
7590
test/generated/test.py
Normal file
7590
test/generated/test.py
Normal file
File diff suppressed because it is too large
Load diff
28
test/test.js
Normal file
28
test/test.js
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
// in the browser use this instead of require():
|
||||||
|
//
|
||||||
|
// <script src="Query.js"></script>
|
||||||
|
// <script>
|
||||||
|
// var q = new hgltf.Query()
|
||||||
|
// </script>
|
||||||
|
|
||||||
|
var hgltf = require('../Query').hgltf
|
||||||
|
var q = new hgltf.Query()
|
||||||
|
|
||||||
|
|
||||||
|
var res = q.parse("")
|
||||||
|
if( !res.copy_all ) throw 'empty string should always set copy_all to true'
|
||||||
|
|
||||||
|
console.log( q.parse("") )
|
||||||
|
console.log( JSON.stringify(q.parse("foo:*"), null, 2) )
|
||||||
|
return
|
||||||
|
console.log( q.parse("-skybox -plane") )
|
||||||
|
console.log( q.parse("foo or bar") );
|
||||||
|
console.log( q.parse("class:fopoer or bar foo:bar").or[0] );
|
||||||
|
console.log( q.parse("-skybox class:foo").or[0] );
|
||||||
|
console.log( q.parse("foo/flop moo or bar").or[0] );
|
||||||
|
console.log( q.parse("-foo/flop moo or bar").or[0] );
|
||||||
|
console.log( q.parse("price:>4 moo or bar").or[0] );
|
||||||
|
console.log( q.parse("price:>=4 moo or bar").or[0] );
|
||||||
|
console.log( q.parse("price:<=4 moo or bar").or[0] );
|
||||||
|
console.log( q.parse("price:!=4 moo or bar").or[0] );
|
||||||
1
test/test.lua
Normal file
1
test/test.lua
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
require "../Query"
|
||||||
14
test/test.py
Normal file
14
test/test.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
from Query import hgltf_Query
|
||||||
|
|
||||||
|
q = hgltf_Query()
|
||||||
|
|
||||||
|
print( q.parse("foo or bar") )
|
||||||
|
print( q.parse("foo or bar") )
|
||||||
|
print( q.parse("class:fopoer or bar foo:bar") )
|
||||||
|
print( q.parse("-skybox class:foo") )
|
||||||
|
print( q.parse("foo/flop moo or bar") )
|
||||||
|
print( q.parse("-foo/flop moo or bar") )
|
||||||
|
print( q.parse("price:>4 moo or bar") )
|
||||||
|
print( q.parse("price:>=4 moo or bar") )
|
||||||
|
print( q.parse("price:<=4 moo or bar") )
|
||||||
|
print( q.parse("price:!=4 moo or bar") )
|
||||||
Loading…
Add table
Reference in a new issue