Commit c4245e3d by Jared Roesch Committed by eqy

[Relay][Prelude] Use the Relay parser to define the Relay prelude (#3043)

* Add ability to load Prelude from disk

* Port over id

* Define compose

* Linting errors and style changes

* Eliminate unnecessary parens

* Rename identType to typeIdent (makes more sense)

* Another unnecessary paren

* Bump the version number for the text format

* Ensure .rly (Relay text files) are permitted

* Correct release number and simplify grammar rule

* Correct load_prelude docstring

* Corrections to _parser

* Add Apache headers to prelude source file

* Remove test_prelude (redundant)

* Correct misleading error message

* Add check that parser is enabled in Prelude

* Commit pre-generated parser, ensure generated files are treated as binaries, and have parser tests always fire

* Permit parser files and git attributes files

* Exclude gitattributes and parser files from apache check

* Another attempt at appeasing Apache audit checker

* Corrections to rat-excludes

* Apache should be truly appeased now

* Ignore Relay parser files by name

* Mark parser files as generated so they don't show up on Github

* Add parsing helper function for tests

* Mark parser files as not detectable
parent 70041c48
......@@ -242,10 +242,12 @@ class ParseTreeToRelayIR(RelayVisitor):
self.visit_list(ctx.defn())
return self.module
return self.visit(ctx.expr())
if ctx.expr():
return self.visit(ctx.expr())
# Exprs
return self.module
# Exprs
def visitOpIdent(self, ctx):
# type: (RelayParser.OpIdentContext) -> op.Op
return op.get(ctx.CNAME().getText())
......@@ -368,14 +370,25 @@ class ParseTreeToRelayIR(RelayVisitor):
self.enter_var_scope()
# Capture type params in params.
self.enter_type_param_scope()
type_params = ctx.typeParamSeq()
if type_params is not None:
type_params = type_params.ident()
assert type_params
for ty_param in type_params:
name = ty_param.getText()
self.mk_typ(name, ty.Kind.Type)
var_list, attr_list = self.visit(ctx.argList())
ret_type = self.getType_(ctx.type_())
body = self.visit(ctx.body())
# NB(@jroesch): you must stay in the type parameter scope until
# after you exit the body, you can reference the type parameters
# of your parent scopes.
type_params = list(self.exit_type_param_scope())
if type_params:
_, type_params = zip(*type_params)
body = self.visit(ctx.body())
self.exit_var_scope()
attrs = tvm.make.node("DictAttrs", **attr_list) if attr_list is not None else None
......@@ -453,16 +466,23 @@ class ParseTreeToRelayIR(RelayVisitor):
# type (RelayParser.IncompleteTypeContext) -> None:
return None
def visitIdentType(self, ctx):
# type: (RelayParser.IdentTypeContext) -> Union[ty.TensorType, str]
ident_type = ctx.CNAME().getText()
def visitTypeIdent(self, ctx):
# type: (RelayParser.TypeIdentContext) -> Union[ty.TensorType, str]
'''
Handle type identifier.
'''
type_ident = ctx.CNAME().getText()
# look through all type prefixes for a match
# Look through all type prefixes for a match
for type_prefix in TYPE_PREFIXES:
if ident_type.startswith(type_prefix):
return ty.scalar_type(ident_type)
if type_ident.startswith(type_prefix):
return ty.scalar_type(type_ident)
type_param = lookup(self.type_param_scopes, type_ident)
if type_param is not None:
return type_param
raise ParseError("Unknown builtin type: {}".format(ident_type))
raise ParseError("Unknown builtin type: {}".format(type_ident))
# def visitCallType(self, ctx):
# # type: (RelayParser.CallTypeContext) -> Union[expr.Expr, ty.TensorType]
......
......@@ -19,7 +19,7 @@
grammar Relay;
SEMVER: 'v0.0.1' ;
SEMVER: 'v0.0.2' ;
// Lexing
// comments
......@@ -111,8 +111,8 @@ expr
// | 'debug' # debug
;
func: 'fn' '(' argList ')' ('->' type_)? body ;
defn: 'def' ident '(' argList ')' ('->' type_)? body ;
func: 'fn' typeParamSeq? '(' argList ')' ('->' type_)? body ;
defn: 'def' ident typeParamSeq? '(' argList ')' ('->' type_)? body ;
argList
: varList
......@@ -132,15 +132,20 @@ attr: CNAME '=' expr ;
// relations: 'where' relation (',' relation)* ;
// relation: ident '(' (type_ (',' type_)*)? ')' ;
typeParamSeq
: '[' ']'
| '[' ident (',' ident)* ']'
;
type_
: '(' ')' # tupleType
| '(' type_ ',' ')' # tupleType
| '(' type_ (',' type_)+ ')' # tupleType
| identType # identTypeType
| typeIdent # typeIdentType
| 'Tensor' '[' shapeSeq ',' type_ ']' # tensorType
// currently unused
// | identType '[' (type_ (',' type_)*)? ']' # callType
| 'fn' '(' (type_ (',' type_)*)? ')' '->' type_ # funcType
// | typeIdent '[' (type_ (',' type_)*)? ']' # callType
| 'fn' typeParamSeq? '(' (type_ (',' type_)*)? ')' '->' type_ # funcType
| '_' # incompleteType
| NAT # intType
;
......@@ -158,7 +163,7 @@ shape
| NAT # intShape
;
identType: CNAME ;
typeIdent : CNAME ;
// int8, int16, int32, int64
// uint8, uint16, uint32, uint64
// float16, float32, float64
......
Relay* binary
Relay* linguist-generated=true
Relay* linguist-detectable=false
\ No newline at end of file
T__0=1
T__1=2
T__2=3
T__3=4
T__4=5
T__5=6
T__6=7
T__7=8
T__8=9
T__9=10
T__10=11
T__11=12
T__12=13
T__13=14
T__14=15
T__15=16
T__16=17
T__17=18
SEMVER=19
WS=20
LINE_COMMENT=21
COMMENT=22
MUL=23
DIV=24
ADD=25
SUB=26
LT=27
GT=28
LE=29
GE=30
EQ=31
NE=32
GLOBAL_VAR=33
LOCAL_VAR=34
GRAPH_VAR=35
MUT=36
BOOL_LIT=37
FLOAT=38
NAT=39
CNAME=40
'('=1
')'=2
','=3
'['=4
']'=5
'if'=6
'else'=7
'let'=8
'='=9
';'=10
'{'=11
'}'=12
'fn'=13
'->'=14
'def'=15
':'=16
'Tensor'=17
'_'=18
'v0.0.2'=19
'*'=23
'/'=24
'+'=25
'-'=26
'<'=27
'>'=28
'<='=29
'>='=30
'=='=31
'!='=32
'mut'=36
token literal names:
null
'('
')'
','
'['
']'
'if'
'else'
'let'
'='
';'
'{'
'}'
'fn'
'->'
'def'
':'
'Tensor'
'_'
'v0.0.2'
null
null
null
'*'
'/'
'+'
'-'
'<'
'>'
'<='
'>='
'=='
'!='
null
null
null
'mut'
null
null
null
null
token symbolic names:
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
SEMVER
WS
LINE_COMMENT
COMMENT
MUL
DIV
ADD
SUB
LT
GT
LE
GE
EQ
NE
GLOBAL_VAR
LOCAL_VAR
GRAPH_VAR
MUT
BOOL_LIT
FLOAT
NAT
CNAME
rule names:
T__0
T__1
T__2
T__3
T__4
T__5
T__6
T__7
T__8
T__9
T__10
T__11
T__12
T__13
T__14
T__15
T__16
T__17
SEMVER
WS
LINE_COMMENT
COMMENT
MUL
DIV
ADD
SUB
LT
GT
LE
GE
EQ
NE
GLOBAL_VAR
LOCAL_VAR
GRAPH_VAR
MUT
BOOL_LIT
FLOAT
NAT
EXP
CNAME
LETTER
DIGIT
channel names:
DEFAULT_TOKEN_CHANNEL
HIDDEN
mode names:
DEFAULT_MODE
atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 42, 267, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 6, 21, 149, 10, 21, 13, 21, 14, 21, 150, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 7, 22, 159, 10, 22, 12, 22, 14, 22, 162, 11, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 172, 10, 23, 12, 23, 14, 23, 175, 11, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 5, 38, 228, 10, 38, 3, 39, 3, 39, 3, 39, 3, 39, 5, 39, 234, 10, 39, 3, 39, 3, 39, 3, 39, 5, 39, 239, 10, 39, 3, 40, 6, 40, 242, 10, 40, 13, 40, 14, 40, 243, 3, 41, 3, 41, 5, 41, 248, 10, 41, 3, 41, 3, 41, 3, 42, 3, 42, 5, 42, 254, 10, 42, 3, 42, 3, 42, 3, 42, 7, 42, 259, 10, 42, 12, 42, 14, 42, 262, 11, 42, 3, 43, 3, 43, 3, 44, 3, 44, 4, 160, 173, 2, 45, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 2, 83, 42, 85, 2, 87, 2, 3, 2, 7, 5, 2, 11, 12, 15, 15, 34, 34, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45, 47, 47, 4, 2, 67, 92, 99, 124, 3, 2, 50, 59, 2, 275, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 3, 89, 3, 2, 2, 2, 5, 91, 3, 2, 2, 2, 7, 93, 3, 2, 2, 2, 9, 95, 3, 2, 2, 2, 11, 97, 3, 2, 2, 2, 13, 99, 3, 2, 2, 2, 15, 102, 3, 2, 2, 2, 17, 107, 3, 2, 2, 2, 19, 111, 3, 2, 2, 2, 21, 113, 3, 2, 2, 2, 23, 115, 3, 2, 2, 2, 25, 117, 3, 2, 2, 2, 27, 119, 3, 2, 2, 2, 29, 122, 3, 2, 2, 2, 31, 125, 3, 2, 2, 2, 33, 129, 3, 2, 2, 2, 35, 131, 3, 2, 2, 2, 37, 138, 3, 2, 2, 2, 39, 140, 3, 2, 2, 2, 41, 148, 3, 2, 2, 2, 43, 154, 3, 2, 2, 2, 45, 167, 3, 2, 2, 2, 47, 181, 3, 2, 2, 2, 49, 183, 3, 2, 2, 2, 51, 185, 3, 2, 2, 2, 53, 187, 3, 2, 2, 2, 55, 189, 3, 2, 2, 2, 57, 191, 3, 2, 2, 2, 59, 193, 3, 2, 2, 2, 61, 196, 3, 2, 2, 2, 63, 199, 3, 2, 2, 2, 65, 202, 3, 2, 2, 2, 67, 205, 3, 2, 2, 2, 69, 208, 3, 2, 2, 2, 71, 211, 3, 2, 2, 2, 73, 214, 3, 2, 2, 2, 75, 227, 3, 2, 2, 2, 77, 238, 3, 2, 2, 2, 79, 241, 3, 2, 2, 2, 81, 245, 3, 2, 2, 2, 83, 253, 3, 2, 2, 2, 85, 263, 3, 2, 2, 2, 87, 265, 3, 2, 2, 2, 89, 90, 7, 42, 2, 2, 90, 4, 3, 2, 2, 2, 91, 92, 7, 43, 2, 2, 92, 6, 3, 2, 2, 2, 93, 94, 7, 46, 2, 2, 94, 8, 3, 2, 2, 2, 95, 96, 7, 93, 2, 2, 96, 10, 3, 2, 2, 2, 97, 98, 7, 95, 2, 2, 98, 12, 3, 2, 2, 2, 99, 100, 7, 107, 2, 2, 100, 101, 7, 104, 2, 2, 101, 14, 3, 2, 2, 2, 102, 103, 7, 103, 2, 2, 103, 104, 7, 110, 2, 2, 104, 105, 7, 117, 2, 2, 105, 106, 7, 103, 2, 2, 106, 16, 3, 2, 2, 2, 107, 108, 7, 110, 2, 2, 108, 109, 7, 103, 2, 2, 109, 110, 7, 118, 2, 2, 110, 18, 3, 2, 2, 2, 111, 112, 7, 63, 2, 2, 112, 20, 3, 2, 2, 2, 113, 114, 7, 61, 2, 2, 114, 22, 3, 2, 2, 2, 115, 116, 7, 125, 2, 2, 116, 24, 3, 2, 2, 2, 117, 118, 7, 127, 2, 2, 118, 26, 3, 2, 2, 2, 119, 120, 7, 104, 2, 2, 120, 121, 7, 112, 2, 2, 121, 28, 3, 2, 2, 2, 122, 123, 7, 47, 2, 2, 123, 124, 7, 64, 2, 2, 124, 30, 3, 2, 2, 2, 125, 126, 7, 102, 2, 2, 126, 127, 7, 103, 2, 2, 127, 128, 7, 104, 2, 2, 128, 32, 3, 2, 2, 2, 129, 130, 7, 60, 2, 2, 130, 34, 3, 2, 2, 2, 131, 132, 7, 86, 2, 2, 132, 133, 7, 103, 2, 2, 133, 134, 7, 112, 2, 2, 134, 135, 7, 117, 2, 2, 135, 136, 7, 113, 2, 2, 136, 137, 7, 116, 2, 2, 137, 36, 3, 2, 2, 2, 138, 139, 7, 97, 2, 2, 139, 38, 3, 2, 2, 2, 140, 141, 7, 120, 2, 2, 141, 142, 7, 50, 2, 2, 142, 143, 7, 48, 2, 2, 143, 144, 7, 50, 2, 2, 144, 145, 7, 48, 2, 2, 145, 146, 7, 52, 2, 2, 146, 40, 3, 2, 2, 2, 147, 149, 9, 2, 2, 2, 148, 147, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 8, 21, 2, 2, 153, 42, 3, 2, 2, 2, 154, 155, 7, 49, 2, 2, 155, 156, 7, 49, 2, 2, 156, 160, 3, 2, 2, 2, 157, 159, 11, 2, 2, 2, 158, 157, 3, 2, 2, 2, 159, 162, 3, 2, 2, 2, 160, 161, 3, 2, 2, 2, 160, 158, 3, 2, 2, 2, 161, 163, 3, 2, 2, 2, 162, 160, 3, 2, 2, 2, 163, 164, 7, 12, 2, 2, 164, 165, 3, 2, 2, 2, 165, 166, 8, 22, 2, 2, 166, 44, 3, 2, 2, 2, 167, 168, 7, 49, 2, 2, 168, 169, 7, 44, 2, 2, 169, 173, 3, 2, 2, 2, 170, 172, 11, 2, 2, 2, 171, 170, 3, 2, 2, 2, 172, 175, 3, 2, 2, 2, 173, 174, 3, 2, 2, 2, 173, 171, 3, 2, 2, 2, 174, 176, 3, 2, 2, 2, 175, 173, 3, 2, 2, 2, 176, 177, 7, 44, 2, 2, 177, 178, 7, 49, 2, 2, 178, 179, 3, 2, 2, 2, 179, 180, 8, 23, 2, 2, 180, 46, 3, 2, 2, 2, 181, 182, 7, 44, 2, 2, 182, 48, 3, 2, 2, 2, 183, 184, 7, 49, 2, 2, 184, 50, 3, 2, 2, 2, 185, 186, 7, 45, 2, 2, 186, 52, 3, 2, 2, 2, 187, 188, 7, 47, 2, 2, 188, 54, 3, 2, 2, 2, 189, 190, 7, 62, 2, 2, 190, 56, 3, 2, 2, 2, 191, 192, 7, 64, 2, 2, 192, 58, 3, 2, 2, 2, 193, 194, 7, 62, 2, 2, 194, 195, 7, 63, 2, 2, 195, 60, 3, 2, 2, 2, 196, 197, 7, 64, 2, 2, 197, 198, 7, 63, 2, 2, 198, 62, 3, 2, 2, 2, 199, 200, 7, 63, 2, 2, 200, 201, 7, 63, 2, 2, 201, 64, 3, 2, 2, 2, 202, 203, 7, 35, 2, 2, 203, 204, 7, 63, 2, 2, 204, 66, 3, 2, 2, 2, 205, 206, 7, 66, 2, 2, 206, 207, 5, 83, 42, 2, 207, 68, 3, 2, 2, 2, 208, 209, 7, 39, 2, 2, 209, 210, 5, 83, 42, 2, 210, 70, 3, 2, 2, 2, 211, 212, 7, 39, 2, 2, 212, 213, 5, 79, 40, 2, 213, 72, 3, 2, 2, 2, 214, 215, 7, 111, 2, 2, 215, 216, 7, 119, 2, 2, 216, 217, 7, 118, 2, 2, 217, 74, 3, 2, 2, 2, 218, 219, 7, 86, 2, 2, 219, 220, 7, 116, 2, 2, 220, 221, 7, 119, 2, 2, 221, 228, 7, 103, 2, 2, 222, 223, 7, 72, 2, 2, 223, 224, 7, 99, 2, 2, 224, 225, 7, 110, 2, 2, 225, 226, 7, 117, 2, 2, 226, 228, 7, 103, 2, 2, 227, 218, 3, 2, 2, 2, 227, 222, 3, 2, 2, 2, 228, 76, 3, 2, 2, 2, 229, 230, 5, 79, 40, 2, 230, 231, 7, 48, 2, 2, 231, 233, 5, 79, 40, 2, 232, 234, 5, 81, 41, 2, 233, 232, 3, 2, 2, 2, 233, 234, 3, 2, 2, 2, 234, 239, 3, 2, 2, 2, 235, 236, 5, 79, 40, 2, 236, 237, 5, 81, 41, 2, 237, 239, 3, 2, 2, 2, 238, 229, 3, 2, 2, 2, 238, 235, 3, 2, 2, 2, 239, 78, 3, 2, 2, 2, 240, 242, 5, 87, 44, 2, 241, 240, 3, 2, 2, 2, 242, 243, 3, 2, 2, 2, 243, 241, 3, 2, 2, 2, 243, 244, 3, 2, 2, 2, 244, 80, 3, 2, 2, 2, 245, 247, 9, 3, 2, 2, 246, 248, 9, 4, 2, 2, 247, 246, 3, 2, 2, 2, 247, 248, 3, 2, 2, 2, 248, 249, 3, 2, 2, 2, 249, 250, 5, 79, 40, 2, 250, 82, 3, 2, 2, 2, 251, 254, 7, 97, 2, 2, 252, 254, 5, 85, 43, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 260, 3, 2, 2, 2, 255, 259, 7, 97, 2, 2, 256, 259, 5, 85, 43, 2, 257, 259, 5, 87, 44, 2, 258, 255, 3, 2, 2, 2, 258, 256, 3, 2, 2, 2, 258, 257, 3, 2, 2, 2, 259, 262, 3, 2, 2, 2, 260, 258, 3, 2, 2, 2, 260, 261, 3, 2, 2, 2, 261, 84, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 263, 264, 9, 5, 2, 2, 264, 86, 3, 2, 2, 2, 265, 266, 9, 6, 2, 2, 266, 88, 3, 2, 2, 2, 14, 2, 150, 160, 173, 227, 233, 238, 243, 247, 253, 258, 260, 3, 8, 2, 2]
\ No newline at end of file
T__0=1
T__1=2
T__2=3
T__3=4
T__4=5
T__5=6
T__6=7
T__7=8
T__8=9
T__9=10
T__10=11
T__11=12
T__12=13
T__13=14
T__14=15
T__15=16
T__16=17
T__17=18
SEMVER=19
WS=20
LINE_COMMENT=21
COMMENT=22
MUL=23
DIV=24
ADD=25
SUB=26
LT=27
GT=28
LE=29
GE=30
EQ=31
NE=32
GLOBAL_VAR=33
LOCAL_VAR=34
GRAPH_VAR=35
MUT=36
BOOL_LIT=37
FLOAT=38
NAT=39
CNAME=40
'('=1
')'=2
','=3
'['=4
']'=5
'if'=6
'else'=7
'let'=8
'='=9
';'=10
'{'=11
'}'=12
'fn'=13
'->'=14
'def'=15
':'=16
'Tensor'=17
'_'=18
'v0.0.2'=19
'*'=23
'/'=24
'+'=25
'-'=26
'<'=27
'>'=28
'<='=29
'>='=30
'=='=31
'!='=32
'mut'=36
# Generated from /home/sslyu/tvm/python/tvm/relay/grammar/Relay.g4 by ANTLR 4.7.2
from antlr4 import *
# This class defines a complete generic visitor for a parse tree produced by RelayParser.
class RelayVisitor(ParseTreeVisitor):
# Visit a parse tree produced by RelayParser#opIdent.
def visitOpIdent(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#prog.
def visitProg(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#identExpr.
def visitIdentExpr(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#call.
def visitCall(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#neg.
def visitNeg(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#tuple.
def visitTuple(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#parens.
def visitParens(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#funcExpr.
def visitFuncExpr(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#scalarExpr.
def visitScalarExpr(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#let.
def visitLet(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#tensor.
def visitTensor(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#ifElse.
def visitIfElse(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#graph.
def visitGraph(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#binOp.
def visitBinOp(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#func.
def visitFunc(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#defn.
def visitDefn(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#argList.
def visitArgList(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#varList.
def visitVarList(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#var.
def visitVar(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#attrList.
def visitAttrList(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#attr.
def visitAttr(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#typeParamSeq.
def visitTypeParamSeq(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#tupleType.
def visitTupleType(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#typeIdentType.
def visitTypeIdentType(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#tensorType.
def visitTensorType(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#funcType.
def visitFuncType(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#incompleteType.
def visitIncompleteType(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#intType.
def visitIntType(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#shapeSeq.
def visitShapeSeq(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#parensShape.
def visitParensShape(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#intShape.
def visitIntShape(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#typeIdent.
def visitTypeIdent(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#body.
def visitBody(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#scalarFloat.
def visitScalarFloat(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#scalarInt.
def visitScalarInt(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#scalarBool.
def visitScalarBool(self, ctx):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#ident.
def visitIdent(self, ctx):
return self.visitChildren(ctx)
Relay* binary
Relay* linguist-generated=true
Relay* linguist-detectable=false
\ No newline at end of file
T__0=1
T__1=2
T__2=3
T__3=4
T__4=5
T__5=6
T__6=7
T__7=8
T__8=9
T__9=10
T__10=11
T__11=12
T__12=13
T__13=14
T__14=15
T__15=16
T__16=17
T__17=18
SEMVER=19
WS=20
LINE_COMMENT=21
COMMENT=22
MUL=23
DIV=24
ADD=25
SUB=26
LT=27
GT=28
LE=29
GE=30
EQ=31
NE=32
GLOBAL_VAR=33
LOCAL_VAR=34
GRAPH_VAR=35
MUT=36
BOOL_LIT=37
FLOAT=38
NAT=39
CNAME=40
'('=1
')'=2
','=3
'['=4
']'=5
'if'=6
'else'=7
'let'=8
'='=9
';'=10
'{'=11
'}'=12
'fn'=13
'->'=14
'def'=15
':'=16
'Tensor'=17
'_'=18
'v0.0.2'=19
'*'=23
'/'=24
'+'=25
'-'=26
'<'=27
'>'=28
'<='=29
'>='=30
'=='=31
'!='=32
'mut'=36
token literal names:
null
'('
')'
','
'['
']'
'if'
'else'
'let'
'='
';'
'{'
'}'
'fn'
'->'
'def'
':'
'Tensor'
'_'
'v0.0.2'
null
null
null
'*'
'/'
'+'
'-'
'<'
'>'
'<='
'>='
'=='
'!='
null
null
null
'mut'
null
null
null
null
token symbolic names:
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
SEMVER
WS
LINE_COMMENT
COMMENT
MUL
DIV
ADD
SUB
LT
GT
LE
GE
EQ
NE
GLOBAL_VAR
LOCAL_VAR
GRAPH_VAR
MUT
BOOL_LIT
FLOAT
NAT
CNAME
rule names:
T__0
T__1
T__2
T__3
T__4
T__5
T__6
T__7
T__8
T__9
T__10
T__11
T__12
T__13
T__14
T__15
T__16
T__17
SEMVER
WS
LINE_COMMENT
COMMENT
MUL
DIV
ADD
SUB
LT
GT
LE
GE
EQ
NE
GLOBAL_VAR
LOCAL_VAR
GRAPH_VAR
MUT
BOOL_LIT
FLOAT
NAT
EXP
CNAME
LETTER
DIGIT
channel names:
DEFAULT_TOKEN_CHANNEL
HIDDEN
mode names:
DEFAULT_MODE
atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 42, 267, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 6, 21, 149, 10, 21, 13, 21, 14, 21, 150, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 7, 22, 159, 10, 22, 12, 22, 14, 22, 162, 11, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 172, 10, 23, 12, 23, 14, 23, 175, 11, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 5, 38, 228, 10, 38, 3, 39, 3, 39, 3, 39, 3, 39, 5, 39, 234, 10, 39, 3, 39, 3, 39, 3, 39, 5, 39, 239, 10, 39, 3, 40, 6, 40, 242, 10, 40, 13, 40, 14, 40, 243, 3, 41, 3, 41, 5, 41, 248, 10, 41, 3, 41, 3, 41, 3, 42, 3, 42, 5, 42, 254, 10, 42, 3, 42, 3, 42, 3, 42, 7, 42, 259, 10, 42, 12, 42, 14, 42, 262, 11, 42, 3, 43, 3, 43, 3, 44, 3, 44, 4, 160, 173, 2, 45, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 2, 83, 42, 85, 2, 87, 2, 3, 2, 7, 5, 2, 11, 12, 15, 15, 34, 34, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45, 47, 47, 4, 2, 67, 92, 99, 124, 3, 2, 50, 59, 2, 275, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 3, 89, 3, 2, 2, 2, 5, 91, 3, 2, 2, 2, 7, 93, 3, 2, 2, 2, 9, 95, 3, 2, 2, 2, 11, 97, 3, 2, 2, 2, 13, 99, 3, 2, 2, 2, 15, 102, 3, 2, 2, 2, 17, 107, 3, 2, 2, 2, 19, 111, 3, 2, 2, 2, 21, 113, 3, 2, 2, 2, 23, 115, 3, 2, 2, 2, 25, 117, 3, 2, 2, 2, 27, 119, 3, 2, 2, 2, 29, 122, 3, 2, 2, 2, 31, 125, 3, 2, 2, 2, 33, 129, 3, 2, 2, 2, 35, 131, 3, 2, 2, 2, 37, 138, 3, 2, 2, 2, 39, 140, 3, 2, 2, 2, 41, 148, 3, 2, 2, 2, 43, 154, 3, 2, 2, 2, 45, 167, 3, 2, 2, 2, 47, 181, 3, 2, 2, 2, 49, 183, 3, 2, 2, 2, 51, 185, 3, 2, 2, 2, 53, 187, 3, 2, 2, 2, 55, 189, 3, 2, 2, 2, 57, 191, 3, 2, 2, 2, 59, 193, 3, 2, 2, 2, 61, 196, 3, 2, 2, 2, 63, 199, 3, 2, 2, 2, 65, 202, 3, 2, 2, 2, 67, 205, 3, 2, 2, 2, 69, 208, 3, 2, 2, 2, 71, 211, 3, 2, 2, 2, 73, 214, 3, 2, 2, 2, 75, 227, 3, 2, 2, 2, 77, 238, 3, 2, 2, 2, 79, 241, 3, 2, 2, 2, 81, 245, 3, 2, 2, 2, 83, 253, 3, 2, 2, 2, 85, 263, 3, 2, 2, 2, 87, 265, 3, 2, 2, 2, 89, 90, 7, 42, 2, 2, 90, 4, 3, 2, 2, 2, 91, 92, 7, 43, 2, 2, 92, 6, 3, 2, 2, 2, 93, 94, 7, 46, 2, 2, 94, 8, 3, 2, 2, 2, 95, 96, 7, 93, 2, 2, 96, 10, 3, 2, 2, 2, 97, 98, 7, 95, 2, 2, 98, 12, 3, 2, 2, 2, 99, 100, 7, 107, 2, 2, 100, 101, 7, 104, 2, 2, 101, 14, 3, 2, 2, 2, 102, 103, 7, 103, 2, 2, 103, 104, 7, 110, 2, 2, 104, 105, 7, 117, 2, 2, 105, 106, 7, 103, 2, 2, 106, 16, 3, 2, 2, 2, 107, 108, 7, 110, 2, 2, 108, 109, 7, 103, 2, 2, 109, 110, 7, 118, 2, 2, 110, 18, 3, 2, 2, 2, 111, 112, 7, 63, 2, 2, 112, 20, 3, 2, 2, 2, 113, 114, 7, 61, 2, 2, 114, 22, 3, 2, 2, 2, 115, 116, 7, 125, 2, 2, 116, 24, 3, 2, 2, 2, 117, 118, 7, 127, 2, 2, 118, 26, 3, 2, 2, 2, 119, 120, 7, 104, 2, 2, 120, 121, 7, 112, 2, 2, 121, 28, 3, 2, 2, 2, 122, 123, 7, 47, 2, 2, 123, 124, 7, 64, 2, 2, 124, 30, 3, 2, 2, 2, 125, 126, 7, 102, 2, 2, 126, 127, 7, 103, 2, 2, 127, 128, 7, 104, 2, 2, 128, 32, 3, 2, 2, 2, 129, 130, 7, 60, 2, 2, 130, 34, 3, 2, 2, 2, 131, 132, 7, 86, 2, 2, 132, 133, 7, 103, 2, 2, 133, 134, 7, 112, 2, 2, 134, 135, 7, 117, 2, 2, 135, 136, 7, 113, 2, 2, 136, 137, 7, 116, 2, 2, 137, 36, 3, 2, 2, 2, 138, 139, 7, 97, 2, 2, 139, 38, 3, 2, 2, 2, 140, 141, 7, 120, 2, 2, 141, 142, 7, 50, 2, 2, 142, 143, 7, 48, 2, 2, 143, 144, 7, 50, 2, 2, 144, 145, 7, 48, 2, 2, 145, 146, 7, 52, 2, 2, 146, 40, 3, 2, 2, 2, 147, 149, 9, 2, 2, 2, 148, 147, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 8, 21, 2, 2, 153, 42, 3, 2, 2, 2, 154, 155, 7, 49, 2, 2, 155, 156, 7, 49, 2, 2, 156, 160, 3, 2, 2, 2, 157, 159, 11, 2, 2, 2, 158, 157, 3, 2, 2, 2, 159, 162, 3, 2, 2, 2, 160, 161, 3, 2, 2, 2, 160, 158, 3, 2, 2, 2, 161, 163, 3, 2, 2, 2, 162, 160, 3, 2, 2, 2, 163, 164, 7, 12, 2, 2, 164, 165, 3, 2, 2, 2, 165, 166, 8, 22, 2, 2, 166, 44, 3, 2, 2, 2, 167, 168, 7, 49, 2, 2, 168, 169, 7, 44, 2, 2, 169, 173, 3, 2, 2, 2, 170, 172, 11, 2, 2, 2, 171, 170, 3, 2, 2, 2, 172, 175, 3, 2, 2, 2, 173, 174, 3, 2, 2, 2, 173, 171, 3, 2, 2, 2, 174, 176, 3, 2, 2, 2, 175, 173, 3, 2, 2, 2, 176, 177, 7, 44, 2, 2, 177, 178, 7, 49, 2, 2, 178, 179, 3, 2, 2, 2, 179, 180, 8, 23, 2, 2, 180, 46, 3, 2, 2, 2, 181, 182, 7, 44, 2, 2, 182, 48, 3, 2, 2, 2, 183, 184, 7, 49, 2, 2, 184, 50, 3, 2, 2, 2, 185, 186, 7, 45, 2, 2, 186, 52, 3, 2, 2, 2, 187, 188, 7, 47, 2, 2, 188, 54, 3, 2, 2, 2, 189, 190, 7, 62, 2, 2, 190, 56, 3, 2, 2, 2, 191, 192, 7, 64, 2, 2, 192, 58, 3, 2, 2, 2, 193, 194, 7, 62, 2, 2, 194, 195, 7, 63, 2, 2, 195, 60, 3, 2, 2, 2, 196, 197, 7, 64, 2, 2, 197, 198, 7, 63, 2, 2, 198, 62, 3, 2, 2, 2, 199, 200, 7, 63, 2, 2, 200, 201, 7, 63, 2, 2, 201, 64, 3, 2, 2, 2, 202, 203, 7, 35, 2, 2, 203, 204, 7, 63, 2, 2, 204, 66, 3, 2, 2, 2, 205, 206, 7, 66, 2, 2, 206, 207, 5, 83, 42, 2, 207, 68, 3, 2, 2, 2, 208, 209, 7, 39, 2, 2, 209, 210, 5, 83, 42, 2, 210, 70, 3, 2, 2, 2, 211, 212, 7, 39, 2, 2, 212, 213, 5, 79, 40, 2, 213, 72, 3, 2, 2, 2, 214, 215, 7, 111, 2, 2, 215, 216, 7, 119, 2, 2, 216, 217, 7, 118, 2, 2, 217, 74, 3, 2, 2, 2, 218, 219, 7, 86, 2, 2, 219, 220, 7, 116, 2, 2, 220, 221, 7, 119, 2, 2, 221, 228, 7, 103, 2, 2, 222, 223, 7, 72, 2, 2, 223, 224, 7, 99, 2, 2, 224, 225, 7, 110, 2, 2, 225, 226, 7, 117, 2, 2, 226, 228, 7, 103, 2, 2, 227, 218, 3, 2, 2, 2, 227, 222, 3, 2, 2, 2, 228, 76, 3, 2, 2, 2, 229, 230, 5, 79, 40, 2, 230, 231, 7, 48, 2, 2, 231, 233, 5, 79, 40, 2, 232, 234, 5, 81, 41, 2, 233, 232, 3, 2, 2, 2, 233, 234, 3, 2, 2, 2, 234, 239, 3, 2, 2, 2, 235, 236, 5, 79, 40, 2, 236, 237, 5, 81, 41, 2, 237, 239, 3, 2, 2, 2, 238, 229, 3, 2, 2, 2, 238, 235, 3, 2, 2, 2, 239, 78, 3, 2, 2, 2, 240, 242, 5, 87, 44, 2, 241, 240, 3, 2, 2, 2, 242, 243, 3, 2, 2, 2, 243, 241, 3, 2, 2, 2, 243, 244, 3, 2, 2, 2, 244, 80, 3, 2, 2, 2, 245, 247, 9, 3, 2, 2, 246, 248, 9, 4, 2, 2, 247, 246, 3, 2, 2, 2, 247, 248, 3, 2, 2, 2, 248, 249, 3, 2, 2, 2, 249, 250, 5, 79, 40, 2, 250, 82, 3, 2, 2, 2, 251, 254, 7, 97, 2, 2, 252, 254, 5, 85, 43, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 260, 3, 2, 2, 2, 255, 259, 7, 97, 2, 2, 256, 259, 5, 85, 43, 2, 257, 259, 5, 87, 44, 2, 258, 255, 3, 2, 2, 2, 258, 256, 3, 2, 2, 2, 258, 257, 3, 2, 2, 2, 259, 262, 3, 2, 2, 2, 260, 258, 3, 2, 2, 2, 260, 261, 3, 2, 2, 2, 261, 84, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 263, 264, 9, 5, 2, 2, 264, 86, 3, 2, 2, 2, 265, 266, 9, 6, 2, 2, 266, 88, 3, 2, 2, 2, 14, 2, 150, 160, 173, 227, 233, 238, 243, 247, 253, 258, 260, 3, 8, 2, 2]
\ No newline at end of file
T__0=1
T__1=2
T__2=3
T__3=4
T__4=5
T__5=6
T__6=7
T__7=8
T__8=9
T__9=10
T__10=11
T__11=12
T__12=13
T__13=14
T__14=15
T__15=16
T__16=17
T__17=18
SEMVER=19
WS=20
LINE_COMMENT=21
COMMENT=22
MUL=23
DIV=24
ADD=25
SUB=26
LT=27
GT=28
LE=29
GE=30
EQ=31
NE=32
GLOBAL_VAR=33
LOCAL_VAR=34
GRAPH_VAR=35
MUT=36
BOOL_LIT=37
FLOAT=38
NAT=39
CNAME=40
'('=1
')'=2
','=3
'['=4
']'=5
'if'=6
'else'=7
'let'=8
'='=9
';'=10
'{'=11
'}'=12
'fn'=13
'->'=14
'def'=15
':'=16
'Tensor'=17
'_'=18
'v0.0.2'=19
'*'=23
'/'=24
'+'=25
'-'=26
'<'=27
'>'=28
'<='=29
'>='=30
'=='=31
'!='=32
'mut'=36
# Generated from /home/sslyu/tvm/python/tvm/relay/grammar/Relay.g4 by ANTLR 4.7.2
from antlr4 import *
if __name__ is not None and "." in __name__:
from .RelayParser import RelayParser
else:
from RelayParser import RelayParser
# This class defines a complete generic visitor for a parse tree produced by RelayParser.
class RelayVisitor(ParseTreeVisitor):
# Visit a parse tree produced by RelayParser#opIdent.
def visitOpIdent(self, ctx:RelayParser.OpIdentContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#prog.
def visitProg(self, ctx:RelayParser.ProgContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#identExpr.
def visitIdentExpr(self, ctx:RelayParser.IdentExprContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#call.
def visitCall(self, ctx:RelayParser.CallContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#neg.
def visitNeg(self, ctx:RelayParser.NegContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#tuple.
def visitTuple(self, ctx:RelayParser.TupleContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#parens.
def visitParens(self, ctx:RelayParser.ParensContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#funcExpr.
def visitFuncExpr(self, ctx:RelayParser.FuncExprContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#scalarExpr.
def visitScalarExpr(self, ctx:RelayParser.ScalarExprContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#let.
def visitLet(self, ctx:RelayParser.LetContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#tensor.
def visitTensor(self, ctx:RelayParser.TensorContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#ifElse.
def visitIfElse(self, ctx:RelayParser.IfElseContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#graph.
def visitGraph(self, ctx:RelayParser.GraphContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#binOp.
def visitBinOp(self, ctx:RelayParser.BinOpContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#func.
def visitFunc(self, ctx:RelayParser.FuncContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#defn.
def visitDefn(self, ctx:RelayParser.DefnContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#argList.
def visitArgList(self, ctx:RelayParser.ArgListContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#varList.
def visitVarList(self, ctx:RelayParser.VarListContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#var.
def visitVar(self, ctx:RelayParser.VarContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#attrList.
def visitAttrList(self, ctx:RelayParser.AttrListContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#attr.
def visitAttr(self, ctx:RelayParser.AttrContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#typeParamSeq.
def visitTypeParamSeq(self, ctx:RelayParser.TypeParamSeqContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#tupleType.
def visitTupleType(self, ctx:RelayParser.TupleTypeContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#typeIdentType.
def visitTypeIdentType(self, ctx:RelayParser.TypeIdentTypeContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#tensorType.
def visitTensorType(self, ctx:RelayParser.TensorTypeContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#funcType.
def visitFuncType(self, ctx:RelayParser.FuncTypeContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#incompleteType.
def visitIncompleteType(self, ctx:RelayParser.IncompleteTypeContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#intType.
def visitIntType(self, ctx:RelayParser.IntTypeContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#shapeSeq.
def visitShapeSeq(self, ctx:RelayParser.ShapeSeqContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#parensShape.
def visitParensShape(self, ctx:RelayParser.ParensShapeContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#intShape.
def visitIntShape(self, ctx:RelayParser.IntShapeContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#typeIdent.
def visitTypeIdent(self, ctx:RelayParser.TypeIdentContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#body.
def visitBody(self, ctx:RelayParser.BodyContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#scalarFloat.
def visitScalarFloat(self, ctx:RelayParser.ScalarFloatContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#scalarInt.
def visitScalarInt(self, ctx:RelayParser.ScalarIntContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#scalarBool.
def visitScalarBool(self, ctx:RelayParser.ScalarBoolContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by RelayParser#ident.
def visitIdent(self, ctx:RelayParser.IdentContext):
return self.visitChildren(ctx)
del RelayParser
\ No newline at end of file
......@@ -18,19 +18,6 @@
from __future__ import absolute_import
from .. import register_func
def enabled():
"""Checks whether the parser is enabled, this allows users to
optionally support building the parser.
We use this check before importing the parser.
"""
try:
# pylint: disable=unused-variable
from tvm.relay import _parser
return True
# pylint: disable=broad-except
except Exception:
return False
@register_func("relay.fromtext")
def fromtext(data, source_name=None):
......
......@@ -15,12 +15,16 @@
# specific language governing permissions and limitations
# under the License.
# pylint: disable=no-else-return, unidiomatic-typecheck, invalid-name
"""Adds certain standard global functions and ADT definitions to the module."""
"""A prelude containing useful global functions and ADT definitions."""
import os
from .ty import GlobalTypeVar, TypeVar, FuncType, TupleType, scalar_type
from .expr import Var, Function, GlobalVar, Let, If, Tuple, TupleGetItem, const
from .op.tensor import add, subtract, equal
from .adt import Constructor, TypeData, Clause, Match
from .adt import PatternConstructor, PatternVar, PatternWildcard
from .parser import fromtext
__PRELUDE_PATH__ = os.path.dirname(os.path.realpath(__file__))
class Prelude:
"""Contains standard definitions."""
......@@ -451,35 +455,6 @@ class Prelude:
Match(t, [rose_case]), scalar_type('int32'), [a])
def define_id(self):
"""Defines a function that return its argument.
Signature: fn<a>(x : a) -> a
"""
self.id = GlobalVar("id")
a = TypeVar("a")
x = Var("x", a)
self.mod[self.id] = Function([x], x, a, [a])
def define_compose(self):
"""Defines a function that composes two function.
Signature: fn<a, b, c>(f : fn(b) -> c, g : fn(a) -> b) -> fn(a) -> c
"""
self.compose = GlobalVar("compose")
a = TypeVar("a")
b = TypeVar("b")
c = TypeVar("c")
f = Var("f", FuncType([b], c))
g = Var("g", FuncType([a], b))
x = Var("x")
self.mod[self.compose] = Function([f, g],
Function([x], f(g(x))),
FuncType([a], c),
[a, b, c])
def define_iterate(self):
"""Defines a function that take a number n and a function f;
returns a closure that takes an argument and applies f
......@@ -500,9 +475,23 @@ class Prelude:
FuncType([a], a),
[a])
def load_prelude(self):
"""
Parses the portions of the Prelude written in Relay's text format and adds
them to the module.
"""
prelude_file = os.path.join(__PRELUDE_PATH__, "prelude.rly")
with open(prelude_file) as prelude:
prelude = fromtext(prelude.read())
self.mod.update(prelude)
self.id = self.mod["id"]
self.compose = self.mod["compose"]
def __init__(self, mod):
self.mod = mod
self.load_prelude()
self.define_list_adt()
self.define_list_hd()
self.define_list_tl()
......@@ -530,6 +519,4 @@ class Prelude:
self.define_tree_map()
self.define_tree_size()
self.define_id()
self.define_compose()
self.define_iterate()
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
v0.0.2
def @id[a](%x: a) -> a {
%x
}
def @compose[a, b, c](%f: fn(b) -> c, %g: fn(a) -> b) {
fn (%x: a) -> c {
%f(%g(%x))
}
}
......@@ -41,6 +41,8 @@ ALLOW_EXTENSION = {
"pxi",
"pyd",
"pyx",
# relay text format
"rly",
# configurations
"mk",
"in",
......@@ -66,11 +68,15 @@ ALLOW_EXTENSION = {
"sbt",
"properties",
"v",
# generated parser
"interp",
"tokens"
}
# List of file names allowed
ALLOW_FILE_NAME = {
".gitignore",
".gitattributes",
"README",
"Makefile",
"Doxyfile",
......@@ -155,7 +161,7 @@ def main():
report += "\nFound %d files that are now allowed\n" % len(error_list)
report += ("We do not check in binary files into the repo.\n"
"If necessary, please discuss with committers and"
"modify tests/scripts/check_file_type.py to enable the file you need.\n")
"modify tests/lint/check_file_type.py to enable the file you need.\n")
sys.stderr.write(report)
sys.stderr.flush()
sys.exit(-1)
......
......@@ -23,6 +23,8 @@
.*\.csv
.*\.mk
.*\.log
.*\.interp
.*\.tokens
# Generated modules
.*\.egg-info
......@@ -35,10 +37,16 @@ _build
.*~
\#..*\#
# Relay parser
RelayLexer.py
RelayParser.py
RelayVisitor.py
# Specific files
package-list
MANIFEST
.gitignore
.gitattributes
.gitmodules
.clang-format
.bash_history
......
......@@ -16,19 +16,14 @@
# under the License.
import tvm
from tvm import relay
from tvm.relay.parser import enabled
from tvm.relay.ir_pass import alpha_equal
from nose import SkipTest
from nose.tools import nottest, raises
from numpy import isclose
from typing import Union
from functools import wraps
if enabled():
raises_parse_error = raises(tvm._ffi.base.TVMError)
else:
raises_parse_error = lambda x: x
raises_parse_error = raises(tvm._ffi.base.TVMError)
SEMVER = "v0.0.1"
SEMVER = "v0.0.2"
BINARY_OPS = {
"*": relay.multiply,
......@@ -65,9 +60,12 @@ TYPES = {
"float16x4",
}
def parse_text(code):
return relay.fromtext(SEMVER + "\n" + code)
def parses_as(code, expr):
# type: (str, relay.Expr) -> bool
return alpha_equal(relay.fromtext(SEMVER + "\n" + code), expr)
return alpha_equal(parse_text(code), expr)
def get_scalar(x):
# type: (relay.Constant) -> (Union[float, int, bool])
......@@ -83,17 +81,7 @@ Y_ANNO = relay.Var("y", int32)
UNIT = relay.Tuple([])
# decorator to determine if parser is enabled
def if_parser_enabled(func):
# https://stackoverflow.com/q/7727678
@wraps(func)
def wrapper():
if not enabled():
raise SkipTest("ANTLR is not installed!")
func()
return wrapper
@if_parser_enabled
def test_comments():
assert parses_as(
"""
......@@ -113,46 +101,46 @@ def test_comments():
UNIT
)
@if_parser_enabled
def test_int_literal():
assert isinstance(relay.fromtext(SEMVER+"1"), relay.Constant)
assert isinstance(relay.fromtext(SEMVER+"1").data, tvm.ndarray.NDArray)
assert isinstance(parse_text("1"), relay.Constant)
assert isinstance(parse_text("1").data, tvm.ndarray.NDArray)
assert get_scalar(parse_text("1")) == 1
assert get_scalar(parse_text("10")) == 10
assert get_scalar(parse_text("0")) == 0
assert get_scalar(parse_text("-100")) == -100
assert get_scalar(parse_text("-05")) == -5
assert get_scalar(relay.fromtext(SEMVER+"1")) == 1
assert get_scalar(relay.fromtext(SEMVER+"10")) == 10
assert get_scalar(relay.fromtext(SEMVER+"0")) == 0
assert get_scalar(relay.fromtext(SEMVER+"-100")) == -100
assert get_scalar(relay.fromtext(SEMVER+"-05")) == -5
@if_parser_enabled
def test_float_literal():
assert get_scalar(relay.fromtext(SEMVER+"1.0")) == 1.0
assert isclose(get_scalar(relay.fromtext(SEMVER+"1.56667")), 1.56667)
assert get_scalar(relay.fromtext(SEMVER+"0.0")) == 0.0
assert get_scalar(relay.fromtext(SEMVER+"-10.0")) == -10.0
assert get_scalar(parse_text("1.0")) == 1.0
assert isclose(get_scalar(parse_text("1.56667")), 1.56667)
assert get_scalar(parse_text("0.0")) == 0.0
assert get_scalar(parse_text("-10.0")) == -10.0
# scientific notation
assert isclose(get_scalar(relay.fromtext(SEMVER+"1e-1")), 1e-1)
assert get_scalar(relay.fromtext(SEMVER+"1e+1")) == 1e+1
assert isclose(get_scalar(relay.fromtext(SEMVER+"1E-1")), 1E-1)
assert get_scalar(relay.fromtext(SEMVER+"1E+1")) == 1E+1
assert isclose(get_scalar(relay.fromtext(SEMVER+"1.0e-1")), 1.0e-1)
assert get_scalar(relay.fromtext(SEMVER+"1.0e+1")) == 1.0e+1
assert isclose(get_scalar(relay.fromtext(SEMVER+"1.0E-1")), 1.0E-1)
assert get_scalar(relay.fromtext(SEMVER+"1.0E+1")) == 1.0E+1
@if_parser_enabled
assert isclose(get_scalar(parse_text("1e-1")), 1e-1)
assert get_scalar(parse_text("1e+1")) == 1e+1
assert isclose(get_scalar(parse_text("1E-1")), 1E-1)
assert get_scalar(parse_text("1E+1")) == 1E+1
assert isclose(get_scalar(parse_text("1.0e-1")), 1.0e-1)
assert get_scalar(parse_text("1.0e+1")) == 1.0e+1
assert isclose(get_scalar(parse_text("1.0E-1")), 1.0E-1)
assert get_scalar(parse_text("1.0E+1")) == 1.0E+1
def test_bool_literal():
assert get_scalar(relay.fromtext(SEMVER+"True")) == True
assert get_scalar(relay.fromtext(SEMVER+"False")) == False
assert get_scalar(parse_text("True")) == True
assert get_scalar(parse_text("False")) == False
@if_parser_enabled
def test_negative():
assert isinstance(relay.fromtext(SEMVER+"let %x = 1; -%x").body, relay.Call)
assert get_scalar(relay.fromtext(SEMVER+"--10")) == 10
assert get_scalar(relay.fromtext(SEMVER+"---10")) == -10
assert isinstance(parse_text("let %x = 1; -%x").body, relay.Call)
assert get_scalar(parse_text("--10")) == 10
assert get_scalar(parse_text("---10")) == -10
@if_parser_enabled
def test_bin_op():
for bin_op in BINARY_OPS.keys():
assert parses_as(
......@@ -160,18 +148,18 @@ def test_bin_op():
BINARY_OPS.get(bin_op)(relay.const(1), relay.const(1))
)
@if_parser_enabled
def test_parens():
assert alpha_equal(relay.fromtext(SEMVER+"1 * 1 + 1"), relay.fromtext(SEMVER+"(1 * 1) + 1"))
assert not alpha_equal(relay.fromtext(SEMVER+"1 * 1 + 1"), relay.fromtext(SEMVER+"1 * (1 + 1)"))
assert alpha_equal(parse_text("1 * 1 + 1"), parse_text("(1 * 1) + 1"))
assert not alpha_equal(parse_text("1 * 1 + 1"), parse_text("1 * (1 + 1)"))
@if_parser_enabled
def test_op_assoc():
assert alpha_equal(relay.fromtext(SEMVER+"1 * 1 + 1 < 1 == 1"), relay.fromtext(SEMVER+"(((1 * 1) + 1) < 1) == 1"))
assert alpha_equal(relay.fromtext(SEMVER+"1 == 1 < 1 + 1 * 1"), relay.fromtext(SEMVER+"1 == (1 < (1 + (1 * 1)))"))
assert alpha_equal(parse_text("1 * 1 + 1 < 1 == 1"), parse_text("(((1 * 1) + 1) < 1) == 1"))
assert alpha_equal(parse_text("1 == 1 < 1 + 1 * 1"), parse_text("1 == (1 < (1 + (1 * 1)))"))
@nottest
@if_parser_enabled
def test_vars():
# temp vars won't work b/c they start with a digit
# # temp var
......@@ -180,21 +168,21 @@ def test_vars():
# assert temp_var.name == "1"
# var
var = relay.fromtext(SEMVER+"let %foo = (); %foo")
var = parse_text("let %foo = (); %foo")
assert isinstance(var.body, relay.Var)
assert var.body.name_hint == "foo"
# global var
global_var = relay.fromtext(SEMVER+"@foo")
global_var = parse_text("@foo")
assert isinstance(global_var, relay.GlobalVar)
assert global_var.name_hint == "foo"
# operator id
op = relay.fromtext(SEMVER+"foo")
op = parse_text("foo")
assert isinstance(op, relay.Op)
assert op.name == "foo"
@if_parser_enabled
def test_let():
assert parses_as(
"let %x = 1; ()",
......@@ -222,7 +210,7 @@ def test_let():
)
)
@if_parser_enabled
def test_seq():
assert parses_as(
"(); ()",
......@@ -241,7 +229,7 @@ def test_seq():
)
)
@if_parser_enabled
def test_graph():
assert parses_as(
"%0 = (); %1 = 1; (%0, %0, %1)",
......@@ -253,22 +241,22 @@ def test_graph():
relay.Tuple([relay.Tuple([]), relay.Tuple([]), relay.const(1)])
)
@raises_parse_error
@if_parser_enabled
def test_graph_wrong_order():
relay.fromtext(SEMVER+"%1 = (); %1")
parse_text("%1 = (); %1")
@raises_parse_error
@if_parser_enabled
def test_let_global_var():
relay.fromtext(SEMVER+"let @x = 1; ()")
parse_text("let @x = 1; ()")
@raises_parse_error
@if_parser_enabled
def test_let_op():
relay.fromtext(SEMVER+"let x = 1; ()")
parse_text("let x = 1; ()")
@if_parser_enabled
def test_tuple():
assert parses_as("()", relay.Tuple([]))
......@@ -278,7 +266,7 @@ def test_tuple():
assert parses_as("(0, 1, 2)", relay.Tuple([relay.const(0), relay.const(1), relay.const(2)]))
@if_parser_enabled
def test_func():
# 0 args
assert parses_as(
......@@ -330,8 +318,8 @@ def test_func():
relay.Function([], UNIT, None, None, tvm.make.node("DictAttrs", n=relay.const(5)))
)
# TODO(@jmp): Crashes if %x isn't annnotated.
@if_parser_enabled
def test_defn():
id_defn = relay.fromtext(
SEMVER+
......@@ -342,7 +330,7 @@ def test_defn():
""")
assert isinstance(id_defn, relay.Module)
@if_parser_enabled
def test_recursive_call():
id_defn = relay.fromtext(
SEMVER+
......@@ -353,7 +341,7 @@ def test_recursive_call():
""")
assert isinstance(id_defn, relay.Module)
@if_parser_enabled
def test_ifelse():
assert parses_as(
"""
......@@ -370,8 +358,8 @@ def test_ifelse():
)
)
@raises_parse_error
@if_parser_enabled
def test_ifelse_scope():
relay.fromtext(
SEMVER+
......@@ -385,7 +373,7 @@ def test_ifelse_scope():
"""
)
@if_parser_enabled
def test_call():
# select right function to call: simple ident case
id_func = relay.Var("id")
......@@ -509,7 +497,7 @@ def test_call():
# Types
@if_parser_enabled
def test_incomplete_type():
assert parses_as(
"let %_ : _ = (); ()",
......@@ -520,17 +508,17 @@ def test_incomplete_type():
)
)
@if_parser_enabled
def test_builtin_types():
for builtin_type in TYPES:
relay.fromtext(SEMVER+"let %_ : {} = (); ()".format(builtin_type))
parse_text("let %_ : {} = (); ()".format(builtin_type))
@nottest
@if_parser_enabled
def test_call_type():
assert False
@if_parser_enabled
def test_tensor_type():
assert parses_as(
"let %_ : Tensor[(), float32] = (); ()",
......@@ -559,7 +547,7 @@ def test_tensor_type():
)
)
@if_parser_enabled
def test_function_type():
assert parses_as(
"""
......@@ -594,7 +582,7 @@ def test_function_type():
)
)
@if_parser_enabled
def test_tuple_type():
assert parses_as(
"""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment