2023-03-31 12:58:53 +02:00
package xrfragment ;
@ : expose // <- makes the class reachable from plain JavaScript
@ : keep // <- avoids accidental removal by dead code elimination
2023-03-31 14:40:24 +02:00
class Parser { // # XR Fragments (key/value params)
2023-03-31 16:35:54 +02:00
public static var error: String = " " ; //
2023-03-31 17:10:03 +02:00
// ```
// ⛁ = fragment in 3D asset-file (custom property)
// ⚂ = fragment in navigator URI (`document.location.href` e.g.)
@ : keep // ```
2023-03-31 12:58:53 +02:00
public static function parse ( key : String , value : String , resultMap : haxe . DynamicAccess < Dynamic > ) : Bool {
2023-03-31 17:10:03 +02:00
var Frag: Map < String , EReg > = new Map < String , EReg > ( ) ; // | param | type | scope | navigator override |category | notes |
// |---------|---------------|-------|--------------------|-------------------------|
Frag . set ( " p r i o " , Type . isInt ) ; // | prio | int (-10..1) | ⛁ | Asset loading / linking | #include doc/notes/prio.md |
2023-03-31 15:57:35 +02:00
2023-03-31 16:35:54 +02:00
Frag . set ( " p o s " , Type . isVector ) ; // | pos | 3D vector | HREF navigation/portals | |
//
2023-03-31 14:40:24 +02:00
// # XR Fragments parser
2023-03-31 16:35:54 +02:00
if ( Frag . exists ( key ) ) { // note: community parsers will prolly outperform this initial parser :)
2023-03-31 14:40:24 +02:00
if ( Frag . get ( key ) . match ( value ) ) { // > icanhazcode? yes, see [Parser.hx](./../src/xrfragment/Parser.hx)
var v: Value = new Value ( ) ; //
guessType ( v , value ) ; // the gist of it:
// process multiple/fallback values // 1. each key has a regex to validate its value-type (see regexes)
2023-03-31 12:58:53 +02:00
if ( value . split ( " | " ) . length > 1 ) { // 1. `|` is used to split multiple/fallback values
v . args = new Array < Value > ( ) ;
var args: Array < String > = value . split ( " | " ) ;
for ( i in 0 ... args . length ) {
var x: Value = new Value ( ) ;
guessType ( x , args [ i ] ) ;
v . args . push ( x ) ;
}
}
resultMap . set ( key , v ) ;
} e lse { trace ( " [ i ] 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 + " ) " ) ; return false ; }
} e lse { trace ( " [ i ] f r a g m e n t ' " + key + " ' d o e s n o t e x i s t o r h a s n o t y p e d e f i n e d ( y e t ) " ) ; return false ; }
return true ;
}
@ : keep
public static function guessType ( v : Value , str : String ) : Void {
v . string = str ;
if ( str . split ( " , " ) . length > 1 ) { // 1. `,` assumes 1D/2D/3D vector-values like x[,y[,z]]
var xyz: Array < String > = str . split ( " , " ) ; // 1. parseFloat(..) and parseInt(..) is applied to vector/float and int values
if ( xyz . length > 0 ) v . x = Std . parseFloat ( xyz [ 0 ] ) ; // 1. anything else will be treated as string-value
if ( xyz . length > 1 ) v . y = Std . parseFloat ( xyz [ 1 ] ) ; // 1. incompatible value-types will be dropped / not used
if ( xyz . length > 2 ) v . y = Std . parseFloat ( xyz [ 2 ] ) ; //
2023-03-31 16:35:54 +02:00
} // > the xrfragment specification should stay simple enough
2023-03-31 12:58:53 +02:00
// > for anyone to write a parser using either regexes or grammar/lexers
if ( Type . isColor . match ( str ) ) v . color = str ; // > therefore expressions/comprehensions are not supported (max wildcard/comparison operators for queries e.g.)
if ( Type . isFloat . match ( str ) ) v . float = Std . parseFloat ( str ) ;
if ( Type . isInt . match ( str ) ) v . int = Std . parseInt ( str ) ;
}
}
2023-03-31 16:35:54 +02:00
// # Parser Value types
//
// | type | info | format | example |
2023-03-31 12:58:53 +02:00
class Value { // |------|------|--------|----------------------------------|
2023-03-31 16:35:54 +02:00
public var x: Float ; // |vector| x,y,z| comma-separated | #pos=1,2,3 |
public var y: Float ; //
public var z: Float ; //
public var color: String ; // |string| color| FFFFFF (hex) | #fog=5m,FFAACC |
public var string: String ; // |string| | | #q=-sun |
public var int: Int ; // |int | | [-]x[xxxxx] | #price:>=100 |
public var float: Float ; // |float | | [-]x[.xxxx] (ieee)| #prio=-20
public var args: Array < Value > ; // |array | mixed| \|-separated | #pos=0,0,0|90,0,0 |
public function n e w ( ) { } //
// > rule for thumb: type-limitations will piggyback JSON limitations (IEEE floatsize e.g.)
2023-03-31 12:58:53 +02:00
}
2023-03-31 16:35:54 +02:00
// Regexes:
2023-03-31 12:58:53 +02:00
class Type { //
static public var isColor: EReg = ~/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/ ; // 1. hex colors are detected using regex `/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/`
static public var isInt: EReg = ~/^[0-9]+$/ ; // 1. integers are detected using regex `/^[0-9]+$/`
static public var isFloat: EReg = ~/^[0-9]+\.[0-9]+$/ ; // 1. floats are detected using regex `/^[0-9]+\.[0-9]+$/`
static public var isVector: EReg = ~/([,]+|\w)/ ; // 1. vectors are detected using regex `/[,]/` (but can also be an string referring to an entity-ID in the asset)
}
// # Tests
//
2023-03-31 13:32:44 +02:00
// the spec is tested with [JSON unittests](./../src/spec) consumed by [Test.hx](./../src/Test.hx) to cross-test all languages.