2023-05-23 11:30:39 +02:00
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 Leon van Kammen/NLNET
2023-03-31 12:58:53 +02:00
package xrfragment ;
2023-04-14 14:45:50 +02:00
import xrfragment . XRF ;
2023-04-02 21:19:03 +02:00
2023-03-31 12:58:53 +02:00
@ : expose // <- makes the class reachable from plain JavaScript
@ : keep // <- avoids accidental removal by dead code elimination
2023-04-02 21:19:03 +02:00
class Parser {
2023-11-10 18:22:47 +01:00
public static var error: String = " " ;
public static var debug: Bool = false ;
public static var keyClean: EReg = ~/(\*$|^-)/g ;
2023-04-02 21:19:03 +02:00
@ : keep
2023-11-16 14:50:57 +01:00
public static function parse ( key : String , value : String , store : haxe . DynamicAccess < Dynamic > , ? index : Int ) : Bool {
2023-04-14 14:45:50 +02:00
// here we define allowed characteristics & datatypes for each fragment (stored as bitmasked int for performance purposes)
var Frag: Map < String , Int > = new Map < String , Int > ( ) ;
2023-08-15 18:27:26 +02:00
Frag . set ( " # " , XRF . ASSET | XRF . T_PREDEFINED_VIEW | XRF . PV_EXECUTE ) ;
2023-04-20 18:49:18 +02:00
Frag . set ( " s r c " , XRF . ASSET | XRF . T_URL ) ;
Frag . set ( " h r e f " , XRF . ASSET | XRF . T_URL | XRF . T_PREDEFINED_VIEW ) ;
2023-09-15 19:42:37 +02:00
Frag . set ( " t a g " , XRF . ASSET | XRF . T_STRING ) ;
2023-04-14 14:45:50 +02:00
2023-11-10 18:22:47 +01:00
// spatial category: query selector / object manipulation
2023-10-30 16:15:08 +01:00
Frag . set ( " p o s " , XRF . PV_OVERRIDE | XRF . T_VECTOR3 | XRF . T_STRING_OBJ | XRF . METADATA | XRF . NAVIGATOR ) ;
Frag . set ( " r o t " , XRF . QUERY_OPERATOR | XRF . PV_OVERRIDE | XRF . T_VECTOR3 | XRF . METADATA | XRF . NAVIGATOR ) ;
2023-04-14 14:45:50 +02:00
// category: animation
2023-11-02 16:49:18 +01:00
Frag . set ( " t " , XRF . ASSET | XRF . PV_OVERRIDE | XRF . T_FLOAT | XRF . T_VECTOR2 | XRF . T_STRING | XRF . NAVIGATOR | XRF . METADATA ) ;
Frag . set ( " t v " , XRF . ASSET | XRF . PV_OVERRIDE | XRF . T_FLOAT | XRF . T_VECTOR2 | XRF . T_VECTOR3 | XRF . NAVIGATOR | XRF . METADATA ) ;
2023-04-14 14:45:50 +02:00
// category: author / metadata
Frag . set ( " n a m e s p a c e " , XRF . ASSET | XRF . T_STRING ) ;
2023-04-27 22:45:19 +02:00
Frag . set ( " S P D X " , XRF . ASSET | XRF . T_STRING ) ;
2023-04-14 14:45:50 +02:00
Frag . set ( " u n i t " , XRF . ASSET | XRF . T_STRING ) ;
Frag . set ( " d e s c r i p t i o n " , XRF . ASSET | XRF . T_STRING ) ;
// category: multiparty
2023-10-30 16:15:08 +01:00
Frag . set ( " s e s s i o n " , XRF . ASSET | XRF . T_URL | XRF . PV_OVERRIDE | XRF . NAVIGATOR | XRF . METADATA | XRF . PROMPT ) ;
2023-04-14 14:45:50 +02:00
2023-04-02 21:19:03 +02:00
/ * *
2023-06-27 12:15:04 +02:00
* # Spec
2023-04-02 21:19:03 +02:00
*
2023-06-27 12:15:04 +02:00
* > version 1.0 .0 [ ! [ Actions S t a t u s ] ( https : //github.com/coderofsalvation/xrfragment/workflows/test/badge.svg)](https://github.com/coderofsalvation/xrfragment/actions) generated by `make doc` @ $(date +"%Y-%m-%dT%H:%M:%S%z")
*
* In c ase your programming language has no parser ( [ check h e r e ] ( https : //github.com/coderofsalvation/xrfragment/tree/main/dist)) you can [crosscompile it](https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml), or roll your own `Parser.parse(k,v,store)` using the spec:
2023-04-02 21:19:03 +02:00
* /
2023-04-20 14:12:50 +02:00
2023-06-27 12:15:04 +02:00
// 1. requirement: receive arguments: key (string), value (string), store (writable associative array/object)
2023-04-20 18:49:18 +02:00
// dynamic fragments cases: predefined views & assign/binds
2023-11-10 18:22:47 +01:00
var isPVDynamic: Bool = key . length > 0 && ! Frag . exists ( key ) ;
2023-08-15 18:27:26 +02:00
var isPVDefault: Bool = value . length == 0 && key . length > 0 && key == " # " ;
if ( isPVDynamic ) { //|| isPVDefault ){ // 1. add keys without values to store as [predefined view](predefined_view)
2023-11-16 14:50:57 +01:00
var v: XRF = new XRF ( key , XRF . PV_EXECUTE | XRF . NAVIGATOR , index ) ;
2023-11-10 18:22:47 +01:00
v . validate ( value ) ; // will fail but will parse multiple args for us (separated by |)
store . set ( keyClean . replace ( key , ' ' ) , v ) ;
2023-04-14 17:37:33 +02:00
return true ;
}
2023-04-20 14:12:50 +02:00
// regular fragments:
2023-11-16 14:50:57 +01:00
var v: XRF = new XRF ( key , Frag . get ( key ) , index ) ;
2023-06-27 09:43:10 +02:00
if ( Frag . exists ( key ) ) { // 1. check if fragment is official XR Fragment
2023-06-27 12:15:04 +02:00
if ( ! v . validate ( value ) ) { // 1. guess the type of the value (string,int,float,x,y,z,color,args,query)
2023-06-27 09:43:10 +02:00
trace ( " ⚠ f r a g m e n t ' " + key + " ' h a s i n c o m p a t i b l e v a l u e ( " + value + " ) " ) ; // 1. don't add to store if value-type is incorrect
2023-04-14 14:45:50 +02:00
return false ;
}
2023-06-27 09:43:10 +02:00
store . set ( key , v ) ; // 1. if valid, add to store
2023-05-05 18:53:42 +02:00
if ( debug ) trace ( " ✔ " + key + " : " + v . string ) ;
2023-09-14 10:21:16 +02:00
} e lse { // 1. expose (but mark) non-offical fragments too
2023-06-27 12:15:04 +02:00
if ( Std . isOfType ( value , String ) ) v . guessType ( v , value ) ;
2023-09-14 10:21:16 +02:00
v . noXRF = true ;
2023-11-10 18:22:47 +01:00
store . set ( keyClean . replace ( key , ' ' ) , v ) ;
2023-05-04 16:26:14 +02:00
}
2023-03-31 12:58:53 +02:00
return true ;
}
}
2023-06-27 12:15:04 +02:00
/ * *
* > icanhazcode ? yes , s e e [ P a r s e r . h x ] ( h t t p s : //github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/Parser.hx)
*
* # Tests
*
* the spec is tested with [ JSON u n i t t e s t s ] ( . / . . / src / spec ) consumed by [ Test . hx ] ( . / . . / src / Test . hx ) to cross - test all languages .
* /
2023-04-14 14:45:50 +02:00