Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F65156854
PhutilTypeSpec.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Jun 1, 07:35
Size
41 KB
Mime Type
text/x-php
Expires
Mon, Jun 3, 07:35 (2 d)
Engine
blob
Format
Raw Data
Handle
18014153
Attached To
rPHU libphutil
PhutilTypeSpec.php
View Options
<?php
/**
* Perform type checks using a simple type grammar. The grammar supports the
* following basic types:
*
* int
* float
* bool
* string
* null
* callable
* regex
* wild
* AnyClassOrInterfaceName
*
* It supports the following complex types:
*
* list<type>
* map<type, type>
* type|type
*
* A type may be marked as optional by suffixing it with "?" or prefixing it
* with the word "optional":
*
* int?
* optional int
*
* A type may have a human-readable comment in parentheses, at the end:
*
* int (must be even)
*
* For example, these are valid type specifications:
*
* int|string
* map<int, bool>
* list<list<wild>>
* optional int
* string (uppercase)
*
*/
final
class
PhutilTypeSpec
extends
Phobject
{
private
$type
;
private
$subtypes
=
array
();
private
$optional
;
private
$comment
;
private
function
__construct
()
{}
public
function
getType
()
{
return
$this
->
type
;
}
public
function
check
(
$value
,
$name
=
null
)
{
switch
(
$this
->
type
)
{
case
'int'
:
if
(!
is_int
(
$value
))
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
break
;
case
'float'
:
if
(!
is_float
(
$value
))
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
break
;
case
'bool'
:
if
(!
is_bool
(
$value
))
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
break
;
case
'string'
:
if
(!
is_string
(
$value
))
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
break
;
case
'regex'
:
$trap
=
new
PhutilErrorTrap
();
$ok
=
@
preg_match
(
$value
,
''
);
$err
=
$trap
->
getErrorsAsString
();
$trap
->
destroy
();
if
(
$ok
===
false
)
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
,
$err
);
}
break
;
case
'null'
:
if
(!
is_null
(
$value
))
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
break
;
case
'list'
:
if
(!
is_array
(
$value
))
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
if
(
$value
&&
(
array_keys
(
$value
)
!==
range
(
0
,
count
(
$value
)
-
1
)))
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
try
{
foreach
(
$value
as
$v
)
{
$this
->
subtypes
[
0
]->
check
(
$v
);
}
}
catch
(
PhutilTypeCheckException
$ex
)
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
break
;
case
'map'
:
if
(!
is_array
(
$value
))
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
try
{
foreach
(
$value
as
$k
=>
$v
)
{
$this
->
subtypes
[
0
]->
check
(
$k
);
$this
->
subtypes
[
1
]->
check
(
$v
);
}
}
catch
(
PhutilTypeCheckException
$ex
)
{
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
break
;
case
'or'
:
foreach
(
$this
->
subtypes
as
$subtype
)
{
try
{
$subtype
->
check
(
$value
);
return
;
}
catch
(
PhutilTypeCheckException
$ex
)
{
// Ignore.
}
}
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
case
'wild'
:
return
;
default
:
if
(
class_exists
(
$this
->
type
,
false
))
{
if
(
$value
instanceof
$this
->
type
)
{
return
;
}
}
else
if
(
interface_exists
(
$this
->
type
,
false
))
{
if
(
$value
instanceof
$this
->
type
)
{
return
;
}
}
throw
new
PhutilTypeCheckException
(
$this
,
$value
,
$name
);
}
}
public
static
function
checkMap
(
array
$values
,
array
$types
)
{
$extra
=
array_diff_key
(
$values
,
$types
);
if
(
$extra
)
{
throw
new
PhutilTypeExtraParametersException
(
$extra
);
}
$missing
=
array
();
foreach
(
$types
as
$key
=>
$type
)
{
$types
[
$key
]
=
self
::
newFromString
(
$type
);
if
(!
array_key_exists
(
$key
,
$values
))
{
if
(!
$types
[
$key
]->
optional
)
{
$missing
[]
=
$key
;
}
}
}
if
(
$missing
)
{
throw
new
PhutilTypeMissingParametersException
(
$missing
);
}
foreach
(
$types
as
$key
=>
$type
)
{
if
(
array_key_exists
(
$key
,
$values
))
{
$type
->
check
(
$values
[
$key
],
$key
);
}
}
}
public
static
function
getCommonParentClass
(
$class_a
,
$class_b
)
{
// Make sure both classes are really classes.
try
{
if
(!
class_exists
(
$class_a
)
||
!
class_exists
(
$class_b
))
{
return
null
;
}
}
catch
(
PhutilMissingSymbolException
$ex
)
{
return
null
;
}
$ancestors_a
=
array
();
do
{
$ancestors_a
[]
=
$class_a
;
}
while
(
$class_a
=
get_parent_class
(
$class_a
));
$ancestors_b
=
array
();
do
{
$ancestors_b
[]
=
$class_b
;
}
while
(
$class_b
=
get_parent_class
(
$class_b
));
return
head
(
array_intersect
(
$ancestors_a
,
$ancestors_b
));
}
public
static
function
getTypeOf
(
$value
)
{
if
(
is_int
(
$value
))
{
return
'int'
;
}
else
if
(
is_float
(
$value
))
{
return
'float'
;
}
else
if
(
is_bool
(
$value
))
{
return
'bool'
;
}
else
if
(
is_string
(
$value
))
{
return
'string'
;
}
else
if
(
is_null
(
$value
))
{
return
'null'
;
}
else
if
(
is_object
(
$value
))
{
return
get_class
(
$value
);
}
else
if
(
is_array
(
$value
))
{
$vtype
=
self
::
getTypeOfVector
(
$value
);
if
(
$value
&&
(
array_keys
(
$value
)
===
range
(
0
,
count
(
$value
)
-
1
)))
{
return
'list<'
.
$vtype
.
'>'
;
}
else
{
$ktype
=
self
::
getTypeOfVector
(
array_keys
(
$value
));
return
"map<{$ktype}, {$vtype}>"
;
}
}
else
{
return
'wild'
;
}
}
private
static
function
getTypeOfVector
(
array
$vector
)
{
if
(!
$vector
)
{
return
'wild'
;
}
$type
=
null
;
foreach
(
$vector
as
$value
)
{
$vtype
=
self
::
getTypeOf
(
$value
);
if
(
$type
===
null
)
{
$type
=
$vtype
;
}
else
if
(
$type
===
$vtype
)
{
continue
;
}
else
{
$parent
=
self
::
getCommonParentClass
(
$type
,
$vtype
);
if
(
$parent
)
{
$type
=
$parent
;
}
else
{
return
'wild'
;
}
}
}
return
$type
;
}
public
function
toString
()
{
$sub
=
array
();
foreach
(
$this
->
subtypes
as
$subtype
)
{
$sub
[]
=
$subtype
->
toString
();
}
switch
(
$this
->
type
)
{
case
'map'
:
$string
=
'map<'
.
$sub
[
0
].
', '
.
$sub
[
1
].
'>'
;
break
;
case
'list'
:
$string
=
'list<'
.
$sub
[
0
].
'>'
;
break
;
case
'or'
:
$string
=
implode
(
'|'
,
$sub
);
break
;
default
:
$string
=
$this
->
type
;
break
;
}
if
(
$this
->
optional
)
{
$string
=
'optional '
.
$string
;
}
if
(
$this
->
comment
)
{
$string
.=
' ('
.
$this
->
comment
.
')'
;
}
return
$string
;
}
public
static
function
newFromString
(
$string
)
{
$lexer
=
self
::
getLexer
();
$tokens
=
$lexer
->
getTokens
(
$string
);
// Strip whitespace tokens.
foreach
(
$tokens
as
$key
=>
$token
)
{
$type
=
$token
[
0
];
if
(
$type
==
' '
)
{
unset
(
$tokens
[
$key
]);
}
}
$tokens
=
array_values
(
$tokens
);
$callback
=
array
(
__CLASS__
,
'didReduceTokens'
);
return
self
::
parseTokens
(
$tokens
,
$callback
);
}
public
static
function
didReduceTokens
(
$rule
,
$production
,
array
$tokens
)
{
switch
(
$rule
)
{
case
'start'
:
case
'some_type'
:
case
'not_or_type'
:
return
$tokens
[
0
];
case
'type'
:
if
(
$production
==
'yes'
)
{
$tokens
[
0
]->
optional
=
true
;
}
return
$tokens
[
0
];
case
'basic_type'
:
$obj
=
new
PhutilTypeSpec
();
$obj
->
type
=
$tokens
[
0
][
1
];
return
$obj
;
case
'or_type'
:
$l
=
$tokens
[
0
];
$r
=
$tokens
[
2
];
if
(
$l
->
type
==
'or'
)
{
if
(
$r
->
type
==
'or'
)
{
foreach
(
$r
->
subtypes
as
$subtype
)
{
$l
->
subtypes
[]
=
$subtype
;
}
}
else
{
$l
->
subtypes
[]
=
$r
;
}
return
$l
;
}
else
if
(
$r
->
type
==
'or'
)
{
$r
->
subtypes
[]
=
$l
;
return
$r
;
}
else
{
$obj
=
new
PhutilTypeSpec
();
$obj
->
type
=
'or'
;
$obj
->
subtypes
[]
=
$l
;
$obj
->
subtypes
[]
=
$r
;
return
$obj
;
}
break
;
case
'map_type'
:
$obj
=
new
PhutilTypeSpec
();
$obj
->
type
=
'map'
;
$obj
->
subtypes
[]
=
$tokens
[
2
];
$obj
->
subtypes
[]
=
$tokens
[
4
];
return
$obj
;
case
'list_type'
:
$obj
=
new
PhutilTypeSpec
();
$obj
->
type
=
'list'
;
$obj
->
subtypes
[]
=
$tokens
[
2
];
return
$obj
;
case
'maybe_optional'
:
if
(
$production
==
'yes'
)
{
$tokens
[
1
]->
optional
=
true
;
return
$tokens
[
1
];
}
else
{
return
$tokens
[
0
];
}
break
;
case
'maybe_comment'
:
if
(
$production
==
'yes'
)
{
$tokens
[
0
]->
comment
=
$tokens
[
1
];
}
return
$tokens
[
0
];
case
'comment'
:
return
$tokens
[
1
];
case
'comment_text'
:
$result
=
''
;
foreach
(
$tokens
as
$token
)
{
if
(
is_array
(
$token
))
{
$result
.=
$token
[
1
];
}
else
{
$result
.=
$token
;
}
}
return
$result
;
default
:
throw
new
Exception
(
pht
(
"Unhandled parser rule '%s'!"
,
$rule
));
}
}
private
static
function
getLexer
()
{
static
$lexer
;
if
(!
$lexer
)
{
$lexer
=
new
PhutilTypeLexer
();
}
return
$lexer
;
}
private
static
function
parseTokens
(
array
$tokens
,
$callback
)
{
// NOTE: This is automatically generated by the script
// `support/parser/generate-type-parser.php`.
return
PhutilParserGenerator
::
parseTokensWithTables
(
array
(
0
=>
array
(
'opt'
=>
array
(
0
=>
'S'
,
1
=>
3
,
),
'k'
=>
array
(
0
=>
'S'
,
1
=>
20
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
21
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
71
,
),
),
1
=>
array
(
'(end-of-file)'
=>
array
(
0
=>
'A'
,
),
),
2
=>
array
(
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'start'
,
1
=>
0
,
2
=>
1
,
),
),
),
3
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
20
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
21
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
71
,
),
),
4
=>
array
(
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'maybe_optional'
,
1
=>
'yes'
,
2
=>
2
,
),
),
),
5
=>
array
(
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'maybe_comment'
,
1
=>
'no'
,
2
=>
1
,
),
),
'('
=>
array
(
0
=>
'S'
,
1
=>
7
,
),
),
6
=>
array
(
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'maybe_comment'
,
1
=>
'yes'
,
2
=>
2
,
),
),
),
7
=>
array
(
'cm'
=>
array
(
0
=>
'S'
,
1
=>
11
,
),
),
8
=>
array
(
')'
=>
array
(
0
=>
'S'
,
1
=>
9
,
),
'cm'
=>
array
(
0
=>
'S'
,
1
=>
10
,
),
),
9
=>
array
(
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'comment'
,
1
=>
0
,
2
=>
3
,
),
),
),
10
=>
array
(
')'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'comment_text'
,
1
=>
0
,
2
=>
2
,
),
),
'cm'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'comment_text'
,
1
=>
0
,
2
=>
2
,
),
),
),
11
=>
array
(
')'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'comment_text'
,
1
=>
1
,
2
=>
1
,
),
),
'cm'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'comment_text'
,
1
=>
1
,
2
=>
1
,
),
),
),
12
=>
array
(
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'type'
,
1
=>
'no'
,
2
=>
1
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'type'
,
1
=>
'no'
,
2
=>
1
,
),
),
'?'
=>
array
(
0
=>
'S'
,
1
=>
13
,
),
),
13
=>
array
(
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'type'
,
1
=>
'yes'
,
2
=>
2
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'type'
,
1
=>
'yes'
,
2
=>
2
,
),
),
),
14
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
0
,
2
=>
1
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
0
,
2
=>
1
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'S'
,
1
=>
15
,
),
),
15
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
20
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
21
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
71
,
),
),
16
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
),
17
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
),
18
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
),
19
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
),
20
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
),
21
=>
array
(
'<'
=>
array
(
0
=>
'S'
,
1
=>
22
,
),
),
22
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
57
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
58
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
67
,
),
),
23
=>
array
(
','
=>
array
(
0
=>
'S'
,
1
=>
24
,
),
),
24
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
35
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
36
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
45
,
),
),
25
=>
array
(
'>'
=>
array
(
0
=>
'S'
,
1
=>
26
,
),
),
26
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
),
27
=>
array
(
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'type'
,
1
=>
'no'
,
2
=>
1
,
),
),
'?'
=>
array
(
0
=>
'S'
,
1
=>
28
,
),
),
28
=>
array
(
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'type'
,
1
=>
'yes'
,
2
=>
2
,
),
),
),
29
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
0
,
2
=>
1
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'S'
,
1
=>
30
,
),
),
30
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
35
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
36
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
45
,
),
),
31
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
),
32
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
),
33
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
),
34
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
),
35
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
),
36
=>
array
(
'<'
=>
array
(
0
=>
'S'
,
1
=>
37
,
),
),
37
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
57
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
58
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
67
,
),
),
38
=>
array
(
','
=>
array
(
0
=>
'S'
,
1
=>
39
,
),
),
39
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
35
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
36
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
45
,
),
),
40
=>
array
(
'>'
=>
array
(
0
=>
'S'
,
1
=>
41
,
),
),
41
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
),
42
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
1
,
2
=>
1
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
1
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'S'
,
1
=>
43
,
),
),
43
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
35
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
36
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
45
,
),
),
44
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
),
45
=>
array
(
'<'
=>
array
(
0
=>
'S'
,
1
=>
46
,
),
),
46
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
35
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
36
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
45
,
),
),
47
=>
array
(
'>'
=>
array
(
0
=>
'S'
,
1
=>
48
,
),
),
48
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
'>'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
),
49
=>
array
(
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'type'
,
1
=>
'no'
,
2
=>
1
,
),
),
'?'
=>
array
(
0
=>
'S'
,
1
=>
50
,
),
),
50
=>
array
(
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'type'
,
1
=>
'yes'
,
2
=>
2
,
),
),
),
51
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
0
,
2
=>
1
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'S'
,
1
=>
52
,
),
),
52
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
57
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
58
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
67
,
),
),
53
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
0
,
2
=>
3
,
),
),
),
54
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
0
,
2
=>
1
,
),
),
),
55
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
1
,
2
=>
1
,
),
),
),
56
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'not_or_type'
,
1
=>
2
,
2
=>
1
,
),
),
),
57
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'basic_type'
,
1
=>
0
,
2
=>
1
,
),
),
),
58
=>
array
(
'<'
=>
array
(
0
=>
'S'
,
1
=>
59
,
),
),
59
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
57
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
58
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
67
,
),
),
60
=>
array
(
','
=>
array
(
0
=>
'S'
,
1
=>
61
,
),
),
61
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
35
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
36
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
45
,
),
),
62
=>
array
(
'>'
=>
array
(
0
=>
'S'
,
1
=>
63
,
),
),
63
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'map_type'
,
1
=>
0
,
2
=>
6
,
),
),
),
64
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
1
,
2
=>
1
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
1
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'S'
,
1
=>
65
,
),
),
65
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
57
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
58
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
67
,
),
),
66
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
),
67
=>
array
(
'<'
=>
array
(
0
=>
'S'
,
1
=>
68
,
),
),
68
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
35
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
36
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
45
,
),
),
69
=>
array
(
'>'
=>
array
(
0
=>
'S'
,
1
=>
70
,
),
),
70
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
','
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
),
71
=>
array
(
'<'
=>
array
(
0
=>
'S'
,
1
=>
72
,
),
),
72
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
35
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
36
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
45
,
),
),
73
=>
array
(
'>'
=>
array
(
0
=>
'S'
,
1
=>
74
,
),
),
74
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'list_type'
,
1
=>
0
,
2
=>
4
,
),
),
),
75
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
1
,
2
=>
1
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
1
,
2
=>
1
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'some_type'
,
1
=>
1
,
2
=>
1
,
),
),
'|'
=>
array
(
0
=>
'S'
,
1
=>
76
,
),
),
76
=>
array
(
'k'
=>
array
(
0
=>
'S'
,
1
=>
20
,
),
'map'
=>
array
(
0
=>
'S'
,
1
=>
21
,
),
'list'
=>
array
(
0
=>
'S'
,
1
=>
71
,
),
),
77
=>
array
(
'?'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
'('
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
'|'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'or_type'
,
1
=>
1
,
2
=>
3
,
),
),
),
78
=>
array
(
'(end-of-file)'
=>
array
(
0
=>
'R'
,
1
=>
array
(
0
=>
'maybe_optional'
,
1
=>
'no'
,
2
=>
1
,
),
),
),
),
array
(
0
=>
array
(
'start'
=>
1
,
'maybe_optional'
=>
2
,
'maybe_comment'
=>
78
,
'type'
=>
5
,
'some_type'
=>
12
,
'or_type'
=>
14
,
'not_or_type'
=>
75
,
'basic_type'
=>
17
,
'map_type'
=>
18
,
'list_type'
=>
19
,
),
3
=>
array
(
'maybe_comment'
=>
4
,
'type'
=>
5
,
'some_type'
=>
12
,
'or_type'
=>
14
,
'not_or_type'
=>
75
,
'basic_type'
=>
17
,
'map_type'
=>
18
,
'list_type'
=>
19
,
),
5
=>
array
(
'comment'
=>
6
,
),
7
=>
array
(
'comment_text'
=>
8
,
),
15
=>
array
(
'not_or_type'
=>
16
,
'basic_type'
=>
17
,
'map_type'
=>
18
,
'list_type'
=>
19
,
),
22
=>
array
(
'type'
=>
23
,
'some_type'
=>
49
,
'or_type'
=>
51
,
'not_or_type'
=>
64
,
'basic_type'
=>
54
,
'map_type'
=>
55
,
'list_type'
=>
56
,
),
24
=>
array
(
'type'
=>
25
,
'some_type'
=>
27
,
'or_type'
=>
29
,
'not_or_type'
=>
42
,
'basic_type'
=>
32
,
'map_type'
=>
33
,
'list_type'
=>
34
,
),
30
=>
array
(
'not_or_type'
=>
31
,
'basic_type'
=>
32
,
'map_type'
=>
33
,
'list_type'
=>
34
,
),
37
=>
array
(
'type'
=>
38
,
'some_type'
=>
49
,
'or_type'
=>
51
,
'not_or_type'
=>
64
,
'basic_type'
=>
54
,
'map_type'
=>
55
,
'list_type'
=>
56
,
),
39
=>
array
(
'type'
=>
40
,
'some_type'
=>
27
,
'or_type'
=>
29
,
'not_or_type'
=>
42
,
'basic_type'
=>
32
,
'map_type'
=>
33
,
'list_type'
=>
34
,
),
43
=>
array
(
'not_or_type'
=>
44
,
'basic_type'
=>
32
,
'map_type'
=>
33
,
'list_type'
=>
34
,
),
46
=>
array
(
'type'
=>
47
,
'some_type'
=>
27
,
'or_type'
=>
29
,
'not_or_type'
=>
42
,
'basic_type'
=>
32
,
'map_type'
=>
33
,
'list_type'
=>
34
,
),
52
=>
array
(
'not_or_type'
=>
53
,
'basic_type'
=>
54
,
'map_type'
=>
55
,
'list_type'
=>
56
,
),
59
=>
array
(
'type'
=>
60
,
'some_type'
=>
49
,
'or_type'
=>
51
,
'not_or_type'
=>
64
,
'basic_type'
=>
54
,
'map_type'
=>
55
,
'list_type'
=>
56
,
),
61
=>
array
(
'type'
=>
62
,
'some_type'
=>
27
,
'or_type'
=>
29
,
'not_or_type'
=>
42
,
'basic_type'
=>
32
,
'map_type'
=>
33
,
'list_type'
=>
34
,
),
65
=>
array
(
'not_or_type'
=>
66
,
'basic_type'
=>
54
,
'map_type'
=>
55
,
'list_type'
=>
56
,
),
68
=>
array
(
'type'
=>
69
,
'some_type'
=>
27
,
'or_type'
=>
29
,
'not_or_type'
=>
42
,
'basic_type'
=>
32
,
'map_type'
=>
33
,
'list_type'
=>
34
,
),
72
=>
array
(
'type'
=>
73
,
'some_type'
=>
27
,
'or_type'
=>
29
,
'not_or_type'
=>
42
,
'basic_type'
=>
32
,
'map_type'
=>
33
,
'list_type'
=>
34
,
),
76
=>
array
(
'not_or_type'
=>
77
,
'basic_type'
=>
17
,
'map_type'
=>
18
,
'list_type'
=>
19
,
),
),
'(end-of-file)'
,
$tokens
,
$callback
);
}
}
Event Timeline
Log In to Comment