From 71e85e9d99946787b556526bfa5de44632927417 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 15:19:40 -0700 Subject: [PATCH 01/15] Fix parser --- python/tvm/relay/_parser.py | 83 +-- python/tvm/relay/grammar/Relay.g4 | 4 +- python/tvm/relay/grammar/py3/RelayParser.py | 540 ++++++++++--------- python/tvm/relay/grammar/py3/RelayVisitor.py | 5 + 4 files changed, 347 insertions(+), 285 deletions(-) diff --git a/python/tvm/relay/_parser.py b/python/tvm/relay/_parser.py index 8a969e95081e..9bb74d15e092 100644 --- a/python/tvm/relay/_parser.py +++ b/python/tvm/relay/_parser.py @@ -242,7 +242,7 @@ def mk_global_typ_var(self, name, kind): self.global_type_vars[name] = typ return typ - # TODO: rethink whether we should have type constructors mixed with type vars. + # TODO(weberlo): rethink whether we should have type constructors mixed with type vars. def mk_global_typ_cons(self, name, cons): self._check_existing_typ_expr(name, cons) self.global_type_vars[name] = cons @@ -291,11 +291,15 @@ def visitGeneralIdent(self, ctx): if name.startswith(type_prefix): return ty.scalar_type(name) # Next, look it up in the local then global type params. - type_param = lookup(self.type_var_scopes, name) - if type_param is None: - type_param = self.global_type_vars.get(name, None) - if type_param is not None: - return type_param + type_expr = lookup(self.type_var_scopes, name) + if type_expr is None: + type_expr = self.global_type_vars.get(name, None) + if type_expr is not None: + # Zero-arity constructor calls fall into the general ident case, so in that case, + # we construct a constructor call with no args. + if isinstance(type_expr, adt.Constructor) and len(type_expr.inputs) == 0: + type_expr = expr.Call(type_expr, []) + return type_expr # Check if it's an operator. op_name = ".".join([name.getText() for name in ctx.CNAME()]) if op_name in FUNC_OPS: @@ -321,14 +325,12 @@ def visitGraphVar(self, ctx): def visit_list(self, ctx_list) -> List[Any]: """"Visit a list of contexts.""" - # type: RelayParser.ContextParserRuleContext assert isinstance(ctx_list, list) return [self.visit(ctx) for ctx in ctx_list] - def getTypeExpr(self, ctx) -> Optional[ty.Type]: + def getTypeExpr(self, ctx: Optional[RelayParser.TypeExprContext]) -> Optional[ty.Type]: """Return a (possibly None) Relay type.""" - # type: : Optional[RelayParser.Type_Context] if ctx is None: return None @@ -360,6 +362,10 @@ def visitOpIdent(self, ctx) -> op.Op: def visitParen(self, ctx: RelayParser.ParenContext) -> expr.Expr: return self.visit(ctx.expr()) + # pass through + def visitTypeParen(self, ctx: RelayParser.TypeParenContext) -> expr.Expr: + return self.visit(ctx.typeExpr()) + # pass through def visitBody(self, ctx: RelayParser.BodyContext) -> expr.Expr: return self.visit(ctx.expr()) @@ -466,7 +472,7 @@ def mk_func( type_params = ctx.typeParamList() if type_params is not None: - type_params = type_params.generalIdent() + type_params = type_params.typeExpr() assert type_params for ty_param in type_params: name = ty_param.getText() @@ -498,7 +504,8 @@ def visitFunc(self, ctx: RelayParser.FuncContext) -> expr.Function: def visitFuncDefn(self, ctx: RelayParser.DefnContext) -> None: ident_name = ctx.globalVar().getText()[1:] ident = self.mk_global_var(ident_name) - self.module[ident] = self.mk_func(ctx) + func = self.mk_func(ctx) + self.module[ident] = func def handle_adt_header( self, @@ -512,7 +519,7 @@ def handle_adt_header( type_params = [] else: type_params = [self.mk_typ(type_ident.getText(), ty.Kind.Type) - for type_ident in type_params.generalIdent()] + for type_ident in type_params.typeExpr()] return adt_var, type_params def visitExternAdtDefn(self, ctx: RelayParser.ExternAdtDefnContext): @@ -552,8 +559,6 @@ def visitMatch(self, ctx: RelayParser.MatchContext): else: raise RuntimeError(f"unknown match type {match_type}") - # TODO: Will need some kind of type checking to know which ADT is being - # matched on. match_data = self.visit(ctx.expr()) match_clauses = ctx.matchClauseList() if match_clauses is None: @@ -572,7 +577,6 @@ def visitMatch(self, ctx: RelayParser.MatchContext): patterns = [self.visit(pattern) for pattern in patternList.pattern()] clause_body = self.visit(clause.expr()) self.exit_var_scope() - # TODO: Do we need to pass `None` if it's a 0-arity cons, or is an empty list fine? parsed_clauses.append(adt.Clause( adt.PatternConstructor( constructor, @@ -583,16 +587,24 @@ def visitMatch(self, ctx: RelayParser.MatchContext): return adt.Match(match_data, parsed_clauses, complete=complete_match) def visitPattern(self, ctx: RelayParser.PatternContext): - text = ctx.getText() - if text == "_": + if ctx.getText() == "_": return adt.PatternWildcard() - elif text.startswith("%"): + elif ctx.localVar() is not None: text = ctx.localVar().getText() typ = ctx.typeExpr() if typ is not None: typ = self.visit(typ) var = self.mk_var(text[1:], typ=typ) return adt.PatternVar(var) + elif ctx.constructorName() is not None: + constructor_name = ctx.constructorName().getText() + constructor = self.global_type_vars[constructor_name] + pattern_list = ctx.patternList() + if pattern_list is None: + patterns = [] + else: + patterns = [self.visit(pattern) for pattern in pattern_list.pattern()] + return adt.PatternConstructor(constructor, patterns) else: raise ParseError(f"invalid pattern syntax \"{text}\"") @@ -610,16 +622,14 @@ def call(self, func, args, attrs, type_args): return expr.Call(func, args, attrs, type_args) @spanify - def visitCall(self, ctx: RelayParser.CallContext): - # type: (RelayParser.CallContext) -> expr.Call + def visitCall(self, ctx: RelayParser.CallContext) -> expr.Call: func = self.visit(ctx.expr()) args, attrs = self.visit(ctx.callList()) res = self.call(func, args, attrs, []) return res @spanify - def visitIfElse(self, ctx: RelayParser.IfElseContext): - # type: (RelayParser.IfElseContext) -> expr.If + def visitIfElse(self, ctx: RelayParser.IfElseContext) -> expr.If: """Construct a Relay If node. Creates a new scope for each branch.""" cond = self.visit(ctx.expr()) @@ -634,8 +644,7 @@ def visitIfElse(self, ctx: RelayParser.IfElseContext): return expr.If(cond, true_branch, false_branch) @spanify - def visitGraph(self, ctx: RelayParser.GraphContext): - # type: (RelayParser.GraphContext) -> expr.Expr + def visitGraph(self, ctx: RelayParser.GraphContext) -> expr.Expr: """Visit a graph variable assignment.""" graph_nid = int(ctx.graphVar().getText()[1:]) @@ -655,28 +664,24 @@ def visitGraph(self, ctx: RelayParser.GraphContext): # Types # pylint: disable=unused-argument - def visitIncompleteType(self, ctx: RelayParser.IncompleteTypeContext): - # type (RelayParser.IncompleteTypeContext) -> None: + def visitIncompleteType(self, ctx: RelayParser.IncompleteTypeContext) -> None: return None def visitTypeCallType(self, ctx: RelayParser.TypeCallTypeContext): func = self.visit(ctx.generalIdent()) - args = [self.visit(arg) for arg in ctx.typeParamList().generalIdent()] + args = [self.visit(arg) for arg in ctx.typeParamList().typeExpr()] return ty.TypeCall(func, args) - def visitParensShape(self, ctx: RelayParser.ParensShapeContext): - # type: (RelayParser.ParensShapeContext) -> int + def visitParensShape(self, ctx: RelayParser.ParensShapeContext) -> int: return self.visit(ctx.shape()) - def visitShapeList(self, ctx: RelayParser.ShapeListContext): - # type: (RelayParser.ShapeListContext) -> List[int] + def visitShapeList(self, ctx: RelayParser.ShapeListContext) -> List[int]: return self.visit_list(ctx.shape()) def visitTensor(self, ctx: RelayParser.TensorContext): return tuple(self.visit_list(ctx.expr())) - def visitTensorType(self, ctx: RelayParser.TensorTypeContext): - # type: (RelayParser.TensorTypeContext) -> ty.TensorType + def visitTensorType(self, ctx: RelayParser.TensorTypeContext) -> ty.TensorType: """Create a simple tensor type. No generics.""" shape = self.visit(ctx.shapeList()) @@ -689,12 +694,10 @@ def visitTensorType(self, ctx: RelayParser.TensorTypeContext): return ty.TensorType(shape, dtype) - def visitTupleType(self, ctx: RelayParser.TupleTypeContext): - # type: (RelayParser.TupleTypeContext) -> ty.TupleType + def visitTupleType(self, ctx: RelayParser.TupleTypeContext) -> ty.TupleType: return ty.TupleType(self.visit_list(ctx.typeExpr())) - def visitFuncType(self, ctx: RelayParser.FuncTypeContext): - # type: (RelayParser.FuncTypeContext) -> ty.FuncType + def visitFuncType(self, ctx: RelayParser.FuncTypeContext) -> ty.FuncType: types = self.visit_list(ctx.typeExpr()) arg_types = types[:-1] @@ -702,8 +705,7 @@ def visitFuncType(self, ctx: RelayParser.FuncTypeContext): return ty.FuncType(arg_types, ret_type, [], None) -def make_parser(data): - # type: (str) -> RelayParser +def make_parser(data: str) -> RelayParser: """Construct a RelayParser a given data stream.""" input_stream = InputStream(data) lexer = RelayLexer(input_stream) @@ -738,8 +740,7 @@ def reportAttemptingFullContext(self, def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs): raise Exception("Context Sensitivity in:\n" + self.text) -def fromtext(data, source_name=None): - # type: (str, str) -> Union[expr.Expr, module.Module] +def fromtext(data: str, source_name: str = None) -> Union[expr.Expr, module.Module]: """Parse a Relay program.""" if data == "": raise ParseError("cannot parse the empty string.") diff --git a/python/tvm/relay/grammar/Relay.g4 b/python/tvm/relay/grammar/Relay.g4 index b3269fb113fd..46bd80e7ed93 100644 --- a/python/tvm/relay/grammar/Relay.g4 +++ b/python/tvm/relay/grammar/Relay.g4 @@ -136,6 +136,7 @@ patternList: '(' pattern (',' pattern)* ')'; pattern : '_' | localVar (':' typeExpr)? + | constructorName patternList? ; adtCons: constructorName adtConsParamList? ; @@ -155,6 +156,7 @@ attr: CNAME '=' expr ; typeExpr : '(' ')' # tupleType + | '(' typeExpr ')' # typeParen | '(' typeExpr ',' ')' # tupleType | '(' typeExpr (',' typeExpr)+ ')' # tupleType | generalIdent typeParamList # typeCallType @@ -164,7 +166,7 @@ typeExpr | '_' # incompleteType ; -typeParamList: '[' generalIdent (',' generalIdent)* ']' ; +typeParamList: '[' typeExpr (',' typeExpr)* ']' ; shapeList : '(' ')' diff --git a/python/tvm/relay/grammar/py3/RelayParser.py b/python/tvm/relay/grammar/py3/RelayParser.py index 91fde4c04114..ea3604c2231b 100644 --- a/python/tvm/relay/grammar/py3/RelayParser.py +++ b/python/tvm/relay/grammar/py3/RelayParser.py @@ -9,7 +9,7 @@ def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\62") - buf.write("\u01fc\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\u0204\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write("\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r\4\16") buf.write("\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23\t\23") buf.write("\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31") @@ -40,37 +40,38 @@ def serializedATN(): buf.write("\n\17\3\20\3\20\5\20\u0139\n\20\3\20\3\20\3\20\3\20\3") buf.write("\20\3\20\5\20\u0141\n\20\3\21\3\21\3\22\3\22\3\22\3\22") buf.write("\7\22\u0149\n\22\f\22\16\22\u014c\13\22\3\22\3\22\3\23") - buf.write("\3\23\3\23\3\23\5\23\u0154\n\23\5\23\u0156\n\23\3\24\3") - buf.write("\24\5\24\u015a\n\24\3\25\3\25\3\25\3\25\7\25\u0160\n\25") - buf.write("\f\25\16\25\u0163\13\25\3\25\3\25\3\26\3\26\5\26\u0169") - buf.write("\n\26\3\27\3\27\3\27\3\27\7\27\u016f\n\27\f\27\16\27\u0172") - buf.write("\13\27\3\27\5\27\u0175\n\27\3\30\3\30\3\30\7\30\u017a") - buf.write("\n\30\f\30\16\30\u017d\13\30\5\30\u017f\n\30\3\31\3\31") - buf.write("\3\31\5\31\u0184\n\31\3\32\3\32\3\32\7\32\u0189\n\32\f") - buf.write("\32\16\32\u018c\13\32\3\33\3\33\3\33\3\33\3\34\3\34\3") - buf.write("\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\6\34\u019d") - buf.write("\n\34\r\34\16\34\u019e\3\34\3\34\3\34\3\34\3\34\3\34\3") - buf.write("\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\5\34\u01b0") - buf.write("\n\34\3\34\3\34\3\34\3\34\7\34\u01b6\n\34\f\34\16\34\u01b9") - buf.write("\13\34\5\34\u01bb\n\34\3\34\3\34\3\34\3\34\5\34\u01c1") - buf.write("\n\34\3\35\3\35\3\35\3\35\7\35\u01c7\n\35\f\35\16\35\u01ca") - buf.write("\13\35\3\35\3\35\3\36\3\36\3\36\3\36\3\36\3\36\6\36\u01d4") - buf.write("\n\36\r\36\16\36\u01d5\3\36\3\36\3\36\5\36\u01db\n\36") + buf.write("\3\23\3\23\3\23\5\23\u0154\n\23\3\23\3\23\5\23\u0158\n") + buf.write("\23\5\23\u015a\n\23\3\24\3\24\5\24\u015e\n\24\3\25\3\25") + buf.write("\3\25\3\25\7\25\u0164\n\25\f\25\16\25\u0167\13\25\3\25") + buf.write("\3\25\3\26\3\26\5\26\u016d\n\26\3\27\3\27\3\27\3\27\7") + buf.write("\27\u0173\n\27\f\27\16\27\u0176\13\27\3\27\5\27\u0179") + buf.write("\n\27\3\30\3\30\3\30\7\30\u017e\n\30\f\30\16\30\u0181") + buf.write("\13\30\5\30\u0183\n\30\3\31\3\31\3\31\5\31\u0188\n\31") + buf.write("\3\32\3\32\3\32\7\32\u018d\n\32\f\32\16\32\u0190\13\32") + buf.write("\3\33\3\33\3\33\3\33\3\34\3\34\3\34\3\34\3\34\3\34\3\34") + buf.write("\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\6\34\u01a5\n") + buf.write("\34\r\34\16\34\u01a6\3\34\3\34\3\34\3\34\3\34\3\34\3\34") + buf.write("\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\5\34\u01b8\n") + buf.write("\34\3\34\3\34\3\34\3\34\7\34\u01be\n\34\f\34\16\34\u01c1") + buf.write("\13\34\5\34\u01c3\n\34\3\34\3\34\3\34\3\34\5\34\u01c9") + buf.write("\n\34\3\35\3\35\3\35\3\35\7\35\u01cf\n\35\f\35\16\35\u01d2") + buf.write("\13\35\3\35\3\35\3\36\3\36\3\36\3\36\3\36\3\36\6\36\u01dc") + buf.write("\n\36\r\36\16\36\u01dd\3\36\3\36\3\36\5\36\u01e3\n\36") buf.write("\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3") - buf.write(" \3 \5 \u01eb\n \3!\3!\3!\3!\3\"\3\"\3\"\5\"\u01f4\n\"") - buf.write("\3#\3#\3#\3#\5#\u01fa\n#\3#\2\3\20$\2\4\6\b\n\f\16\20") + buf.write(" \3 \5 \u01f3\n \3!\3!\3!\3!\3\"\3\"\3\"\5\"\u01fc\n\"") + buf.write("\3#\3#\3#\3#\5#\u0202\n#\3#\2\3\20$\2\4\6\b\n\f\16\20") buf.write("\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\668:<>@BD\2\b") - buf.write("\4\2\6\6//\3\2$%\3\2&\'\3\2(+\3\2,-\3\2\32\33\2\u022d") + buf.write("\4\2\6\6//\3\2$%\3\2&\'\3\2(+\3\2,-\3\2\32\33\2\u0238") buf.write("\2F\3\2\2\2\4U\3\2\2\2\6]\3\2\2\2\b`\3\2\2\2\nc\3\2\2") buf.write("\2\fn\3\2\2\2\16z\3\2\2\2\20\u00c4\3\2\2\2\22\u00e2\3") buf.write("\2\2\2\24\u010e\3\2\2\2\26\u0110\3\2\2\2\30\u0112\3\2") buf.write("\2\2\32\u011d\3\2\2\2\34\u012b\3\2\2\2\36\u0136\3\2\2") - buf.write("\2 \u0142\3\2\2\2\"\u0144\3\2\2\2$\u0155\3\2\2\2&\u0157") - buf.write("\3\2\2\2(\u015b\3\2\2\2*\u0168\3\2\2\2,\u0174\3\2\2\2") - buf.write(".\u017e\3\2\2\2\60\u0180\3\2\2\2\62\u0185\3\2\2\2\64\u018d") - buf.write("\3\2\2\2\66\u01c0\3\2\2\28\u01c2\3\2\2\2:\u01da\3\2\2") - buf.write("\2<\u01dc\3\2\2\2>\u01ea\3\2\2\2@\u01ec\3\2\2\2B\u01f3") - buf.write("\3\2\2\2D\u01f9\3\2\2\2FN\7\37\2\2GI\5\24\13\2HG\3\2\2") + buf.write("\2 \u0142\3\2\2\2\"\u0144\3\2\2\2$\u0159\3\2\2\2&\u015b") + buf.write("\3\2\2\2(\u015f\3\2\2\2*\u016c\3\2\2\2,\u0178\3\2\2\2") + buf.write(".\u0182\3\2\2\2\60\u0184\3\2\2\2\62\u0189\3\2\2\2\64\u0191") + buf.write("\3\2\2\2\66\u01c8\3\2\2\28\u01ca\3\2\2\2:\u01e2\3\2\2") + buf.write("\2<\u01e4\3\2\2\2>\u01f2\3\2\2\2@\u01f4\3\2\2\2B\u01fb") + buf.write("\3\2\2\2D\u0201\3\2\2\2FN\7\37\2\2GI\5\24\13\2HG\3\2\2") buf.write("\2IL\3\2\2\2JH\3\2\2\2JK\3\2\2\2KO\3\2\2\2LJ\3\2\2\2M") buf.write("O\5\20\t\2NJ\3\2\2\2NM\3\2\2\2OQ\3\2\2\2PR\7\62\2\2QP") buf.write("\3\2\2\2QR\3\2\2\2RS\3\2\2\2ST\7\2\2\3T\3\3\2\2\2UZ\7") @@ -175,86 +176,90 @@ def serializedATN(): buf.write("\7\2\2\u0147\u0149\5$\23\2\u0148\u0146\3\2\2\2\u0149\u014c") buf.write("\3\2\2\2\u014a\u0148\3\2\2\2\u014a\u014b\3\2\2\2\u014b") buf.write("\u014d\3\2\2\2\u014c\u014a\3\2\2\2\u014d\u014e\7\t\2\2") - buf.write("\u014e#\3\2\2\2\u014f\u0156\7\6\2\2\u0150\u0153\5\b\5") + buf.write("\u014e#\3\2\2\2\u014f\u015a\7\6\2\2\u0150\u0153\5\b\5") buf.write("\2\u0151\u0152\7\34\2\2\u0152\u0154\5\66\34\2\u0153\u0151") - buf.write("\3\2\2\2\u0153\u0154\3\2\2\2\u0154\u0156\3\2\2\2\u0155") - buf.write("\u014f\3\2\2\2\u0155\u0150\3\2\2\2\u0156%\3\2\2\2\u0157") - buf.write("\u0159\5\26\f\2\u0158\u015a\5(\25\2\u0159\u0158\3\2\2") - buf.write("\2\u0159\u015a\3\2\2\2\u015a\'\3\2\2\2\u015b\u015c\7\b") - buf.write("\2\2\u015c\u0161\5*\26\2\u015d\u015e\7\7\2\2\u015e\u0160") - buf.write("\5*\26\2\u015f\u015d\3\2\2\2\u0160\u0163\3\2\2\2\u0161") - buf.write("\u015f\3\2\2\2\u0161\u0162\3\2\2\2\u0162\u0164\3\2\2\2") - buf.write("\u0163\u0161\3\2\2\2\u0164\u0165\7\t\2\2\u0165)\3\2\2") - buf.write("\2\u0166\u0169\5\b\5\2\u0167\u0169\5\26\f\2\u0168\u0166") - buf.write("\3\2\2\2\u0168\u0167\3\2\2\2\u0169+\3\2\2\2\u016a\u0175") - buf.write("\5.\30\2\u016b\u016c\5\60\31\2\u016c\u016d\7\7\2\2\u016d") - buf.write("\u016f\3\2\2\2\u016e\u016b\3\2\2\2\u016f\u0172\3\2\2\2") - buf.write("\u0170\u016e\3\2\2\2\u0170\u0171\3\2\2\2\u0171\u0173\3") - buf.write("\2\2\2\u0172\u0170\3\2\2\2\u0173\u0175\5\62\32\2\u0174") - buf.write("\u016a\3\2\2\2\u0174\u0170\3\2\2\2\u0175-\3\2\2\2\u0176") - buf.write("\u017b\5\60\31\2\u0177\u0178\7\7\2\2\u0178\u017a\5\60") - buf.write("\31\2\u0179\u0177\3\2\2\2\u017a\u017d\3\2\2\2\u017b\u0179") - buf.write("\3\2\2\2\u017b\u017c\3\2\2\2\u017c\u017f\3\2\2\2\u017d") - buf.write("\u017b\3\2\2\2\u017e\u0176\3\2\2\2\u017e\u017f\3\2\2\2") - buf.write("\u017f/\3\2\2\2\u0180\u0183\5\b\5\2\u0181\u0182\7\34\2") - buf.write("\2\u0182\u0184\5\66\34\2\u0183\u0181\3\2\2\2\u0183\u0184") - buf.write("\3\2\2\2\u0184\61\3\2\2\2\u0185\u018a\5\64\33\2\u0186") - buf.write("\u0187\7\7\2\2\u0187\u0189\5\64\33\2\u0188\u0186\3\2\2") - buf.write("\2\u0189\u018c\3\2\2\2\u018a\u0188\3\2\2\2\u018a\u018b") - buf.write("\3\2\2\2\u018b\63\3\2\2\2\u018c\u018a\3\2\2\2\u018d\u018e") - buf.write("\7/\2\2\u018e\u018f\7\21\2\2\u018f\u0190\5\20\t\2\u0190") - buf.write("\65\3\2\2\2\u0191\u0192\7\b\2\2\u0192\u01c1\7\t\2\2\u0193") - buf.write("\u0194\7\b\2\2\u0194\u0195\5\66\34\2\u0195\u0196\7\7\2") - buf.write("\2\u0196\u0197\7\t\2\2\u0197\u01c1\3\2\2\2\u0198\u0199") - buf.write("\7\b\2\2\u0199\u019c\5\66\34\2\u019a\u019b\7\7\2\2\u019b") - buf.write("\u019d\5\66\34\2\u019c\u019a\3\2\2\2\u019d\u019e\3\2\2") - buf.write("\2\u019e\u019c\3\2\2\2\u019e\u019f\3\2\2\2\u019f\u01a0") - buf.write("\3\2\2\2\u01a0\u01a1\7\t\2\2\u01a1\u01c1\3\2\2\2\u01a2") - buf.write("\u01a3\5\4\3\2\u01a3\u01a4\58\35\2\u01a4\u01c1\3\2\2\2") - buf.write("\u01a5\u01c1\5\4\3\2\u01a6\u01a7\7\35\2\2\u01a7\u01a8") - buf.write("\7\n\2\2\u01a8\u01a9\5:\36\2\u01a9\u01aa\7\7\2\2\u01aa") - buf.write("\u01ab\5\66\34\2\u01ab\u01ac\7\13\2\2\u01ac\u01c1\3\2") - buf.write("\2\2\u01ad\u01af\7\24\2\2\u01ae\u01b0\58\35\2\u01af\u01ae") - buf.write("\3\2\2\2\u01af\u01b0\3\2\2\2\u01b0\u01b1\3\2\2\2\u01b1") - buf.write("\u01ba\7\b\2\2\u01b2\u01b7\5\66\34\2\u01b3\u01b4\7\7\2") - buf.write("\2\u01b4\u01b6\5\66\34\2\u01b5\u01b3\3\2\2\2\u01b6\u01b9") - buf.write("\3\2\2\2\u01b7\u01b5\3\2\2\2\u01b7\u01b8\3\2\2\2\u01b8") - buf.write("\u01bb\3\2\2\2\u01b9\u01b7\3\2\2\2\u01ba\u01b2\3\2\2\2") - buf.write("\u01ba\u01bb\3\2\2\2\u01bb\u01bc\3\2\2\2\u01bc\u01bd\7") - buf.write("\t\2\2\u01bd\u01be\7\25\2\2\u01be\u01c1\5\66\34\2\u01bf") - buf.write("\u01c1\7\6\2\2\u01c0\u0191\3\2\2\2\u01c0\u0193\3\2\2\2") - buf.write("\u01c0\u0198\3\2\2\2\u01c0\u01a2\3\2\2\2\u01c0\u01a5\3") - buf.write("\2\2\2\u01c0\u01a6\3\2\2\2\u01c0\u01ad\3\2\2\2\u01c0\u01bf") - buf.write("\3\2\2\2\u01c1\67\3\2\2\2\u01c2\u01c3\7\n\2\2\u01c3\u01c8") - buf.write("\5\4\3\2\u01c4\u01c5\7\7\2\2\u01c5\u01c7\5\4\3\2\u01c6") - buf.write("\u01c4\3\2\2\2\u01c7\u01ca\3\2\2\2\u01c8\u01c6\3\2\2\2") - buf.write("\u01c8\u01c9\3\2\2\2\u01c9\u01cb\3\2\2\2\u01ca\u01c8\3") - buf.write("\2\2\2\u01cb\u01cc\7\13\2\2\u01cc9\3\2\2\2\u01cd\u01ce") - buf.write("\7\b\2\2\u01ce\u01db\7\t\2\2\u01cf\u01d0\7\b\2\2\u01d0") - buf.write("\u01d3\5> \2\u01d1\u01d2\7\7\2\2\u01d2\u01d4\5> \2\u01d3") - buf.write("\u01d1\3\2\2\2\u01d4\u01d5\3\2\2\2\u01d5\u01d3\3\2\2\2") - buf.write("\u01d5\u01d6\3\2\2\2\u01d6\u01d7\3\2\2\2\u01d7\u01d8\7") - buf.write("\t\2\2\u01d8\u01db\3\2\2\2\u01d9\u01db\5> \2\u01da\u01cd") - buf.write("\3\2\2\2\u01da\u01cf\3\2\2\2\u01da\u01d9\3\2\2\2\u01db") - buf.write(";\3\2\2\2\u01dc\u01dd\7\36\2\2\u01dd\u01de\7\n\2\2\u01de") - buf.write("\u01df\7/\2\2\u01df\u01e0\7\13\2\2\u01e0\u01e1\7\n\2\2") - buf.write("\u01e1\u01e2\7\61\2\2\u01e2\u01e3\7\13\2\2\u01e3=\3\2") - buf.write("\2\2\u01e4\u01eb\5<\37\2\u01e5\u01e6\7\b\2\2\u01e6\u01e7") - buf.write("\5> \2\u01e7\u01e8\7\t\2\2\u01e8\u01eb\3\2\2\2\u01e9\u01eb") - buf.write("\7\61\2\2\u01ea\u01e4\3\2\2\2\u01ea\u01e5\3\2\2\2\u01ea") - buf.write("\u01e9\3\2\2\2\u01eb?\3\2\2\2\u01ec\u01ed\7\16\2\2\u01ed") - buf.write("\u01ee\5\20\t\2\u01ee\u01ef\7\17\2\2\u01efA\3\2\2\2\u01f0") - buf.write("\u01f4\7\60\2\2\u01f1\u01f4\7\61\2\2\u01f2\u01f4\7.\2") - buf.write("\2\u01f3\u01f0\3\2\2\2\u01f3\u01f1\3\2\2\2\u01f3\u01f2") - buf.write("\3\2\2\2\u01f4C\3\2\2\2\u01f5\u01fa\5\4\3\2\u01f6\u01fa") - buf.write("\5\6\4\2\u01f7\u01fa\5\b\5\2\u01f8\u01fa\5\n\6\2\u01f9") - buf.write("\u01f5\3\2\2\2\u01f9\u01f6\3\2\2\2\u01f9\u01f7\3\2\2\2") - buf.write("\u01f9\u01f8\3\2\2\2\u01faE\3\2\2\28JNQZknvz\u0091\u009b") + buf.write("\3\2\2\2\u0153\u0154\3\2\2\2\u0154\u015a\3\2\2\2\u0155") + buf.write("\u0157\5\26\f\2\u0156\u0158\5\"\22\2\u0157\u0156\3\2\2") + buf.write("\2\u0157\u0158\3\2\2\2\u0158\u015a\3\2\2\2\u0159\u014f") + buf.write("\3\2\2\2\u0159\u0150\3\2\2\2\u0159\u0155\3\2\2\2\u015a") + buf.write("%\3\2\2\2\u015b\u015d\5\26\f\2\u015c\u015e\5(\25\2\u015d") + buf.write("\u015c\3\2\2\2\u015d\u015e\3\2\2\2\u015e\'\3\2\2\2\u015f") + buf.write("\u0160\7\b\2\2\u0160\u0165\5*\26\2\u0161\u0162\7\7\2\2") + buf.write("\u0162\u0164\5*\26\2\u0163\u0161\3\2\2\2\u0164\u0167\3") + buf.write("\2\2\2\u0165\u0163\3\2\2\2\u0165\u0166\3\2\2\2\u0166\u0168") + buf.write("\3\2\2\2\u0167\u0165\3\2\2\2\u0168\u0169\7\t\2\2\u0169") + buf.write(")\3\2\2\2\u016a\u016d\5\b\5\2\u016b\u016d\5\26\f\2\u016c") + buf.write("\u016a\3\2\2\2\u016c\u016b\3\2\2\2\u016d+\3\2\2\2\u016e") + buf.write("\u0179\5.\30\2\u016f\u0170\5\60\31\2\u0170\u0171\7\7\2") + buf.write("\2\u0171\u0173\3\2\2\2\u0172\u016f\3\2\2\2\u0173\u0176") + buf.write("\3\2\2\2\u0174\u0172\3\2\2\2\u0174\u0175\3\2\2\2\u0175") + buf.write("\u0177\3\2\2\2\u0176\u0174\3\2\2\2\u0177\u0179\5\62\32") + buf.write("\2\u0178\u016e\3\2\2\2\u0178\u0174\3\2\2\2\u0179-\3\2") + buf.write("\2\2\u017a\u017f\5\60\31\2\u017b\u017c\7\7\2\2\u017c\u017e") + buf.write("\5\60\31\2\u017d\u017b\3\2\2\2\u017e\u0181\3\2\2\2\u017f") + buf.write("\u017d\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0183\3\2\2\2") + buf.write("\u0181\u017f\3\2\2\2\u0182\u017a\3\2\2\2\u0182\u0183\3") + buf.write("\2\2\2\u0183/\3\2\2\2\u0184\u0187\5\b\5\2\u0185\u0186") + buf.write("\7\34\2\2\u0186\u0188\5\66\34\2\u0187\u0185\3\2\2\2\u0187") + buf.write("\u0188\3\2\2\2\u0188\61\3\2\2\2\u0189\u018e\5\64\33\2") + buf.write("\u018a\u018b\7\7\2\2\u018b\u018d\5\64\33\2\u018c\u018a") + buf.write("\3\2\2\2\u018d\u0190\3\2\2\2\u018e\u018c\3\2\2\2\u018e") + buf.write("\u018f\3\2\2\2\u018f\63\3\2\2\2\u0190\u018e\3\2\2\2\u0191") + buf.write("\u0192\7/\2\2\u0192\u0193\7\21\2\2\u0193\u0194\5\20\t") + buf.write("\2\u0194\65\3\2\2\2\u0195\u0196\7\b\2\2\u0196\u01c9\7") + buf.write("\t\2\2\u0197\u0198\7\b\2\2\u0198\u0199\5\66\34\2\u0199") + buf.write("\u019a\7\t\2\2\u019a\u01c9\3\2\2\2\u019b\u019c\7\b\2\2") + buf.write("\u019c\u019d\5\66\34\2\u019d\u019e\7\7\2\2\u019e\u019f") + buf.write("\7\t\2\2\u019f\u01c9\3\2\2\2\u01a0\u01a1\7\b\2\2\u01a1") + buf.write("\u01a4\5\66\34\2\u01a2\u01a3\7\7\2\2\u01a3\u01a5\5\66") + buf.write("\34\2\u01a4\u01a2\3\2\2\2\u01a5\u01a6\3\2\2\2\u01a6\u01a4") + buf.write("\3\2\2\2\u01a6\u01a7\3\2\2\2\u01a7\u01a8\3\2\2\2\u01a8") + buf.write("\u01a9\7\t\2\2\u01a9\u01c9\3\2\2\2\u01aa\u01ab\5\4\3\2") + buf.write("\u01ab\u01ac\58\35\2\u01ac\u01c9\3\2\2\2\u01ad\u01c9\5") + buf.write("\4\3\2\u01ae\u01af\7\35\2\2\u01af\u01b0\7\n\2\2\u01b0") + buf.write("\u01b1\5:\36\2\u01b1\u01b2\7\7\2\2\u01b2\u01b3\5\66\34") + buf.write("\2\u01b3\u01b4\7\13\2\2\u01b4\u01c9\3\2\2\2\u01b5\u01b7") + buf.write("\7\24\2\2\u01b6\u01b8\58\35\2\u01b7\u01b6\3\2\2\2\u01b7") + buf.write("\u01b8\3\2\2\2\u01b8\u01b9\3\2\2\2\u01b9\u01c2\7\b\2\2") + buf.write("\u01ba\u01bf\5\66\34\2\u01bb\u01bc\7\7\2\2\u01bc\u01be") + buf.write("\5\66\34\2\u01bd\u01bb\3\2\2\2\u01be\u01c1\3\2\2\2\u01bf") + buf.write("\u01bd\3\2\2\2\u01bf\u01c0\3\2\2\2\u01c0\u01c3\3\2\2\2") + buf.write("\u01c1\u01bf\3\2\2\2\u01c2\u01ba\3\2\2\2\u01c2\u01c3\3") + buf.write("\2\2\2\u01c3\u01c4\3\2\2\2\u01c4\u01c5\7\t\2\2\u01c5\u01c6") + buf.write("\7\25\2\2\u01c6\u01c9\5\66\34\2\u01c7\u01c9\7\6\2\2\u01c8") + buf.write("\u0195\3\2\2\2\u01c8\u0197\3\2\2\2\u01c8\u019b\3\2\2\2") + buf.write("\u01c8\u01a0\3\2\2\2\u01c8\u01aa\3\2\2\2\u01c8\u01ad\3") + buf.write("\2\2\2\u01c8\u01ae\3\2\2\2\u01c8\u01b5\3\2\2\2\u01c8\u01c7") + buf.write("\3\2\2\2\u01c9\67\3\2\2\2\u01ca\u01cb\7\n\2\2\u01cb\u01d0") + buf.write("\5\66\34\2\u01cc\u01cd\7\7\2\2\u01cd\u01cf\5\66\34\2\u01ce") + buf.write("\u01cc\3\2\2\2\u01cf\u01d2\3\2\2\2\u01d0\u01ce\3\2\2\2") + buf.write("\u01d0\u01d1\3\2\2\2\u01d1\u01d3\3\2\2\2\u01d2\u01d0\3") + buf.write("\2\2\2\u01d3\u01d4\7\13\2\2\u01d49\3\2\2\2\u01d5\u01d6") + buf.write("\7\b\2\2\u01d6\u01e3\7\t\2\2\u01d7\u01d8\7\b\2\2\u01d8") + buf.write("\u01db\5> \2\u01d9\u01da\7\7\2\2\u01da\u01dc\5> \2\u01db") + buf.write("\u01d9\3\2\2\2\u01dc\u01dd\3\2\2\2\u01dd\u01db\3\2\2\2") + buf.write("\u01dd\u01de\3\2\2\2\u01de\u01df\3\2\2\2\u01df\u01e0\7") + buf.write("\t\2\2\u01e0\u01e3\3\2\2\2\u01e1\u01e3\5> \2\u01e2\u01d5") + buf.write("\3\2\2\2\u01e2\u01d7\3\2\2\2\u01e2\u01e1\3\2\2\2\u01e3") + buf.write(";\3\2\2\2\u01e4\u01e5\7\36\2\2\u01e5\u01e6\7\n\2\2\u01e6") + buf.write("\u01e7\7/\2\2\u01e7\u01e8\7\13\2\2\u01e8\u01e9\7\n\2\2") + buf.write("\u01e9\u01ea\7\61\2\2\u01ea\u01eb\7\13\2\2\u01eb=\3\2") + buf.write("\2\2\u01ec\u01f3\5<\37\2\u01ed\u01ee\7\b\2\2\u01ee\u01ef") + buf.write("\5> \2\u01ef\u01f0\7\t\2\2\u01f0\u01f3\3\2\2\2\u01f1\u01f3") + buf.write("\7\61\2\2\u01f2\u01ec\3\2\2\2\u01f2\u01ed\3\2\2\2\u01f2") + buf.write("\u01f1\3\2\2\2\u01f3?\3\2\2\2\u01f4\u01f5\7\16\2\2\u01f5") + buf.write("\u01f6\5\20\t\2\u01f6\u01f7\7\17\2\2\u01f7A\3\2\2\2\u01f8") + buf.write("\u01fc\7\60\2\2\u01f9\u01fc\7\61\2\2\u01fa\u01fc\7.\2") + buf.write("\2\u01fb\u01f8\3\2\2\2\u01fb\u01f9\3\2\2\2\u01fb\u01fa") + buf.write("\3\2\2\2\u01fcC\3\2\2\2\u01fd\u0202\5\4\3\2\u01fe\u0202") + buf.write("\5\6\4\2\u01ff\u0202\5\b\5\2\u0200\u0202\5\n\6\2\u0201") + buf.write("\u01fd\3\2\2\2\u0201\u01fe\3\2\2\2\u0201\u01ff\3\2\2\2") + buf.write("\u0201\u0200\3\2\2\2\u0202E\3\2\2\29JNQZknvz\u0091\u009b") buf.write("\u009e\u00af\u00c4\u00dd\u00df\u00e4\u00eb\u00f2\u00f9") buf.write("\u0101\u0106\u010a\u010e\u0117\u011b\u0124\u0129\u0130") - buf.write("\u0134\u0138\u0140\u014a\u0153\u0155\u0159\u0161\u0168") - buf.write("\u0170\u0174\u017b\u017e\u0183\u018a\u019e\u01af\u01b7") - buf.write("\u01ba\u01c0\u01c8\u01d5\u01da\u01ea\u01f3\u01f9") + buf.write("\u0134\u0138\u0140\u014a\u0153\u0157\u0159\u015d\u0165") + buf.write("\u016c\u0174\u0178\u017f\u0182\u0187\u018e\u01a6\u01b7") + buf.write("\u01bf\u01c2\u01c8\u01d0\u01dd\u01e2\u01f2\u01fb\u0201") return buf.getvalue() @@ -2246,6 +2251,14 @@ def typeExpr(self): return self.getTypedRuleContext(RelayParser.TypeExprContext,0) + def constructorName(self): + return self.getTypedRuleContext(RelayParser.ConstructorNameContext,0) + + + def patternList(self): + return self.getTypedRuleContext(RelayParser.PatternListContext,0) + + def getRuleIndex(self): return RelayParser.RULE_pattern @@ -2264,7 +2277,7 @@ def pattern(self): self.enterRule(localctx, 34, self.RULE_pattern) self._la = 0 # Token type try: - self.state = 339 + self.state = 343 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.T__3]: @@ -2286,6 +2299,19 @@ def pattern(self): self.typeExpr() + pass + elif token in [RelayParser.CNAME]: + self.enterOuterAlt(localctx, 3) + self.state = 339 + self.constructorName() + self.state = 341 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==RelayParser.T__5: + self.state = 340 + self.patternList() + + pass else: raise NoViableAltException(self) @@ -2332,13 +2358,13 @@ def adtCons(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 341 + self.state = 345 self.constructorName() - self.state = 343 + self.state = 347 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__5: - self.state = 342 + self.state = 346 self.adtConsParamList() @@ -2383,23 +2409,23 @@ def adtConsParamList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 345 + self.state = 349 self.match(RelayParser.T__5) - self.state = 346 + self.state = 350 self.adtConsParam() - self.state = 351 + self.state = 355 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 347 + self.state = 351 self.match(RelayParser.T__4) - self.state = 348 + self.state = 352 self.adtConsParam() - self.state = 353 + self.state = 357 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 354 + self.state = 358 self.match(RelayParser.T__6) except RecognitionException as re: localctx.exception = re @@ -2441,17 +2467,17 @@ def adtConsParam(self): localctx = RelayParser.AdtConsParamContext(self, self._ctx, self.state) self.enterRule(localctx, 40, self.RULE_adtConsParam) try: - self.state = 358 + self.state = 362 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.T__2]: self.enterOuterAlt(localctx, 1) - self.state = 356 + self.state = 360 self.localVar() pass elif token in [RelayParser.CNAME]: self.enterOuterAlt(localctx, 2) - self.state = 357 + self.state = 361 self.constructorName() pass else: @@ -2529,32 +2555,32 @@ def argList(self): self.enterRule(localctx, 42, self.RULE_argList) self._la = 0 # Token type try: - self.state = 370 + self.state = 374 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,38,self._ctx) + la_ = self._interp.adaptivePredict(self._input,39,self._ctx) if la_ == 1: localctx = RelayParser.ArgNoAttrContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 360 + self.state = 364 self.varList() pass elif la_ == 2: localctx = RelayParser.ArgWithAttrContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 366 + self.state = 370 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__2: - self.state = 361 + self.state = 365 self.var() - self.state = 362 + self.state = 366 self.match(RelayParser.T__4) - self.state = 368 + self.state = 372 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 369 + self.state = 373 self.attrSeq() pass @@ -2600,21 +2626,21 @@ def varList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 380 + self.state = 384 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__2: - self.state = 372 + self.state = 376 self.var() - self.state = 377 + self.state = 381 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 373 + self.state = 377 self.match(RelayParser.T__4) - self.state = 374 + self.state = 378 self.var() - self.state = 379 + self.state = 383 self._errHandler.sync(self) _la = self._input.LA(1) @@ -2662,15 +2688,15 @@ def var(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 382 + self.state = 386 self.localVar() - self.state = 385 + self.state = 389 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__25: - self.state = 383 + self.state = 387 self.match(RelayParser.T__25) - self.state = 384 + self.state = 388 self.typeExpr() @@ -2715,17 +2741,17 @@ def attrSeq(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 387 + self.state = 391 self.attr() - self.state = 392 + self.state = 396 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 388 + self.state = 392 self.match(RelayParser.T__4) - self.state = 389 + self.state = 393 self.attr() - self.state = 394 + self.state = 398 self._errHandler.sync(self) _la = self._input.LA(1) @@ -2769,11 +2795,11 @@ def attr(self): self.enterRule(localctx, 50, self.RULE_attr) try: self.enterOuterAlt(localctx, 1) - self.state = 395 + self.state = 399 self.match(RelayParser.CNAME) - self.state = 396 + self.state = 400 self.match(RelayParser.T__14) - self.state = 397 + self.state = 401 self.expr(0) except RecognitionException as re: localctx.exception = re @@ -2800,6 +2826,23 @@ def copyFrom(self, ctx:ParserRuleContext): + class TypeParenContext(TypeExprContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a RelayParser.TypeExprContext + super().__init__(parser) + self.copyFrom(ctx) + + def typeExpr(self): + return self.getTypedRuleContext(RelayParser.TypeExprContext,0) + + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitTypeParen" ): + return visitor.visitTypeParen(self) + else: + return visitor.visitChildren(self) + + class TupleTypeContext(TypeExprContext): def __init__(self, parser, ctx:ParserRuleContext): # actually a RelayParser.TypeExprContext @@ -2921,136 +2964,147 @@ def typeExpr(self): self.enterRule(localctx, 52, self.RULE_typeExpr) self._la = 0 # Token type try: - self.state = 446 + self.state = 454 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,47,self._ctx) + la_ = self._interp.adaptivePredict(self._input,48,self._ctx) if la_ == 1: localctx = RelayParser.TupleTypeContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 399 + self.state = 403 self.match(RelayParser.T__5) - self.state = 400 + self.state = 404 self.match(RelayParser.T__6) pass elif la_ == 2: - localctx = RelayParser.TupleTypeContext(self, localctx) + localctx = RelayParser.TypeParenContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 401 + self.state = 405 self.match(RelayParser.T__5) - self.state = 402 + self.state = 406 self.typeExpr() - self.state = 403 - self.match(RelayParser.T__4) - self.state = 404 + self.state = 407 self.match(RelayParser.T__6) pass elif la_ == 3: localctx = RelayParser.TupleTypeContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 406 + self.state = 409 self.match(RelayParser.T__5) - self.state = 407 + self.state = 410 self.typeExpr() - self.state = 410 + self.state = 411 + self.match(RelayParser.T__4) + self.state = 412 + self.match(RelayParser.T__6) + pass + + elif la_ == 4: + localctx = RelayParser.TupleTypeContext(self, localctx) + self.enterOuterAlt(localctx, 4) + self.state = 414 + self.match(RelayParser.T__5) + self.state = 415 + self.typeExpr() + self.state = 418 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 408 + self.state = 416 self.match(RelayParser.T__4) - self.state = 409 + self.state = 417 self.typeExpr() - self.state = 412 + self.state = 420 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==RelayParser.T__4): break - self.state = 414 + self.state = 422 self.match(RelayParser.T__6) pass - elif la_ == 4: + elif la_ == 5: localctx = RelayParser.TypeCallTypeContext(self, localctx) - self.enterOuterAlt(localctx, 4) - self.state = 416 + self.enterOuterAlt(localctx, 5) + self.state = 424 self.generalIdent() - self.state = 417 + self.state = 425 self.typeParamList() pass - elif la_ == 5: + elif la_ == 6: localctx = RelayParser.TypeIdentTypeContext(self, localctx) - self.enterOuterAlt(localctx, 5) - self.state = 419 + self.enterOuterAlt(localctx, 6) + self.state = 427 self.generalIdent() pass - elif la_ == 6: + elif la_ == 7: localctx = RelayParser.TensorTypeContext(self, localctx) - self.enterOuterAlt(localctx, 6) - self.state = 420 + self.enterOuterAlt(localctx, 7) + self.state = 428 self.match(RelayParser.T__26) - self.state = 421 + self.state = 429 self.match(RelayParser.T__7) - self.state = 422 + self.state = 430 self.shapeList() - self.state = 423 + self.state = 431 self.match(RelayParser.T__4) - self.state = 424 + self.state = 432 self.typeExpr() - self.state = 425 + self.state = 433 self.match(RelayParser.T__8) pass - elif la_ == 7: + elif la_ == 8: localctx = RelayParser.FuncTypeContext(self, localctx) - self.enterOuterAlt(localctx, 7) - self.state = 427 + self.enterOuterAlt(localctx, 8) + self.state = 435 self.match(RelayParser.T__17) - self.state = 429 + self.state = 437 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__7: - self.state = 428 + self.state = 436 self.typeParamList() - self.state = 431 + self.state = 439 self.match(RelayParser.T__5) - self.state = 440 + self.state = 448 self._errHandler.sync(self) _la = self._input.LA(1) if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << RelayParser.T__3) | (1 << RelayParser.T__5) | (1 << RelayParser.T__17) | (1 << RelayParser.T__26) | (1 << RelayParser.CNAME))) != 0): - self.state = 432 + self.state = 440 self.typeExpr() - self.state = 437 + self.state = 445 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 433 + self.state = 441 self.match(RelayParser.T__4) - self.state = 434 + self.state = 442 self.typeExpr() - self.state = 439 + self.state = 447 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 442 + self.state = 450 self.match(RelayParser.T__6) - self.state = 443 + self.state = 451 self.match(RelayParser.T__18) - self.state = 444 + self.state = 452 self.typeExpr() pass - elif la_ == 8: + elif la_ == 9: localctx = RelayParser.IncompleteTypeContext(self, localctx) - self.enterOuterAlt(localctx, 8) - self.state = 445 + self.enterOuterAlt(localctx, 9) + self.state = 453 self.match(RelayParser.T__3) pass @@ -3070,11 +3124,11 @@ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): super().__init__(parent, invokingState) self.parser = parser - def generalIdent(self, i:int=None): + def typeExpr(self, i:int=None): if i is None: - return self.getTypedRuleContexts(RelayParser.GeneralIdentContext) + return self.getTypedRuleContexts(RelayParser.TypeExprContext) else: - return self.getTypedRuleContext(RelayParser.GeneralIdentContext,i) + return self.getTypedRuleContext(RelayParser.TypeExprContext,i) def getRuleIndex(self): @@ -3096,23 +3150,23 @@ def typeParamList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 448 + self.state = 456 self.match(RelayParser.T__7) - self.state = 449 - self.generalIdent() - self.state = 454 + self.state = 457 + self.typeExpr() + self.state = 462 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 450 + self.state = 458 self.match(RelayParser.T__4) - self.state = 451 - self.generalIdent() - self.state = 456 + self.state = 459 + self.typeExpr() + self.state = 464 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 457 + self.state = 465 self.match(RelayParser.T__8) except RecognitionException as re: localctx.exception = re @@ -3154,44 +3208,44 @@ def shapeList(self): self.enterRule(localctx, 56, self.RULE_shapeList) self._la = 0 # Token type try: - self.state = 472 + self.state = 480 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,50,self._ctx) + la_ = self._interp.adaptivePredict(self._input,51,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 459 + self.state = 467 self.match(RelayParser.T__5) - self.state = 460 + self.state = 468 self.match(RelayParser.T__6) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 461 + self.state = 469 self.match(RelayParser.T__5) - self.state = 462 + self.state = 470 self.shape() - self.state = 465 + self.state = 473 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 463 + self.state = 471 self.match(RelayParser.T__4) - self.state = 464 + self.state = 472 self.shape() - self.state = 467 + self.state = 475 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==RelayParser.T__4): break - self.state = 469 + self.state = 477 self.match(RelayParser.T__6) pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 471 + self.state = 479 self.shape() pass @@ -3235,19 +3289,19 @@ def meta(self): self.enterRule(localctx, 58, self.RULE_meta) try: self.enterOuterAlt(localctx, 1) - self.state = 474 + self.state = 482 self.match(RelayParser.T__27) - self.state = 475 + self.state = 483 self.match(RelayParser.T__7) - self.state = 476 + self.state = 484 self.match(RelayParser.CNAME) - self.state = 477 + self.state = 485 self.match(RelayParser.T__8) - self.state = 478 + self.state = 486 self.match(RelayParser.T__7) - self.state = 479 + self.state = 487 self.match(RelayParser.NAT) - self.state = 480 + self.state = 488 self.match(RelayParser.T__8) except RecognitionException as re: localctx.exception = re @@ -3330,29 +3384,29 @@ def shape(self): localctx = RelayParser.ShapeContext(self, self._ctx, self.state) self.enterRule(localctx, 60, self.RULE_shape) try: - self.state = 488 + self.state = 496 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.T__27]: localctx = RelayParser.MetaShapeContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 482 + self.state = 490 self.meta() pass elif token in [RelayParser.T__5]: localctx = RelayParser.ParensShapeContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 483 + self.state = 491 self.match(RelayParser.T__5) - self.state = 484 + self.state = 492 self.shape() - self.state = 485 + self.state = 493 self.match(RelayParser.T__6) pass elif token in [RelayParser.NAT]: localctx = RelayParser.IntShapeContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 487 + self.state = 495 self.match(RelayParser.NAT) pass else: @@ -3395,11 +3449,11 @@ def body(self): self.enterRule(localctx, 62, self.RULE_body) try: self.enterOuterAlt(localctx, 1) - self.state = 490 + self.state = 498 self.match(RelayParser.T__11) - self.state = 491 + self.state = 499 self.expr(0) - self.state = 492 + self.state = 500 self.match(RelayParser.T__12) except RecognitionException as re: localctx.exception = re @@ -3480,25 +3534,25 @@ def scalar(self): localctx = RelayParser.ScalarContext(self, self._ctx, self.state) self.enterRule(localctx, 64, self.RULE_scalar) try: - self.state = 497 + self.state = 505 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.FLOAT]: localctx = RelayParser.ScalarFloatContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 494 + self.state = 502 self.match(RelayParser.FLOAT) pass elif token in [RelayParser.NAT]: localctx = RelayParser.ScalarIntContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 495 + self.state = 503 self.match(RelayParser.NAT) pass elif token in [RelayParser.BOOL_LIT]: localctx = RelayParser.ScalarBoolContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 496 + self.state = 504 self.match(RelayParser.BOOL_LIT) pass else: @@ -3552,30 +3606,30 @@ def ident(self): localctx = RelayParser.IdentContext(self, self._ctx, self.state) self.enterRule(localctx, 66, self.RULE_ident) try: - self.state = 503 + self.state = 511 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,53,self._ctx) + la_ = self._interp.adaptivePredict(self._input,54,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 499 + self.state = 507 self.generalIdent() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 500 + self.state = 508 self.globalVar() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 501 + self.state = 509 self.localVar() pass elif la_ == 4: self.enterOuterAlt(localctx, 4) - self.state = 502 + self.state = 510 self.graphVar() pass diff --git a/python/tvm/relay/grammar/py3/RelayVisitor.py b/python/tvm/relay/grammar/py3/RelayVisitor.py index 98dd09fef669..f0a3f1964f24 100644 --- a/python/tvm/relay/grammar/py3/RelayVisitor.py +++ b/python/tvm/relay/grammar/py3/RelayVisitor.py @@ -239,6 +239,11 @@ def visitTupleType(self, ctx:RelayParser.TupleTypeContext): return self.visitChildren(ctx) + # Visit a parse tree produced by RelayParser#typeParen. + def visitTypeParen(self, ctx:RelayParser.TypeParenContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by RelayParser#typeCallType. def visitTypeCallType(self, ctx:RelayParser.TypeCallTypeContext): return self.visitChildren(ctx) From 8a6e2a234b7388288e057cdc78719acd17c0f41c Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 15:20:15 -0700 Subject: [PATCH 02/15] Doc fix --- include/tvm/expr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/tvm/expr.h b/include/tvm/expr.h index 07cfbc7791da..201a2b485aa6 100644 --- a/include/tvm/expr.h +++ b/include/tvm/expr.h @@ -92,7 +92,7 @@ class Var; /*! * \brief A variable node in the IR. * - * A vraible is uniquely identified by its address. + * A variable is uniquely identified by its address. * * Each variable is only binded once in the following nodes: * - Allocate From 15a39ed10b4a5388fd8890c67dbe1b0f0a034ce4 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 15:48:53 -0700 Subject: [PATCH 03/15] Add module utility functions necessary for prelude --- include/tvm/relay/module.h | 32 +++++++++++++++- python/tvm/relay/module.py | 22 ++++++++++- src/relay/ir/base.cc | 4 +- src/relay/ir/module.cc | 77 ++++++++++++++++++++++++++++++-------- 4 files changed, 116 insertions(+), 19 deletions(-) diff --git a/include/tvm/relay/module.h b/include/tvm/relay/module.h index ee9b4873d28a..c7ff5bea071f 100644 --- a/include/tvm/relay/module.h +++ b/include/tvm/relay/module.h @@ -91,8 +91,10 @@ class ModuleNode : public RelayNode { * \brief Add a type-level definition to the global environment. * \param var The var of the global type definition. * \param type The type definition. + * \param update Controls whether you can replace a definition in the + * environment. */ - TVM_DLL void AddDef(const GlobalTypeVar& var, const TypeData& type); + TVM_DLL void AddDef(const GlobalTypeVar& var, const TypeData& type, bool update = false); /*! * \brief Add a function to the global environment. @@ -103,6 +105,15 @@ class ModuleNode : public RelayNode { */ TVM_DLL void AddUnchecked(const GlobalVar& var, const Function& func); + /*! + * \brief Add a type definition to the global environment. + * \param var The name of the global function. + * \param func The function. + * + * It does not do type inference as AddDef does. + */ + TVM_DLL void AddDefUnchecked(const GlobalTypeVar& var, const TypeData& type); + /*! * \brief Update a function in the global environment. * \param var The name of the global function to update. @@ -110,6 +121,13 @@ class ModuleNode : public RelayNode { */ TVM_DLL void Update(const GlobalVar& var, const Function& func); + /*! + * \brief Update a type definition in the global environment. + * \param var The name of the global type definition to update. + * \param func The new function. + */ + TVM_DLL void UpdateDef(const GlobalTypeVar& var, const TypeData& type); + /*! * \brief Remove a function from the global environment. * \param var The name of the global function to update. @@ -130,6 +148,12 @@ class ModuleNode : public RelayNode { */ TVM_DLL GlobalVar GetGlobalVar(const std::string& str) const; + /*! + * \brief Collect all global vars defined in this module. + * \returns An array of global vars + */ + tvm::Array GetGlobalVars() const; + /*! * \brief Look up a global function by its name. * \param str The unique string specifying the global variable. @@ -137,6 +161,12 @@ class ModuleNode : public RelayNode { */ TVM_DLL GlobalTypeVar GetGlobalTypeVar(const std::string& str) const; + /*! + * \brief Collect all global type vars defined in this module. + * \returns An array of global type vars + */ + tvm::Array GetGlobalTypeVars() const; + /*! * \brief Look up a global function by its variable. * \param var The global var to lookup. diff --git a/python/tvm/relay/module.py b/python/tvm/relay/module.py index 57980dd09cf2..5513bd711c4f 100644 --- a/python/tvm/relay/module.py +++ b/python/tvm/relay/module.py @@ -96,7 +96,7 @@ def _add(self, var, val, update=False): assert isinstance(val, _ty.Type) if isinstance(var, _base.string_types): var = _ty.GlobalTypeVar(var) - _module.Module_AddDef(self, var, val) + _module.Module_AddDef(self, var, val, update) def __getitem__(self, var): """Lookup a global definition by name or by variable. @@ -149,6 +149,26 @@ def get_global_var(self, name): """ return _module.Module_GetGlobalVar(self, name) + def get_global_vars(self): + """Collect all global vars defined in this module. + + Returns + ------- + global_vars: tvm.Array[GlobalVar] + An array of global vars. + """ + return _module.Module_GetGlobalVars(self) + + def get_global_type_vars(self): + """Collect all global type vars defined in this module. + + Returns + ------- + global_type_vars: tvm.Array[GlobalTypeVar] + An array of global type vars. + """ + return _module.Module_GetGlobalTypeVars(self) + def get_global_type_var(self, name): """Get a global type variable in the function by name. diff --git a/src/relay/ir/base.cc b/src/relay/ir/base.cc index f60f6594559c..2032112f2a85 100644 --- a/src/relay/ir/base.cc +++ b/src/relay/ir/base.cc @@ -6,9 +6,9 @@ * 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 diff --git a/src/relay/ir/module.cc b/src/relay/ir/module.cc index 2601f355d03e..1ab3ad70adbf 100644 --- a/src/relay/ir/module.cc +++ b/src/relay/ir/module.cc @@ -73,20 +73,12 @@ GlobalVar ModuleNode::GetGlobalVar(const std::string& name) const { return (*it).second; } -void ModuleNode::AddUnchecked(const GlobalVar& var, - const Function& func) { - auto mod = GetRef(this); - this->functions.Set(var, func); - - auto it = global_var_map_.find(var->name_hint); - if (it != global_var_map_.end()) { - CHECK_EQ((*it).second, var); - } else { - CHECK(!global_var_map_.count(var->name_hint)) - << "Duplicate global function name " << var->name_hint; +tvm::Array ModuleNode::GetGlobalVars() const { + std::vector global_vars; + for (const auto& pair : global_var_map_) { + global_vars.push_back(pair.second); } - - global_var_map_.Set(var->name_hint, var); + return tvm::Array(global_vars); } GlobalTypeVar ModuleNode::GetGlobalTypeVar(const std::string& name) const { @@ -97,6 +89,14 @@ GlobalTypeVar ModuleNode::GetGlobalTypeVar(const std::string& name) const { return (*it).second; } +tvm::Array ModuleNode::GetGlobalTypeVars() const { + std::vector global_type_vars; + for (const auto& pair : global_type_var_map_) { + global_type_vars.push_back(pair.second); + } + return tvm::Array(global_type_vars); +} + template tvm::Array concat(const tvm::Array& l, const tvm::Array& r) { tvm::Array ret(l); @@ -151,6 +151,22 @@ void ModuleNode::Add(const GlobalVar& var, AddUnchecked(var, checked_func); } +void ModuleNode::AddUnchecked(const GlobalVar& var, + const Function& func) { + auto mod = GetRef(this); + this->functions.Set(var, func); + + auto it = global_var_map_.find(var->name_hint); + if (it != global_var_map_.end()) { + CHECK_EQ((*it).second, var); + } else { + CHECK(!global_var_map_.count(var->name_hint)) + << "Duplicate global function name " << var->name_hint; + } + + global_var_map_.Set(var->name_hint, var); +} + void ModuleNode::RegisterConstructors(const GlobalTypeVar& var, const TypeData& type) { // We hash the global type var name to use as a globally unique prefix for tags. // The hash will be used as the most significant byte of the tag, with the index of @@ -163,10 +179,10 @@ void ModuleNode::RegisterConstructors(const GlobalTypeVar& var, const TypeData& } } -void ModuleNode::AddDef(const GlobalTypeVar& var, const TypeData& type) { +void ModuleNode::AddDef(const GlobalTypeVar& var, const TypeData& type, bool update) { this->type_definitions.Set(var, type); // set global type var map - CHECK(!global_type_var_map_.count(var->var->name_hint)) + CHECK(update || global_type_var_map_.count(var->var->name_hint) == 0) << "Duplicate global type definition name " << var->var->name_hint; global_type_var_map_.Set(var->var->name_hint, var); @@ -178,10 +194,23 @@ void ModuleNode::AddDef(const GlobalTypeVar& var, const TypeData& type) { << "Invalid or malformed typedata given to module: " << type; } +void ModuleNode::AddDefUnchecked(const GlobalTypeVar& var, const TypeData& type) { + this->type_definitions.Set(var, type); + // set global type var map + CHECK(!global_type_var_map_.count(var->var->name_hint)) + << "Duplicate global type definition name " << var->var->name_hint; + global_type_var_map_.Set(var->var->name_hint, var); + RegisterConstructors(var, type); +} + void ModuleNode::Update(const GlobalVar& var, const Function& func) { this->Add(var, func, true); } +void ModuleNode::UpdateDef(const GlobalTypeVar& var, const TypeData& type) { + this->AddDef(var, type, true); +} + void ModuleNode::Remove(const GlobalVar& var) { auto functions_node = this->functions.CopyOnWrite(); functions_node->data.erase(var.node_); @@ -226,6 +255,18 @@ Constructor ModuleNode::LookupTag(const int32_t tag) { } void ModuleNode::Update(const Module& mod) { + // add type defs. we add them unchecked first, so all definitions can + // reference each other, independent of the order in which they were defined. + for (auto pair : mod->type_definitions) { + this->AddDefUnchecked(pair.first, pair.second); + } + for (auto pair : mod->type_definitions) { + this->UpdateDef(pair.first, pair.second); + } + // then add func defs in a similar fashion + for (auto pair : mod->functions) { + this->AddUnchecked(pair.first, pair.second); + } for (auto pair : mod->functions) { this->Update(pair.first, pair.second); } @@ -315,6 +356,12 @@ TVM_REGISTER_API("relay._module.Module_AddDef") TVM_REGISTER_API("relay._module.Module_GetGlobalVar") .set_body_method(&ModuleNode::GetGlobalVar); +TVM_REGISTER_API("relay._module.Module_GetGlobalVars") +.set_body_method(&ModuleNode::GetGlobalVars); + +TVM_REGISTER_API("relay._module.Module_GetGlobalTypeVars") +.set_body_method(&ModuleNode::GetGlobalTypeVars); + TVM_REGISTER_API("relay._module.Module_ContainGlobalVar") .set_body_method(&ModuleNode::ContainGlobalVar); From 34d108fdef6096a7d7e7b3b02b227511e50705a2 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 15:51:11 -0700 Subject: [PATCH 04/15] Implement prelude in text format --- python/tvm/relay/prelude.py | 28 --- python/tvm/relay/std/prelude.rly | 293 ++++++++++++++++++++++++++++++- 2 files changed, 287 insertions(+), 34 deletions(-) diff --git a/python/tvm/relay/prelude.py b/python/tvm/relay/prelude.py index d05b669ee7f1..e7a8535bdc82 100644 --- a/python/tvm/relay/prelude.py +++ b/python/tvm/relay/prelude.py @@ -487,31 +487,3 @@ def __init__(self, mod=None): mod = Module() self.mod = mod self.load_prelude() - self.define_list_adt() - self.define_list_hd() - self.define_list_tl() - self.define_list_map() - self.define_list_foldl() - self.define_list_foldr() - self.define_list_foldr1() - self.define_list_concat() - self.define_list_filter() - self.define_list_zip() - self.define_list_rev() - self.define_list_map_accumr() - self.define_list_map_accuml() - - self.define_optional_adt() - self.define_list_unfoldr() - self.define_list_unfoldl() - - self.define_list_length() - self.define_list_nth() - self.define_list_update() - self.define_list_sum() - - self.define_tree_adt() - self.define_tree_map() - self.define_tree_size() - - self.define_iterate() diff --git a/python/tvm/relay/std/prelude.rly b/python/tvm/relay/std/prelude.rly index 6b6047c1b0a7..1beb6647bc3f 100644 --- a/python/tvm/relay/std/prelude.rly +++ b/python/tvm/relay/std/prelude.rly @@ -18,12 +18,293 @@ */ v0.0.4 -def @id[a](%x: a) -> a { - %x +// TODO(weberlo): should we add sugar for scalar types (e.g., `int32` => `Tensor[(), int32]`)? + +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)) + } +} + +/* + * A LISP-style list ADT. An empty list is represented by `Nil`, and a member + * `x` can be appended to the front of a list `l` via the constructor `Cons(x, l)`. + */ +type List[A] { + Cons(A, List[A]), + Nil, +} + +/* + * Get the head of a list. Assume the list has at least one element. + */ +def @hd[A](%xs: List[A]) -> A { + match? (%xs) { + Cons(%x, _) => %x, + } +} + +/* + * Get the tail of a list. + */ +def @tl[A](%xs: List[A]) -> List[A] { + match? (%xs) { + Cons(_, %rest) => %rest, + } +} + +/* + * Get the `n`th element of a list. + */ +def @nth[A](%xs: List[A], %n: Tensor[(), int32]) -> A { + if (%n == 0) { + @hd(%xs) + } else { + @nth(@tl(%xs), %n - 1) + } +} + +/* + * Return the length of a list. + */ +def @length[A](%xs: List[A]) -> Tensor[(), int32] { + match (%xs) { + Cons(_, %rest) => 1 + @length(%rest), + Nil => 0, + } +} + +/* + * Update the `n`th element of a list and return the updated list. + */ +def @update[A](%xs: List[A], %n: Tensor[(), int32], %v: A) -> List[A] { + if (%n == 0) { + Cons(%v, @tl(%xs)) + } else { + Cons(@hd(%xs), @update(@tl(%xs), %n - 1, %v)) + } } -def @compose[a, b, c](%f: fn(b) -> c, %g: fn(a) -> b) { - fn (%x: a) -> c { - %f(%g(%x)) - } +/* + * Map a function over a list's elements. That is, `map(f, xs)` returns a new + * list where the `i`th member is `f` applied to the `i`th member of `xs`. + */ +def @map[A, B](%f: fn(A) -> B, %xs: List[A]) -> List[B] { + match (%xs) { + Cons(%x, %rest) => Cons(%f(%x), @map(%f, %rest)), + Nil => Nil, + } +} + +/* + * A left-way fold over a list. + * + * `foldl(f, z, cons(a1, cons(a2, cons(a3, cons(..., nil)))))` + * evaluates to `f(...f(f(f(z, a1), a2), a3)...)`. + */ +def @foldl[A, B](%f: fn(A, B) -> A, %acc: A, %xs: List[B]) -> A { + match (%xs) { + Cons(%x, %rest) => @foldl(%f, %f(%acc, %x), %rest), + Nil => %acc, + } +} + +/* + * A right-way fold over a list. + * + * `foldr(f, cons(a1, cons(a2, cons(..., cons(an, nil)))), z)` + * evaluates to `f(a1, f(a2, f(..., f(an, z)))...)`. + */ +def @foldr[A, B](%f: fn(A, B) -> B, %xs: List[A], %acc: B) -> B { + match (%xs) { + Cons(%x, %rest) => %f(%x, @foldr(%f, %rest, %acc)), + Nil => %acc, + } +} + +/* + * A right-way fold over a nonempty list. + * + * `foldr1(f, cons(a1, cons(a2, cons(..., cons(an, nil)))))` + * evaluates to `f(a1, f(a2, f(..., f(an-1, an)))...)` + */ +def @foldr1[A](%f: fn(A, A) -> A, %xs: List[A]) -> A { + match? (%xs) { + Cons(%x, Nil) => %x, + Cons(%x, %rest) => %f(%x, @foldr1(%f, %rest)), + } +} + +/* + * Computes the sum of a list of integer scalars. + */ +def @sum(%xs: List[Tensor[(), int32]]) { + let %add_f = fn(%x: Tensor[(), int32], %y: Tensor[(), int32]) -> Tensor[(), int32] { + %x + %y + }; + @foldl(%add_f, 0, %xs) +} + +/* + * Concatenates two lists. + */ +def @concat[A](%xs: List[A], %ys: List[A]) -> List[A] { + // TODO(weberlo): allow using `Cons` directly as the arg to foldr + let %updater = fn(%x: A, %yss: List[A]) -> List[A] { + Cons(%x, %yss) + }; + @foldr(%updater, %ys, %xs) +} + +/* + * Filters a list, returning a sublist of only the values which satisfy the given predicate. + */ +def @filter[A](%f: fn(A) -> Tensor[(), bool], %xs: List[A]) -> List[A] { + match (%xs) { + Cons(%x, %rest) => { + if (%f(%x)) { + Cons(%x, @filter(%f, %rest)) + } else { + @filter(%f, %rest) + } + }, + Nil => Nil, + } +} + +/* + * Combines two lists into a list of tuples of their elements. + * + * The zipped list will be the length of the shorter list. + */ +def @zip[A, B](%xs: List[A], %ys: List[B]) -> List[(A, B)] { + match (%xs) { + Cons(%x, %x_rest) => match (%ys) { + Cons(%y, %y_rest) => Cons((%x, %y), @zip(%x_rest, %y_rest)), + Nil => Nil, + }, + Nil => Nil, + } +} + +/* + * Reverses a list. + */ +def @reverse[A](%xs: List[A]) -> List[A] { + let %updater = fn(%ys: List[A], %x: A) -> List[A] { + Cons(%x, %ys) + }; + @foldl(%updater, Nil, %xs) +} + +/* + * An accumulative map, which is a fold that simulataneously updates an + * accumulator value and a list of results. + * + * This map proceeds through the list from right to left. + */ +def @map_accumr[A, B, C](%f: fn(A, B) -> (A, C), %init: A, %xs: List[B]) -> (A, List[C]) { + let %updater = fn(%x: B, %acc: (A, List[C])) -> (A, List[C]) { + let %f_out = %f(%acc.0, %x); + (%f_out.0, Cons(%f_out.1, %acc.1)) + }; + @foldr(%updater, %xs, (%init, Nil)) +} + +/* + * an accumulative map, which is a fold that simulataneously updates an + * accumulator value and a list of results. + * + * This map proceeds through the list from left to right. + */ +def @map_accuml[A, B, C](%f: fn(A, B) -> (A, C), %init: A, %xs: List[B]) -> (A, List[C]) { + let %updater = fn(%acc: (A, List[C]), %x: B) -> (A, List[C]) { + let %f_out = %f(%acc.0, %x); + (%f_out.0, Cons(%f_out.1, %acc.1)) + }; + @foldl(%updater, (%init, Nil), %xs) +} + +/* + * An optional ADT, which can either contain some other type or nothing at all. + */ +type Option[A] { + Some(A), + None, +} + +/* + * Builds up a list starting from a seed value. + * + * `f` returns an option containing a new seed and an output value. `f` will + * continue to be called on the new seeds until it returns `None`. All the output + * values will be combined into a list, right to left. + */ +def @unfoldr[A, B](%f: fn(A) -> Option[(A, B)], %seed: A) -> List[B] { + match (%f(%seed)) { + Some(%val) => Cons(%val.1, @unfoldr(%f, %val.0)), + None => Nil, + } +} + +/* + * Builds up a list starting from a seed value. + * + * `f` returns an option containing a new seed and an output value. `f` will + * continue to be called on the new seeds until it returns `None`. All the + * output values will be combined into a list, left to right. + */ +def @unfoldl[A, B](%f: fn(A) -> Option[(A, B)], %seed: A) -> List[B] { + @reverse(@unfoldr(%f, %seed)) +} + +/* + * A tree ADT. A tree can contain any type. It has only one + * constructor, rose(x, l), where x is the content of that point of the tree + * and l is a list of more trees of the same type. A leaf is thus rose(x, + * nil()). + */ +type Tree[A] { + Rose(A, List[Tree[A]]), +} + +/* + * Maps over a tree. The function is applied to each subtree's contents. + */ +def @tmap[A, B](%f: fn(A) -> B, %t: Tree[A]) -> Tree[B] { + match(%t) { + Rose(%v, %sub_trees) => { + let %list_f = fn(%tt: Tree[A]) -> Tree[B] { + @tmap(%f, %tt) + }; + Rose(%f(%v), @map(%list_f, %sub_trees)) + }, + } +} + +/* + * Computes the size of a tree. + */ +def @size[A](%t: Tree[A]) -> Tensor[(), int32] { + match(%t) { + Rose(_, %sub_trees) => { + 1 + @sum(@map(@size, %sub_trees)) + }, + } +} + +/* + * Takes a number n and a function f; returns a closure that takes an argument + * and applies f n times to its argument. + */ +def @iterate[A](%f: fn(A) -> A, %n: Tensor[(), int32]) -> (fn(A) -> A) { + if (%n == 0) { + @id + } else { + @compose(%f, @iterate(%f, %n - 1)) + } } From e221f8fffcaa629c126e3445a18a3238bfaabb15 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 15:53:37 -0700 Subject: [PATCH 05/15] Remove programmatically constructed prelude defs --- python/tvm/relay/prelude.py | 461 +------------------------------ python/tvm/relay/std/prelude.rly | 9 +- 2 files changed, 9 insertions(+), 461 deletions(-) diff --git a/python/tvm/relay/prelude.py b/python/tvm/relay/prelude.py index e7a8535bdc82..6a31210c76d7 100644 --- a/python/tvm/relay/prelude.py +++ b/python/tvm/relay/prelude.py @@ -26,464 +26,15 @@ class Prelude: """Contains standard definitions.""" - def define_list_adt(self): - """Defines a LISP-style list ADT. An empty list is - represented by nil(). A member x can be appended to the - front of a list l via the constructor cons(x, l).""" - self.l = GlobalTypeVar("list") - a = TypeVar("a") - self.nil = Constructor("nil", [], self.l) - self.cons = Constructor("cons", [a, self.l(a)], self.l) - self.mod[self.l] = TypeData(self.l, [a], [self.nil, self.cons]) - - def define_list_hd(self): - """Defines a function to get the head of a list. Assume the list has at least one - element. - - hd(l) : list[a] -> a - """ - self.hd = GlobalVar("hd") - a = TypeVar("a") - x = Var("x", self.l(a)) - y = Var("y") - z = Var("z") - cons_case = Clause(PatternConstructor(self.cons, [PatternVar(y), PatternVar(z)]), y) - self.mod[self.hd] = Function([x], Match(x, [cons_case], False), a, [a]) - - def define_list_tl(self): - """Defines a function to get the tail of a list. - - tl(l) : list[a] -> list[a] - """ - self.tl = GlobalVar("tl") - a = TypeVar("a") - x = Var("x", self.l(a)) - y = Var("y") - z = Var("z") - cons_case = Clause(PatternConstructor(self.cons, [PatternVar(y), PatternVar(z)]), z) - self.mod[self.tl] = Function([x], Match(x, [cons_case], False), self.l(a), [a]) - - - def define_list_nth(self): - """Defines a function to get the nth element of a list. - - nth(l) : list[a] -> Tensor[(), int32] -> a - """ - self.nth = GlobalVar("nth") - a = TypeVar("a") - x = Var("x", self.l(a)) - n = Var("n", scalar_type('int32')) - - body = If(equal(n, const(0)), - self.hd(x), - self.nth(self.tl(x), subtract(n, const(1)))) - - self.mod[self.nth] = Function([x, n], body, a, [a]) - - - def define_list_update(self): - """Defines a function to update the nth element of a list and return the updated list. - - update(l, i, v) : list[a] -> Tensor[(), int32] -> a -> list[a] - """ - self.update = GlobalVar("update") - a = TypeVar("a") - l = Var("l", self.l(a)) - n = Var("n", scalar_type('int32')) - v = Var("v", a) - - body = If(equal(n, const(0)), - self.cons(v, self.tl(l)), - self.cons(self.hd(l), - self.update(self.tl(l), - subtract(n, const(1)), - v))) - - self.mod[self.update] = Function([l, n, v], body, self.l(a), [a]) - - - def define_list_map(self): - """Defines a function for mapping a function over a list's - elements. That is, map(f, l) returns a new list where - the ith member is f applied to the ith member of l. - - map(f, l) : fn(fn(a) -> b, list[a]) -> list[b] - """ - self.map = GlobalVar("map") - a = TypeVar("a") - b = TypeVar("b") - f = Var("f", FuncType([a], b)) - x = Var("x", self.l(a)) - y = Var("y") - z = Var("z") - nil_case = Clause(PatternConstructor(self.nil), self.nil()) - cons_case = Clause(PatternConstructor(self.cons, [PatternVar(y), PatternVar(z)]), - self.cons(f(y), self.map(f, z))) - self.mod[self.map] = Function([f, x], Match(x, [nil_case, cons_case]), self.l(b), [a, b]) - - - def define_list_foldl(self): - """Defines a left-way fold over a list. - - foldl(f, z, l) : fn(fn(a, b) -> a, a, list[b]) -> a - - foldl(f, z, cons(a1, cons(a2, cons(a3, cons(..., nil))))) - evaluates to f(...f(f(f(z, a1), a2), a3)...) - """ - self.foldl = GlobalVar("foldl") - a = TypeVar("a") - b = TypeVar("b") - f = Var("f", FuncType([a, b], a)) - av = Var("av", a) - bv = Var("bv", self.l(b)) - y = Var("y") - z = Var("z") - nil_case = Clause(PatternConstructor(self.nil), av) - cons_case = Clause(PatternConstructor(self.cons, [PatternVar(y), PatternVar(z)]), - self.foldl(f, f(av, y), z)) - self.mod[self.foldl] = Function([f, av, bv], - Match(bv, [nil_case, cons_case]), a, [a, b]) - - - def define_list_foldr(self): - """Defines a right-way fold over a list. - - foldr(f, l, z) : fn(fn(a, b) -> b, list[a], b) -> b - - foldr(f, cons(a1, cons(a2, cons(..., cons(an, nil)))), z) - evalutes to f(a1, f(a2, f(..., f(an, z)))...) - """ - self.foldr = GlobalVar("foldr") - a = TypeVar("a") - b = TypeVar("b") - f = Var("f", FuncType([a, b], b)) - av = Var("av", self.l(a)) - bv = Var("bv", b) - y = Var("y") - z = Var("z") - nil_case = Clause(PatternConstructor(self.nil), bv) - cons_case = Clause(PatternConstructor(self.cons, [PatternVar(y), PatternVar(z)]), - f(y, self.foldr(f, bv, z))) - self.mod[self.foldr] = Function([f, bv, av], - Match(av, [nil_case, cons_case]), b, [a, b]) - - - def define_list_foldr1(self): - """Defines a right-way fold over a nonempty list. - - foldr1(f, l) : fn(fn(a, a) -> a, list[a]) -> a - - foldr1(f, cons(a1, cons(a2, cons(..., cons(an, nil))))) - evalutes to f(a1, f(a2, f(..., f(an-1, an)))...) - """ - self.foldr1 = GlobalVar("foldr1") - a = TypeVar("a") - f = Var("f", FuncType([a, a], a)) - av = Var("av", self.l(a)) - x = Var("x") - y = Var("y") - z = Var("z") - one_case = Clause(PatternConstructor(self.cons, - [PatternVar(x), PatternConstructor(self.nil)]), x) - cons_case = Clause(PatternConstructor(self.cons, [PatternVar(y), PatternVar(z)]), - f(y, self.foldr1(f, z))) - self.mod[self.foldr1] = Function([f, av], - Match(av, [one_case, cons_case], False), a, [a]) - - - def define_list_concat(self): - """Defines a function that concatenates two lists. - - concat(l1, l2) : fn(list[a], list[a]) -> list[a]""" - self.concat = GlobalVar("concat") - a = TypeVar("a") - l1 = Var("l1", self.l(a)) - l2 = Var("l2", self.l(a)) - h = Var("h") - t = Var("t") - updater = Function([h, t], self.cons(h, t)) - self.mod[self.concat] = Function([l1, l2], - self.foldr(updater, l2, l1), - self.l(a), [a]) - - - def define_list_filter(self): - """Defines a function that filters a list. - - filter(f, l) : fn(fn(a) -> Tensor[(), bool], list[a]) -> list[a] - - It returns the sublist of l consisting of the elements for which f returns true. - """ - self.filter = GlobalVar("filter") - a = TypeVar("a") - f = Var("f", FuncType([a], scalar_type("bool"))) - l = Var("l", self.l(a)) - h = Var("h") - t = Var("t") - nil_case = Clause(PatternConstructor(self.nil), self.nil()) - cons_case = Clause(PatternConstructor(self.cons, [PatternVar(h), PatternVar(t)]), - If(f(h), self.cons(h, self.filter(f, t)), self.filter(f, t))) - self.mod[self.filter] = Function([f, l], Match(l, [nil_case, cons_case]), self.l(a), [a]) - - - def define_list_zip(self): - """Defines a function that combines two lists into a list of tuples of their elements. - - zip(l, m) : fn(list[a], list[b]) -> list[(a, b)] - - The zipped list will be the length of the shorter list. - """ - self.zip = GlobalVar("zip") - a = TypeVar("a") - b = TypeVar("b") - l1 = Var("l1") - l2 = Var("l2") - h1 = Var("h1") - h2 = Var("h2") - t1 = Var("t1") - t2 = Var("t2") - cons_case = Clause(PatternTuple([PatternConstructor(self.cons, - [PatternVar(h1), PatternVar(t1)]), - PatternConstructor(self.cons, - [PatternVar(h2), PatternVar(t2)])]), - self.cons(Tuple([h1, h2]), self.zip(t1, t2))) - nil_case = Clause(PatternWildcard(), self.nil()) - self.mod[self.zip] = Function([l1, l2], Match(Tuple([l1, l2]), [cons_case, nil_case]), - self.l(TupleType([a, b])), [a, b]) - - - def define_list_rev(self): - """Defines a function that reverses a list. - - rev(l) : fn(list[a]) -> list[a] - """ - self.rev = GlobalVar("rev") - a = TypeVar("a") - l = Var("l", self.l(a)) - x = Var("x") - y = Var("y") - updater = Function([y, x], self.cons(x, y)) - self.mod[self.rev] = Function([l], - self.foldl(updater, self.nil(), l), - self.l(a), [a]) - - - def define_list_map_accumr(self): - """Defines an accumulative map, which is a fold that simulataneously updates - an accumulator value and a list of results. - - map_accumr(f, s, l) : fn(fn(a, b) -> (a, c), a, list[b]) -> (a, list[c]) - - This map proceeds through l from right to left. - """ - self.map_accumr = GlobalVar("map_accumr") - a = TypeVar("a") - b = TypeVar("b") - c = TypeVar("c") - f = Var("f", FuncType([a, b], TupleType([a, c]))) - acc = Var("acc", a) - l = Var("l", self.l(b)) - v = Var("v", b) - p = Var("p", TupleType([a, self.l(c)])) - f_out = Var("f_out", TupleType([a, c])) - updater = Function([v, p], - Let(f_out, f(TupleGetItem(p, 0), v), - Tuple([TupleGetItem(f_out, 0), - self.cons(TupleGetItem(f_out, 1), - TupleGetItem(p, 1))])), - TupleType([a, self.l(c)])) - self.mod[self.map_accumr] = Function([f, acc, l], - self.foldr(updater, Tuple([acc, self.nil()]), l), - TupleType([a, self.l(c)]), - [a, b, c]) - - - def define_list_map_accuml(self): - """Defines an accumulative map, which is a fold that simulataneously updates - an accumulator value and a list of results. - - map_accuml(f, s, l) : fn(fn(a, b) -> (a, c), a, list[b]) -> (a, list[c]) - - This map proceeds through l from left to right. - """ - self.map_accuml = GlobalVar("map_accuml") - a = TypeVar("a") - b = TypeVar("b") - c = TypeVar("c") - f = Var("f", FuncType([a, b], TupleType([a, c]))) - acc = Var("acc", a) - l = Var("l", self.l(b)) - v = Var("v", b) - p = Var("p", TupleType([a, self.l(c)])) - f_out = Var("f_out", TupleType([a, c])) - updater = Function([p, v], - Let(f_out, f(TupleGetItem(p, 0), v), - Tuple([TupleGetItem(f_out, 0), - self.cons(TupleGetItem(f_out, 1), - TupleGetItem(p, 1))])), - TupleType([a, self.l(c)])) - self.mod[self.map_accuml] = Function([f, acc, l], - self.foldl(updater, Tuple([acc, self.nil()]), l), - TupleType([a, self.l(c)]), - [a, b, c]) - - - def define_optional_adt(self): - """Defines an optional ADT, which can either contain some other - type or nothing at all.""" - self.optional = GlobalTypeVar("optional") - a = TypeVar("a") - self.some = Constructor("some", [a], self.optional) - self.none = Constructor("none", [], self.optional) - self.mod[self.optional] = TypeData(self.optional, [a], [self.some, self.none]) - - - def define_list_unfoldr(self): - """Defines a function that builds up a list starting from a seed value. - - unfoldr(f, s) : fn(fn(a) -> Optional[(a, b)], a) -> list[b] - - f returns an option containing a new seed and an output value. f will - continue to be called on the new seeds until it returns None. All the - output values will be combined into a list, right to left. - """ - self.unfoldr = GlobalVar("unfoldr") - a = TypeVar("a") - b = TypeVar("b") - f = Var("f", FuncType([a], self.optional(TupleType([a, b])))) - s = Var("s", a) - p = Var("p", TupleType([a, b])) - none_case = Clause(PatternConstructor(self.none), self.nil()) - some_case = Clause(PatternConstructor(self.some, [PatternVar(p)]), - self.cons(TupleGetItem(p, 1), - self.unfoldr(f, TupleGetItem(p, 0)))) - self.mod[self.unfoldr] = Function([f, s], Match(f(s), [none_case, some_case]), - self.l(b), [a, b]) - - - def define_list_unfoldl(self): - """Defines a function that builds up a list starting from a seed value. - - unfoldl(f, s) : fn(fn(a) -> Optional[(a, b)], a) -> list[b] - - f returns an option containing a new seed and an output value. f will - continue to be called on the new seeds until it returns None. All the - output values will be combined into a list, left to right. - """ - self.unfoldl = GlobalVar("unfoldl") - a = TypeVar("a") - b = TypeVar("b") - f = Var("f", FuncType([a], self.optional(TupleType([a, b])))) - s = Var("s", a) - # easiest way to implement is to do a right unfold and reverse - self.mod[self.unfoldl] = Function([f, s], - self.rev(self.unfoldr(f, s)), - self.l(b), [a, b]) - - - def define_list_sum(self): - """Defines a function that computes the sum of a list of integer scalars.""" - self.sum = GlobalVar("sum") - a = Var("a", self.l(scalar_type('int32'))) - x = Var('x') - y = Var('y') - addf = Function([x, y], add(x, y)) - self.mod[self.sum] = Function([a], self.foldl(addf, const(0), a)) - - - def define_list_length(self): - """Defines a function that returns the length of a list""" - self.length = GlobalVar("length") - a = TypeVar("a") - x = Var("x", self.l(a)) - y = Var("y") - nil_case = Clause(PatternConstructor(self.nil), const(0)) - cons_case = Clause(PatternConstructor(self.cons, [PatternWildcard(), PatternVar(y)]), - add(const(1), self.length(y))) - self.mod[self.length] = Function([x], - Match(x, [nil_case, cons_case]), scalar_type('int32'), [a]) - - - def define_tree_adt(self): - """Defines a tree ADT. A tree can contain any type. - It has only one constructor, rose(x, l), where x is the content - of that point of the tree and l is a list of more trees of the - same type. A leaf is thus rose(x, nil()). - """ - self.tree = GlobalTypeVar("tree") - a = TypeVar("a") - self.rose = Constructor("rose", [a, self.l(self.tree(a))], self.tree) - self.mod[self.tree] = TypeData(self.tree, [a], [self.rose]) - - - def define_tree_map(self): - """Defines a function that maps over a tree. The function - is applied to each subtree's contents. - - Signature: fn(f : fn(a) -> b, t : tree[a]) -> tree[b] - """ - self.tmap = GlobalVar("tmap") - a = TypeVar("a") - b = TypeVar("b") - t = Var("t", self.tree(a)) - f = Var("f", FuncType([a], b)) - x = Var("x", self.tree(a)) - y = Var("y") - z = Var("z") - rose_case = Clause(PatternConstructor(self.rose, [PatternVar(y), PatternVar(z)]), - self.rose(f(y), self.map(Function([x], self.tmap(f, x)), z))) - self.mod[self.tmap] = Function([f, t], - Match(t, [rose_case]), self.tree(b), [a, b]) - - - def define_tree_size(self): - """Defines a function that computes the size of a tree. - - Signature: fn(t : tree[a]) -> Tensor[(), int32] - """ - self.size = GlobalVar("size") - a = TypeVar("a") - t = Var("t", self.tree(a)) - z = Var("z") - rose_case = Clause(PatternConstructor(self.rose, [PatternWildcard(), PatternVar(z)]), - add(const(1), self.sum(self.map(self.size, z)))) - self.mod[self.size] = Function([t], - Match(t, [rose_case]), scalar_type('int32'), [a]) - - - 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 - n times to its argument. - - Signature: fn(f : fn(a) -> a, n : Tensor[(), int32]) -> fn(a) -> a - """ - self.iterate = GlobalVar("iterate") - a = TypeVar("a") - f = Var("f", FuncType([a], a)) - x = Var("x", scalar_type('int32')) - body = If(equal(x, const(0)), - self.id, - self.compose(f, - self.iterate(f, subtract(x, const(1))))) - self.mod[self.iterate] = Function([f, x], - body, - FuncType([a], a), - [a]) + def __init__(self, mod=None): + if mod is None: + mod = Module() + self.mod = mod + self.load_prelude() def load_prelude(self): - """ - Parses the portions of the Prelude written in Relay's text format and adds - them to the module. - """ + """Parses the Prelude from Relay's text format into a module.""" # TODO(@jroesch): we should remove this helper when we port over prelude self.mod.import_from_std("prelude.rly") self.id = self.mod.get_global_var("id") self.compose = self.mod.get_global_var("compose") - - - def __init__(self, mod=None): - if mod is None: - mod = Module() - self.mod = mod - self.load_prelude() diff --git a/python/tvm/relay/std/prelude.rly b/python/tvm/relay/std/prelude.rly index 1beb6647bc3f..f120cd3c7ae6 100644 --- a/python/tvm/relay/std/prelude.rly +++ b/python/tvm/relay/std/prelude.rly @@ -182,12 +182,9 @@ def @filter[A](%f: fn(A) -> Tensor[(), bool], %xs: List[A]) -> List[A] { * The zipped list will be the length of the shorter list. */ def @zip[A, B](%xs: List[A], %ys: List[B]) -> List[(A, B)] { - match (%xs) { - Cons(%x, %x_rest) => match (%ys) { - Cons(%y, %y_rest) => Cons((%x, %y), @zip(%x_rest, %y_rest)), - Nil => Nil, - }, - Nil => Nil, + match (%xs, %ys) { + (Cons(%x, %x_rest), Cons(%y, %y_rest)) => Cons((%x, %y), @zip(%x_rest, %y_rest)), + _ => Nil, } } From b12dc52699d01500266e7dbc9e3a8b8cb0da5284 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 16:12:01 -0700 Subject: [PATCH 06/15] Fix 0-arity type conses in pretty printer and test --- src/relay/ir/pretty_printer.cc | 8 +++++++- tests/python/relay/test_ir_parser.py | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/relay/ir/pretty_printer.cc b/src/relay/ir/pretty_printer.cc index 22bdbcbb2d6a..e361a00f8d80 100644 --- a/src/relay/ir/pretty_printer.cc +++ b/src/relay/ir/pretty_printer.cc @@ -570,7 +570,13 @@ class PrettyPrinter : } else { doc << Print(op->op); } - return doc << "(" << PrintSep(args) << ")"; + + if (cons_node && cons_node->inputs.size() == 0) { + // don't print as a call if it's a 0-arity cons + return doc; + } else { + return doc << "(" << PrintSep(args) << ")"; + } } Doc VisitExpr_(const RefCreateNode* op) final { diff --git a/tests/python/relay/test_ir_parser.py b/tests/python/relay/test_ir_parser.py index e6104da5d7d1..e9a24bfa31d0 100644 --- a/tests/python/relay/test_ir_parser.py +++ b/tests/python/relay/test_ir_parser.py @@ -800,12 +800,13 @@ def test_adt_cons_expr(): %s def @make_singleton(%%x: int32) -> List[int32] { - Cons(%%x, Nil()) + Cons(%%x, Nil) } """ % LIST_DEFN, mod ) + @raises_parse_error def test_duplicate_adt_defn(): parse_text( From e85ba134e04108d13262d4713505ecb5c41bb5c8 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 16:44:32 -0700 Subject: [PATCH 07/15] Make prelude loading backwards-compatible --- python/tvm/relay/prelude.py | 42 +++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/python/tvm/relay/prelude.py b/python/tvm/relay/prelude.py index 6a31210c76d7..93bba57975d8 100644 --- a/python/tvm/relay/prelude.py +++ b/python/tvm/relay/prelude.py @@ -36,5 +36,43 @@ def load_prelude(self): """Parses the Prelude from Relay's text format into a module.""" # TODO(@jroesch): we should remove this helper when we port over prelude self.mod.import_from_std("prelude.rly") - self.id = self.mod.get_global_var("id") - self.compose = self.mod.get_global_var("compose") + + self.l = self.mod.get_global_type_var("List") + list_adt = self.mod[self.l] + self.cons = list_adt.constructors[0] + self.nil = list_adt.constructors[1] + + self.optional = self.mod.get_global_type_var("Option") + optional_adt = self.mod[self.optional] + self.some = optional_adt.constructors[0] + self.none = optional_adt.constructors[1] + + self.tree = self.mod.get_global_type_var("Tree") + tree_adt = self.mod[self.tree] + self.rose = tree_adt.constructors[0] + + GLOBAL_DEFS = [ + "hd", + "tl", + "nth", + "update", + "map", + "foldl", + "foldr", + "foldr1", + "concat", + "filter", + "zip", + "rev", + "map_accuml", + "map_accumr", + "unfoldl", + "unfoldr", + "sum", + "length", + "tmap", + "size", + "iterate", + ] + for global_def in GLOBAL_DEFS: + setattr(self, global_def, self.mod.get_global_var(global_def)) From 2ebb4a1d3f4f6b40d8f45b34d77f3bd4f4132454 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 18:08:15 -0700 Subject: [PATCH 08/15] Fix patterns --- python/tvm/relay/_parser.py | 58 +- python/tvm/relay/grammar/Relay.g4 | 53 +- python/tvm/relay/grammar/py3/RelayParser.py | 1082 +++++++++--------- python/tvm/relay/grammar/py3/RelayVisitor.py | 19 +- 4 files changed, 631 insertions(+), 581 deletions(-) diff --git a/python/tvm/relay/_parser.py b/python/tvm/relay/_parser.py index 9bb74d15e092..c63c9383e4f1 100644 --- a/python/tvm/relay/_parser.py +++ b/python/tvm/relay/_parser.py @@ -567,46 +567,36 @@ def visitMatch(self, ctx: RelayParser.MatchContext): match_clauses = match_clauses.matchClause() parsed_clauses = [] for clause in match_clauses: - constructor_name = clause.constructorName().getText() - constructor = self.global_type_vars[constructor_name] self.enter_var_scope() - patternList = clause.patternList() - if patternList is None: - patterns = [] - else: - patterns = [self.visit(pattern) for pattern in patternList.pattern()] + pattern = self.visit(clause.pattern()) clause_body = self.visit(clause.expr()) self.exit_var_scope() - parsed_clauses.append(adt.Clause( - adt.PatternConstructor( - constructor, - patterns - ), - clause_body - )) + parsed_clauses.append(adt.Clause(pattern, clause_body)) return adt.Match(match_data, parsed_clauses, complete=complete_match) - def visitPattern(self, ctx: RelayParser.PatternContext): - if ctx.getText() == "_": - return adt.PatternWildcard() - elif ctx.localVar() is not None: - text = ctx.localVar().getText() - typ = ctx.typeExpr() - if typ is not None: - typ = self.visit(typ) - var = self.mk_var(text[1:], typ=typ) - return adt.PatternVar(var) - elif ctx.constructorName() is not None: - constructor_name = ctx.constructorName().getText() - constructor = self.global_type_vars[constructor_name] - pattern_list = ctx.patternList() - if pattern_list is None: - patterns = [] - else: - patterns = [self.visit(pattern) for pattern in pattern_list.pattern()] - return adt.PatternConstructor(constructor, patterns) + def visitWildcardPattern(self, ctx: RelayParser.WildcardPatternContext): + return adt.PatternWildcard() + + def visitVarPattern(self, ctx: RelayParser.VarPatternContext): + text = ctx.localVar().getText() + typ = ctx.typeExpr() + if typ is not None: + typ = self.visit(typ) + var = self.mk_var(text[1:], typ=typ) + return adt.PatternVar(var) + + def visitConstructorPattern(self, ctx: RelayParser.ConstructorPatternContext): + constructor_name = ctx.constructorName().getText() + constructor = self.global_type_vars[constructor_name] + pattern_list = ctx.patternList() + if pattern_list is None: + patterns = [] else: - raise ParseError(f"invalid pattern syntax \"{text}\"") + patterns = [self.visit(pattern) for pattern in pattern_list.pattern()] + return adt.PatternConstructor(constructor, patterns) + + def visitTuplePattern(self, ctx: RelayParser.TuplePatternContext): + return adt.PatternTuple([self.visit(pattern) for pattern in ctx.patternList().pattern()]) def visitCallNoAttr(self, ctx: RelayParser.CallNoAttrContext): return (self.visit_list(ctx.exprList().expr()), None) diff --git a/python/tvm/relay/grammar/Relay.g4 b/python/tvm/relay/grammar/Relay.g4 index 46bd80e7ed93..bfcd18ffc98f 100644 --- a/python/tvm/relay/grammar/Relay.g4 +++ b/python/tvm/relay/grammar/Relay.g4 @@ -87,33 +87,33 @@ callList expr // operators - : '(' expr ')' # paren + : '(' expr ')' # paren // function application - | expr '(' callList ')' # call - | '-' expr # neg - | expr op=('*'|'/') expr # binOp - | expr op=('+'|'-') expr # binOp - | expr op=('<'|'>'|'<='|'>=') expr # binOp - | expr op=('=='|'!=') expr # binOp + | expr '(' callList ')' # call + | '-' expr # neg + | expr op=('*'|'/') expr # binOp + | expr op=('+'|'-') expr # binOp + | expr op=('<'|'>'|'<='|'>=') expr # binOp + | expr op=('=='|'!=') expr # binOp // function definition - | func # funcExpr + | func # funcExpr // tuples and tensors - | '(' ')' # tuple - | '(' expr ',' ')' # tuple - | '(' expr (',' expr)+ ')' # tuple - | '[' (expr (',' expr)*)? ']' # tensor - | 'if' '(' expr ')' body 'else' body # ifElse - | matchType '(' expr ')' '{' matchClauseList? '}' # match - | expr '.' NAT # projection + | '(' ')' # tuple + | '(' expr ',' ')' # tuple + | '(' expr (',' expr)+ ')' # tuple + | '[' (expr (',' expr)*)? ']' # tensor + | 'if' '(' expr ')' body 'else' body # ifElse + | matchType expr '{' matchClauseList? '}' # match + | expr '.' NAT # projection // sequencing - | 'let' var '=' expr ';' expr # let + | 'let' var '=' expr ';' expr # let // sugar for let %_ = expr; expr - | expr ';;' expr # let - | graphVar '=' expr ';' expr # graph - | ident # identExpr - | scalar # scalarExpr - | meta # metaExpr - | QUOTED_STRING # stringExpr + | expr ';;' expr # let + | graphVar '=' expr ';' expr # graph + | ident # identExpr + | scalar # scalarExpr + | meta # metaExpr + | QUOTED_STRING # stringExpr ; func: 'fn' typeParamList? '(' argList ')' ('->' typeExpr)? body ; @@ -128,15 +128,16 @@ constructorName: CNAME ; adtConsDefnList: adtConsDefn (',' adtConsDefn)* ','? ; adtConsDefn: constructorName ('(' typeExpr (',' typeExpr)* ')')? ; matchClauseList: matchClause (',' matchClause)* ','? ; -matchClause: constructorName patternList? '=>' ('{' expr '}' | expr) ; +matchClause: pattern '=>' ('{' expr '}' | expr) ; // complete or incomplete match, respectively matchType : 'match' | 'match?' ; patternList: '(' pattern (',' pattern)* ')'; pattern - : '_' - | localVar (':' typeExpr)? - | constructorName patternList? + : '_' # wildcardPattern + | localVar (':' typeExpr)? # varPattern + | constructorName patternList? # constructorPattern + | patternList # tuplePattern ; adtCons: constructorName adtConsParamList? ; diff --git a/python/tvm/relay/grammar/py3/RelayParser.py b/python/tvm/relay/grammar/py3/RelayParser.py index ea3604c2231b..f24eed4be92f 100644 --- a/python/tvm/relay/grammar/py3/RelayParser.py +++ b/python/tvm/relay/grammar/py3/RelayParser.py @@ -9,7 +9,7 @@ def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\62") - buf.write("\u0204\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\u0200\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write("\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r\4\16") buf.write("\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23\t\23") buf.write("\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31") @@ -23,243 +23,241 @@ def serializedATN(): buf.write("\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\6\t\u0090\n\t\r\t\16\t") buf.write("\u0091\3\t\3\t\3\t\3\t\3\t\3\t\7\t\u009a\n\t\f\t\16\t") buf.write("\u009d\13\t\5\t\u009f\n\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t") - buf.write("\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\5\t\u00b0\n\t\3\t\3\t") + buf.write("\3\t\3\t\3\t\3\t\3\t\3\t\5\t\u00ae\n\t\3\t\3\t\3\t\3\t") buf.write("\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3") - buf.write("\t\3\t\3\t\3\t\5\t\u00c5\n\t\3\t\3\t\3\t\3\t\3\t\3\t\3") + buf.write("\t\3\t\5\t\u00c3\n\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3") buf.write("\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t") - buf.write("\3\t\3\t\3\t\7\t\u00de\n\t\f\t\16\t\u00e1\13\t\3\n\3\n") - buf.write("\5\n\u00e5\n\n\3\n\3\n\3\n\3\n\3\n\5\n\u00ec\n\n\3\n\3") - buf.write("\n\3\13\3\13\3\13\5\13\u00f3\n\13\3\13\3\13\3\13\3\13") - buf.write("\3\13\5\13\u00fa\n\13\3\13\3\13\3\13\3\13\3\13\3\13\5") - buf.write("\13\u0102\n\13\3\13\3\13\3\13\5\13\u0107\n\13\3\13\3\13") - buf.write("\5\13\u010b\n\13\3\13\3\13\5\13\u010f\n\13\3\f\3\f\3\r") - buf.write("\3\r\3\r\7\r\u0116\n\r\f\r\16\r\u0119\13\r\3\r\5\r\u011c") - buf.write("\n\r\3\16\3\16\3\16\3\16\3\16\7\16\u0123\n\16\f\16\16") - buf.write("\16\u0126\13\16\3\16\3\16\5\16\u012a\n\16\3\17\3\17\3") - buf.write("\17\7\17\u012f\n\17\f\17\16\17\u0132\13\17\3\17\5\17\u0135") - buf.write("\n\17\3\20\3\20\5\20\u0139\n\20\3\20\3\20\3\20\3\20\3") - buf.write("\20\3\20\5\20\u0141\n\20\3\21\3\21\3\22\3\22\3\22\3\22") - buf.write("\7\22\u0149\n\22\f\22\16\22\u014c\13\22\3\22\3\22\3\23") - buf.write("\3\23\3\23\3\23\5\23\u0154\n\23\3\23\3\23\5\23\u0158\n") - buf.write("\23\5\23\u015a\n\23\3\24\3\24\5\24\u015e\n\24\3\25\3\25") - buf.write("\3\25\3\25\7\25\u0164\n\25\f\25\16\25\u0167\13\25\3\25") - buf.write("\3\25\3\26\3\26\5\26\u016d\n\26\3\27\3\27\3\27\3\27\7") - buf.write("\27\u0173\n\27\f\27\16\27\u0176\13\27\3\27\5\27\u0179") - buf.write("\n\27\3\30\3\30\3\30\7\30\u017e\n\30\f\30\16\30\u0181") - buf.write("\13\30\5\30\u0183\n\30\3\31\3\31\3\31\5\31\u0188\n\31") - buf.write("\3\32\3\32\3\32\7\32\u018d\n\32\f\32\16\32\u0190\13\32") - buf.write("\3\33\3\33\3\33\3\33\3\34\3\34\3\34\3\34\3\34\3\34\3\34") - buf.write("\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\6\34\u01a5\n") - buf.write("\34\r\34\16\34\u01a6\3\34\3\34\3\34\3\34\3\34\3\34\3\34") - buf.write("\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\5\34\u01b8\n") - buf.write("\34\3\34\3\34\3\34\3\34\7\34\u01be\n\34\f\34\16\34\u01c1") - buf.write("\13\34\5\34\u01c3\n\34\3\34\3\34\3\34\3\34\5\34\u01c9") - buf.write("\n\34\3\35\3\35\3\35\3\35\7\35\u01cf\n\35\f\35\16\35\u01d2") - buf.write("\13\35\3\35\3\35\3\36\3\36\3\36\3\36\3\36\3\36\6\36\u01dc") - buf.write("\n\36\r\36\16\36\u01dd\3\36\3\36\3\36\5\36\u01e3\n\36") - buf.write("\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3") - buf.write(" \3 \5 \u01f3\n \3!\3!\3!\3!\3\"\3\"\3\"\5\"\u01fc\n\"") - buf.write("\3#\3#\3#\3#\5#\u0202\n#\3#\2\3\20$\2\4\6\b\n\f\16\20") - buf.write("\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\668:<>@BD\2\b") - buf.write("\4\2\6\6//\3\2$%\3\2&\'\3\2(+\3\2,-\3\2\32\33\2\u0238") - buf.write("\2F\3\2\2\2\4U\3\2\2\2\6]\3\2\2\2\b`\3\2\2\2\nc\3\2\2") - buf.write("\2\fn\3\2\2\2\16z\3\2\2\2\20\u00c4\3\2\2\2\22\u00e2\3") - buf.write("\2\2\2\24\u010e\3\2\2\2\26\u0110\3\2\2\2\30\u0112\3\2") - buf.write("\2\2\32\u011d\3\2\2\2\34\u012b\3\2\2\2\36\u0136\3\2\2") - buf.write("\2 \u0142\3\2\2\2\"\u0144\3\2\2\2$\u0159\3\2\2\2&\u015b") - buf.write("\3\2\2\2(\u015f\3\2\2\2*\u016c\3\2\2\2,\u0178\3\2\2\2") - buf.write(".\u0182\3\2\2\2\60\u0184\3\2\2\2\62\u0189\3\2\2\2\64\u0191") - buf.write("\3\2\2\2\66\u01c8\3\2\2\28\u01ca\3\2\2\2:\u01e2\3\2\2") - buf.write("\2<\u01e4\3\2\2\2>\u01f2\3\2\2\2@\u01f4\3\2\2\2B\u01fb") - buf.write("\3\2\2\2D\u0201\3\2\2\2FN\7\37\2\2GI\5\24\13\2HG\3\2\2") - buf.write("\2IL\3\2\2\2JH\3\2\2\2JK\3\2\2\2KO\3\2\2\2LJ\3\2\2\2M") - buf.write("O\5\20\t\2NJ\3\2\2\2NM\3\2\2\2OQ\3\2\2\2PR\7\62\2\2QP") - buf.write("\3\2\2\2QR\3\2\2\2RS\3\2\2\2ST\7\2\2\3T\3\3\2\2\2UZ\7") - buf.write("/\2\2VW\7\3\2\2WY\7/\2\2XV\3\2\2\2Y\\\3\2\2\2ZX\3\2\2") - buf.write("\2Z[\3\2\2\2[\5\3\2\2\2\\Z\3\2\2\2]^\7\4\2\2^_\7/\2\2") - buf.write("_\7\3\2\2\2`a\7\5\2\2ab\t\2\2\2b\t\3\2\2\2cd\7\5\2\2d") - buf.write("e\7\61\2\2e\13\3\2\2\2fk\5\20\t\2gh\7\7\2\2hj\5\20\t\2") - buf.write("ig\3\2\2\2jm\3\2\2\2ki\3\2\2\2kl\3\2\2\2lo\3\2\2\2mk\3") - buf.write("\2\2\2nf\3\2\2\2no\3\2\2\2o\r\3\2\2\2p{\5\f\7\2qr\5\20") - buf.write("\t\2rs\7\7\2\2su\3\2\2\2tq\3\2\2\2ux\3\2\2\2vt\3\2\2\2") - buf.write("vw\3\2\2\2wy\3\2\2\2xv\3\2\2\2y{\5\62\32\2zp\3\2\2\2z") - buf.write("v\3\2\2\2{\17\3\2\2\2|}\b\t\1\2}~\7\b\2\2~\177\5\20\t") - buf.write("\2\177\u0080\7\t\2\2\u0080\u00c5\3\2\2\2\u0081\u0082\7") - buf.write("\'\2\2\u0082\u00c5\5\20\t\26\u0083\u00c5\5\22\n\2\u0084") - buf.write("\u0085\7\b\2\2\u0085\u00c5\7\t\2\2\u0086\u0087\7\b\2\2") - buf.write("\u0087\u0088\5\20\t\2\u0088\u0089\7\7\2\2\u0089\u008a") - buf.write("\7\t\2\2\u008a\u00c5\3\2\2\2\u008b\u008c\7\b\2\2\u008c") - buf.write("\u008f\5\20\t\2\u008d\u008e\7\7\2\2\u008e\u0090\5\20\t") - buf.write("\2\u008f\u008d\3\2\2\2\u0090\u0091\3\2\2\2\u0091\u008f") - buf.write("\3\2\2\2\u0091\u0092\3\2\2\2\u0092\u0093\3\2\2\2\u0093") - buf.write("\u0094\7\t\2\2\u0094\u00c5\3\2\2\2\u0095\u009e\7\n\2\2") - buf.write("\u0096\u009b\5\20\t\2\u0097\u0098\7\7\2\2\u0098\u009a") - buf.write("\5\20\t\2\u0099\u0097\3\2\2\2\u009a\u009d\3\2\2\2\u009b") - buf.write("\u0099\3\2\2\2\u009b\u009c\3\2\2\2\u009c\u009f\3\2\2\2") - buf.write("\u009d\u009b\3\2\2\2\u009e\u0096\3\2\2\2\u009e\u009f\3") - buf.write("\2\2\2\u009f\u00a0\3\2\2\2\u00a0\u00c5\7\13\2\2\u00a1") - buf.write("\u00a2\7\f\2\2\u00a2\u00a3\7\b\2\2\u00a3\u00a4\5\20\t") - buf.write("\2\u00a4\u00a5\7\t\2\2\u00a5\u00a6\5@!\2\u00a6\u00a7\7") - buf.write("\r\2\2\u00a7\u00a8\5@!\2\u00a8\u00c5\3\2\2\2\u00a9\u00aa") - buf.write("\5 \21\2\u00aa\u00ab\7\b\2\2\u00ab\u00ac\5\20\t\2\u00ac") - buf.write("\u00ad\7\t\2\2\u00ad\u00af\7\16\2\2\u00ae\u00b0\5\34\17") - buf.write("\2\u00af\u00ae\3\2\2\2\u00af\u00b0\3\2\2\2\u00b0\u00b1") - buf.write("\3\2\2\2\u00b1\u00b2\7\17\2\2\u00b2\u00c5\3\2\2\2\u00b3") - buf.write("\u00b4\7\20\2\2\u00b4\u00b5\5\60\31\2\u00b5\u00b6\7\21") - buf.write("\2\2\u00b6\u00b7\5\20\t\2\u00b7\u00b8\7\22\2\2\u00b8\u00b9") - buf.write("\5\20\t\t\u00b9\u00c5\3\2\2\2\u00ba\u00bb\5\n\6\2\u00bb") - buf.write("\u00bc\7\21\2\2\u00bc\u00bd\5\20\t\2\u00bd\u00be\7\22") - buf.write("\2\2\u00be\u00bf\5\20\t\7\u00bf\u00c5\3\2\2\2\u00c0\u00c5") - buf.write("\5D#\2\u00c1\u00c5\5B\"\2\u00c2\u00c5\5<\37\2\u00c3\u00c5") - buf.write("\7#\2\2\u00c4|\3\2\2\2\u00c4\u0081\3\2\2\2\u00c4\u0083") - buf.write("\3\2\2\2\u00c4\u0084\3\2\2\2\u00c4\u0086\3\2\2\2\u00c4") - buf.write("\u008b\3\2\2\2\u00c4\u0095\3\2\2\2\u00c4\u00a1\3\2\2\2") - buf.write("\u00c4\u00a9\3\2\2\2\u00c4\u00b3\3\2\2\2\u00c4\u00ba\3") - buf.write("\2\2\2\u00c4\u00c0\3\2\2\2\u00c4\u00c1\3\2\2\2\u00c4\u00c2") - buf.write("\3\2\2\2\u00c4\u00c3\3\2\2\2\u00c5\u00df\3\2\2\2\u00c6") - buf.write("\u00c7\f\25\2\2\u00c7\u00c8\t\3\2\2\u00c8\u00de\5\20\t") - buf.write("\26\u00c9\u00ca\f\24\2\2\u00ca\u00cb\t\4\2\2\u00cb\u00de") - buf.write("\5\20\t\25\u00cc\u00cd\f\23\2\2\u00cd\u00ce\t\5\2\2\u00ce") - buf.write("\u00de\5\20\t\24\u00cf\u00d0\f\22\2\2\u00d0\u00d1\t\6") - buf.write("\2\2\u00d1\u00de\5\20\t\23\u00d2\u00d3\f\b\2\2\u00d3\u00d4") - buf.write("\7\23\2\2\u00d4\u00de\5\20\t\t\u00d5\u00d6\f\27\2\2\u00d6") - buf.write("\u00d7\7\b\2\2\u00d7\u00d8\5\16\b\2\u00d8\u00d9\7\t\2") - buf.write("\2\u00d9\u00de\3\2\2\2\u00da\u00db\f\n\2\2\u00db\u00dc") - buf.write("\7\3\2\2\u00dc\u00de\7\61\2\2\u00dd\u00c6\3\2\2\2\u00dd") - buf.write("\u00c9\3\2\2\2\u00dd\u00cc\3\2\2\2\u00dd\u00cf\3\2\2\2") - buf.write("\u00dd\u00d2\3\2\2\2\u00dd\u00d5\3\2\2\2\u00dd\u00da\3") - buf.write("\2\2\2\u00de\u00e1\3\2\2\2\u00df\u00dd\3\2\2\2\u00df\u00e0") - buf.write("\3\2\2\2\u00e0\21\3\2\2\2\u00e1\u00df\3\2\2\2\u00e2\u00e4") - buf.write("\7\24\2\2\u00e3\u00e5\58\35\2\u00e4\u00e3\3\2\2\2\u00e4") - buf.write("\u00e5\3\2\2\2\u00e5\u00e6\3\2\2\2\u00e6\u00e7\7\b\2\2") - buf.write("\u00e7\u00e8\5,\27\2\u00e8\u00eb\7\t\2\2\u00e9\u00ea\7") - buf.write("\25\2\2\u00ea\u00ec\5\66\34\2\u00eb\u00e9\3\2\2\2\u00eb") - buf.write("\u00ec\3\2\2\2\u00ec\u00ed\3\2\2\2\u00ed\u00ee\5@!\2\u00ee") - buf.write("\23\3\2\2\2\u00ef\u00f0\7\26\2\2\u00f0\u00f2\5\6\4\2\u00f1") - buf.write("\u00f3\58\35\2\u00f2\u00f1\3\2\2\2\u00f2\u00f3\3\2\2\2") - buf.write("\u00f3\u00f4\3\2\2\2\u00f4\u00f5\7\b\2\2\u00f5\u00f6\5") - buf.write(",\27\2\u00f6\u00f9\7\t\2\2\u00f7\u00f8\7\25\2\2\u00f8") - buf.write("\u00fa\5\66\34\2\u00f9\u00f7\3\2\2\2\u00f9\u00fa\3\2\2") - buf.write("\2\u00fa\u00fb\3\2\2\2\u00fb\u00fc\5@!\2\u00fc\u010f\3") - buf.write("\2\2\2\u00fd\u00fe\7\27\2\2\u00fe\u00ff\7\30\2\2\u00ff") - buf.write("\u0101\5\4\3\2\u0100\u0102\58\35\2\u0101\u0100\3\2\2\2") - buf.write("\u0101\u0102\3\2\2\2\u0102\u010f\3\2\2\2\u0103\u0104\7") - buf.write("\30\2\2\u0104\u0106\5\4\3\2\u0105\u0107\58\35\2\u0106") - buf.write("\u0105\3\2\2\2\u0106\u0107\3\2\2\2\u0107\u0108\3\2\2\2") - buf.write("\u0108\u010a\7\16\2\2\u0109\u010b\5\30\r\2\u010a\u0109") - buf.write("\3\2\2\2\u010a\u010b\3\2\2\2\u010b\u010c\3\2\2\2\u010c") - buf.write("\u010d\7\17\2\2\u010d\u010f\3\2\2\2\u010e\u00ef\3\2\2") - buf.write("\2\u010e\u00fd\3\2\2\2\u010e\u0103\3\2\2\2\u010f\25\3") - buf.write("\2\2\2\u0110\u0111\7/\2\2\u0111\27\3\2\2\2\u0112\u0117") - buf.write("\5\32\16\2\u0113\u0114\7\7\2\2\u0114\u0116\5\32\16\2\u0115") - buf.write("\u0113\3\2\2\2\u0116\u0119\3\2\2\2\u0117\u0115\3\2\2\2") - buf.write("\u0117\u0118\3\2\2\2\u0118\u011b\3\2\2\2\u0119\u0117\3") - buf.write("\2\2\2\u011a\u011c\7\7\2\2\u011b\u011a\3\2\2\2\u011b\u011c") - buf.write("\3\2\2\2\u011c\31\3\2\2\2\u011d\u0129\5\26\f\2\u011e\u011f") - buf.write("\7\b\2\2\u011f\u0124\5\66\34\2\u0120\u0121\7\7\2\2\u0121") - buf.write("\u0123\5\66\34\2\u0122\u0120\3\2\2\2\u0123\u0126\3\2\2") - buf.write("\2\u0124\u0122\3\2\2\2\u0124\u0125\3\2\2\2\u0125\u0127") - buf.write("\3\2\2\2\u0126\u0124\3\2\2\2\u0127\u0128\7\t\2\2\u0128") - buf.write("\u012a\3\2\2\2\u0129\u011e\3\2\2\2\u0129\u012a\3\2\2\2") - buf.write("\u012a\33\3\2\2\2\u012b\u0130\5\36\20\2\u012c\u012d\7") - buf.write("\7\2\2\u012d\u012f\5\36\20\2\u012e\u012c\3\2\2\2\u012f") - buf.write("\u0132\3\2\2\2\u0130\u012e\3\2\2\2\u0130\u0131\3\2\2\2") - buf.write("\u0131\u0134\3\2\2\2\u0132\u0130\3\2\2\2\u0133\u0135\7") - buf.write("\7\2\2\u0134\u0133\3\2\2\2\u0134\u0135\3\2\2\2\u0135\35") - buf.write("\3\2\2\2\u0136\u0138\5\26\f\2\u0137\u0139\5\"\22\2\u0138") - buf.write("\u0137\3\2\2\2\u0138\u0139\3\2\2\2\u0139\u013a\3\2\2\2") - buf.write("\u013a\u0140\7\31\2\2\u013b\u013c\7\16\2\2\u013c\u013d") - buf.write("\5\20\t\2\u013d\u013e\7\17\2\2\u013e\u0141\3\2\2\2\u013f") - buf.write("\u0141\5\20\t\2\u0140\u013b\3\2\2\2\u0140\u013f\3\2\2") - buf.write("\2\u0141\37\3\2\2\2\u0142\u0143\t\7\2\2\u0143!\3\2\2\2") - buf.write("\u0144\u0145\7\b\2\2\u0145\u014a\5$\23\2\u0146\u0147\7") - buf.write("\7\2\2\u0147\u0149\5$\23\2\u0148\u0146\3\2\2\2\u0149\u014c") - buf.write("\3\2\2\2\u014a\u0148\3\2\2\2\u014a\u014b\3\2\2\2\u014b") - buf.write("\u014d\3\2\2\2\u014c\u014a\3\2\2\2\u014d\u014e\7\t\2\2") - buf.write("\u014e#\3\2\2\2\u014f\u015a\7\6\2\2\u0150\u0153\5\b\5") - buf.write("\2\u0151\u0152\7\34\2\2\u0152\u0154\5\66\34\2\u0153\u0151") - buf.write("\3\2\2\2\u0153\u0154\3\2\2\2\u0154\u015a\3\2\2\2\u0155") - buf.write("\u0157\5\26\f\2\u0156\u0158\5\"\22\2\u0157\u0156\3\2\2") - buf.write("\2\u0157\u0158\3\2\2\2\u0158\u015a\3\2\2\2\u0159\u014f") - buf.write("\3\2\2\2\u0159\u0150\3\2\2\2\u0159\u0155\3\2\2\2\u015a") - buf.write("%\3\2\2\2\u015b\u015d\5\26\f\2\u015c\u015e\5(\25\2\u015d") - buf.write("\u015c\3\2\2\2\u015d\u015e\3\2\2\2\u015e\'\3\2\2\2\u015f") - buf.write("\u0160\7\b\2\2\u0160\u0165\5*\26\2\u0161\u0162\7\7\2\2") - buf.write("\u0162\u0164\5*\26\2\u0163\u0161\3\2\2\2\u0164\u0167\3") - buf.write("\2\2\2\u0165\u0163\3\2\2\2\u0165\u0166\3\2\2\2\u0166\u0168") - buf.write("\3\2\2\2\u0167\u0165\3\2\2\2\u0168\u0169\7\t\2\2\u0169") - buf.write(")\3\2\2\2\u016a\u016d\5\b\5\2\u016b\u016d\5\26\f\2\u016c") - buf.write("\u016a\3\2\2\2\u016c\u016b\3\2\2\2\u016d+\3\2\2\2\u016e") - buf.write("\u0179\5.\30\2\u016f\u0170\5\60\31\2\u0170\u0171\7\7\2") - buf.write("\2\u0171\u0173\3\2\2\2\u0172\u016f\3\2\2\2\u0173\u0176") - buf.write("\3\2\2\2\u0174\u0172\3\2\2\2\u0174\u0175\3\2\2\2\u0175") - buf.write("\u0177\3\2\2\2\u0176\u0174\3\2\2\2\u0177\u0179\5\62\32") - buf.write("\2\u0178\u016e\3\2\2\2\u0178\u0174\3\2\2\2\u0179-\3\2") - buf.write("\2\2\u017a\u017f\5\60\31\2\u017b\u017c\7\7\2\2\u017c\u017e") - buf.write("\5\60\31\2\u017d\u017b\3\2\2\2\u017e\u0181\3\2\2\2\u017f") - buf.write("\u017d\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0183\3\2\2\2") - buf.write("\u0181\u017f\3\2\2\2\u0182\u017a\3\2\2\2\u0182\u0183\3") - buf.write("\2\2\2\u0183/\3\2\2\2\u0184\u0187\5\b\5\2\u0185\u0186") - buf.write("\7\34\2\2\u0186\u0188\5\66\34\2\u0187\u0185\3\2\2\2\u0187") - buf.write("\u0188\3\2\2\2\u0188\61\3\2\2\2\u0189\u018e\5\64\33\2") - buf.write("\u018a\u018b\7\7\2\2\u018b\u018d\5\64\33\2\u018c\u018a") - buf.write("\3\2\2\2\u018d\u0190\3\2\2\2\u018e\u018c\3\2\2\2\u018e") - buf.write("\u018f\3\2\2\2\u018f\63\3\2\2\2\u0190\u018e\3\2\2\2\u0191") - buf.write("\u0192\7/\2\2\u0192\u0193\7\21\2\2\u0193\u0194\5\20\t") - buf.write("\2\u0194\65\3\2\2\2\u0195\u0196\7\b\2\2\u0196\u01c9\7") - buf.write("\t\2\2\u0197\u0198\7\b\2\2\u0198\u0199\5\66\34\2\u0199") - buf.write("\u019a\7\t\2\2\u019a\u01c9\3\2\2\2\u019b\u019c\7\b\2\2") - buf.write("\u019c\u019d\5\66\34\2\u019d\u019e\7\7\2\2\u019e\u019f") - buf.write("\7\t\2\2\u019f\u01c9\3\2\2\2\u01a0\u01a1\7\b\2\2\u01a1") - buf.write("\u01a4\5\66\34\2\u01a2\u01a3\7\7\2\2\u01a3\u01a5\5\66") - buf.write("\34\2\u01a4\u01a2\3\2\2\2\u01a5\u01a6\3\2\2\2\u01a6\u01a4") - buf.write("\3\2\2\2\u01a6\u01a7\3\2\2\2\u01a7\u01a8\3\2\2\2\u01a8") - buf.write("\u01a9\7\t\2\2\u01a9\u01c9\3\2\2\2\u01aa\u01ab\5\4\3\2") - buf.write("\u01ab\u01ac\58\35\2\u01ac\u01c9\3\2\2\2\u01ad\u01c9\5") - buf.write("\4\3\2\u01ae\u01af\7\35\2\2\u01af\u01b0\7\n\2\2\u01b0") - buf.write("\u01b1\5:\36\2\u01b1\u01b2\7\7\2\2\u01b2\u01b3\5\66\34") - buf.write("\2\u01b3\u01b4\7\13\2\2\u01b4\u01c9\3\2\2\2\u01b5\u01b7") - buf.write("\7\24\2\2\u01b6\u01b8\58\35\2\u01b7\u01b6\3\2\2\2\u01b7") - buf.write("\u01b8\3\2\2\2\u01b8\u01b9\3\2\2\2\u01b9\u01c2\7\b\2\2") - buf.write("\u01ba\u01bf\5\66\34\2\u01bb\u01bc\7\7\2\2\u01bc\u01be") - buf.write("\5\66\34\2\u01bd\u01bb\3\2\2\2\u01be\u01c1\3\2\2\2\u01bf") - buf.write("\u01bd\3\2\2\2\u01bf\u01c0\3\2\2\2\u01c0\u01c3\3\2\2\2") - buf.write("\u01c1\u01bf\3\2\2\2\u01c2\u01ba\3\2\2\2\u01c2\u01c3\3") - buf.write("\2\2\2\u01c3\u01c4\3\2\2\2\u01c4\u01c5\7\t\2\2\u01c5\u01c6") - buf.write("\7\25\2\2\u01c6\u01c9\5\66\34\2\u01c7\u01c9\7\6\2\2\u01c8") - buf.write("\u0195\3\2\2\2\u01c8\u0197\3\2\2\2\u01c8\u019b\3\2\2\2") - buf.write("\u01c8\u01a0\3\2\2\2\u01c8\u01aa\3\2\2\2\u01c8\u01ad\3") - buf.write("\2\2\2\u01c8\u01ae\3\2\2\2\u01c8\u01b5\3\2\2\2\u01c8\u01c7") - buf.write("\3\2\2\2\u01c9\67\3\2\2\2\u01ca\u01cb\7\n\2\2\u01cb\u01d0") - buf.write("\5\66\34\2\u01cc\u01cd\7\7\2\2\u01cd\u01cf\5\66\34\2\u01ce") - buf.write("\u01cc\3\2\2\2\u01cf\u01d2\3\2\2\2\u01d0\u01ce\3\2\2\2") - buf.write("\u01d0\u01d1\3\2\2\2\u01d1\u01d3\3\2\2\2\u01d2\u01d0\3") - buf.write("\2\2\2\u01d3\u01d4\7\13\2\2\u01d49\3\2\2\2\u01d5\u01d6") - buf.write("\7\b\2\2\u01d6\u01e3\7\t\2\2\u01d7\u01d8\7\b\2\2\u01d8") - buf.write("\u01db\5> \2\u01d9\u01da\7\7\2\2\u01da\u01dc\5> \2\u01db") - buf.write("\u01d9\3\2\2\2\u01dc\u01dd\3\2\2\2\u01dd\u01db\3\2\2\2") - buf.write("\u01dd\u01de\3\2\2\2\u01de\u01df\3\2\2\2\u01df\u01e0\7") - buf.write("\t\2\2\u01e0\u01e3\3\2\2\2\u01e1\u01e3\5> \2\u01e2\u01d5") - buf.write("\3\2\2\2\u01e2\u01d7\3\2\2\2\u01e2\u01e1\3\2\2\2\u01e3") - buf.write(";\3\2\2\2\u01e4\u01e5\7\36\2\2\u01e5\u01e6\7\n\2\2\u01e6") - buf.write("\u01e7\7/\2\2\u01e7\u01e8\7\13\2\2\u01e8\u01e9\7\n\2\2") - buf.write("\u01e9\u01ea\7\61\2\2\u01ea\u01eb\7\13\2\2\u01eb=\3\2") - buf.write("\2\2\u01ec\u01f3\5<\37\2\u01ed\u01ee\7\b\2\2\u01ee\u01ef") - buf.write("\5> \2\u01ef\u01f0\7\t\2\2\u01f0\u01f3\3\2\2\2\u01f1\u01f3") - buf.write("\7\61\2\2\u01f2\u01ec\3\2\2\2\u01f2\u01ed\3\2\2\2\u01f2") - buf.write("\u01f1\3\2\2\2\u01f3?\3\2\2\2\u01f4\u01f5\7\16\2\2\u01f5") - buf.write("\u01f6\5\20\t\2\u01f6\u01f7\7\17\2\2\u01f7A\3\2\2\2\u01f8") - buf.write("\u01fc\7\60\2\2\u01f9\u01fc\7\61\2\2\u01fa\u01fc\7.\2") - buf.write("\2\u01fb\u01f8\3\2\2\2\u01fb\u01f9\3\2\2\2\u01fb\u01fa") - buf.write("\3\2\2\2\u01fcC\3\2\2\2\u01fd\u0202\5\4\3\2\u01fe\u0202") - buf.write("\5\6\4\2\u01ff\u0202\5\b\5\2\u0200\u0202\5\n\6\2\u0201") - buf.write("\u01fd\3\2\2\2\u0201\u01fe\3\2\2\2\u0201\u01ff\3\2\2\2") - buf.write("\u0201\u0200\3\2\2\2\u0202E\3\2\2\29JNQZknvz\u0091\u009b") - buf.write("\u009e\u00af\u00c4\u00dd\u00df\u00e4\u00eb\u00f2\u00f9") - buf.write("\u0101\u0106\u010a\u010e\u0117\u011b\u0124\u0129\u0130") - buf.write("\u0134\u0138\u0140\u014a\u0153\u0157\u0159\u015d\u0165") - buf.write("\u016c\u0174\u0178\u017f\u0182\u0187\u018e\u01a6\u01b7") - buf.write("\u01bf\u01c2\u01c8\u01d0\u01dd\u01e2\u01f2\u01fb\u0201") + buf.write("\3\t\7\t\u00dc\n\t\f\t\16\t\u00df\13\t\3\n\3\n\5\n\u00e3") + buf.write("\n\n\3\n\3\n\3\n\3\n\3\n\5\n\u00ea\n\n\3\n\3\n\3\13\3") + buf.write("\13\3\13\5\13\u00f1\n\13\3\13\3\13\3\13\3\13\3\13\5\13") + buf.write("\u00f8\n\13\3\13\3\13\3\13\3\13\3\13\3\13\5\13\u0100\n") + buf.write("\13\3\13\3\13\3\13\5\13\u0105\n\13\3\13\3\13\5\13\u0109") + buf.write("\n\13\3\13\3\13\5\13\u010d\n\13\3\f\3\f\3\r\3\r\3\r\7") + buf.write("\r\u0114\n\r\f\r\16\r\u0117\13\r\3\r\5\r\u011a\n\r\3\16") + buf.write("\3\16\3\16\3\16\3\16\7\16\u0121\n\16\f\16\16\16\u0124") + buf.write("\13\16\3\16\3\16\5\16\u0128\n\16\3\17\3\17\3\17\7\17\u012d") + buf.write("\n\17\f\17\16\17\u0130\13\17\3\17\5\17\u0133\n\17\3\20") + buf.write("\3\20\3\20\3\20\3\20\3\20\3\20\5\20\u013c\n\20\3\21\3") + buf.write("\21\3\22\3\22\3\22\3\22\7\22\u0144\n\22\f\22\16\22\u0147") + buf.write("\13\22\3\22\3\22\3\23\3\23\3\23\3\23\5\23\u014f\n\23\3") + buf.write("\23\3\23\5\23\u0153\n\23\3\23\5\23\u0156\n\23\3\24\3\24") + buf.write("\5\24\u015a\n\24\3\25\3\25\3\25\3\25\7\25\u0160\n\25\f") + buf.write("\25\16\25\u0163\13\25\3\25\3\25\3\26\3\26\5\26\u0169\n") + buf.write("\26\3\27\3\27\3\27\3\27\7\27\u016f\n\27\f\27\16\27\u0172") + buf.write("\13\27\3\27\5\27\u0175\n\27\3\30\3\30\3\30\7\30\u017a") + buf.write("\n\30\f\30\16\30\u017d\13\30\5\30\u017f\n\30\3\31\3\31") + buf.write("\3\31\5\31\u0184\n\31\3\32\3\32\3\32\7\32\u0189\n\32\f") + buf.write("\32\16\32\u018c\13\32\3\33\3\33\3\33\3\33\3\34\3\34\3") + buf.write("\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34") + buf.write("\3\34\3\34\6\34\u01a1\n\34\r\34\16\34\u01a2\3\34\3\34") + buf.write("\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34") + buf.write("\3\34\3\34\5\34\u01b4\n\34\3\34\3\34\3\34\3\34\7\34\u01ba") + buf.write("\n\34\f\34\16\34\u01bd\13\34\5\34\u01bf\n\34\3\34\3\34") + buf.write("\3\34\3\34\5\34\u01c5\n\34\3\35\3\35\3\35\3\35\7\35\u01cb") + buf.write("\n\35\f\35\16\35\u01ce\13\35\3\35\3\35\3\36\3\36\3\36") + buf.write("\3\36\3\36\3\36\6\36\u01d8\n\36\r\36\16\36\u01d9\3\36") + buf.write("\3\36\3\36\5\36\u01df\n\36\3\37\3\37\3\37\3\37\3\37\3") + buf.write("\37\3\37\3\37\3 \3 \3 \3 \3 \3 \5 \u01ef\n \3!\3!\3!\3") + buf.write("!\3\"\3\"\3\"\5\"\u01f8\n\"\3#\3#\3#\3#\5#\u01fe\n#\3") + buf.write("#\2\3\20$\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&") + buf.write("(*,.\60\62\64\668:<>@BD\2\b\4\2\6\6//\3\2$%\3\2&\'\3\2") + buf.write("(+\3\2,-\3\2\32\33\2\u0234\2F\3\2\2\2\4U\3\2\2\2\6]\3") + buf.write("\2\2\2\b`\3\2\2\2\nc\3\2\2\2\fn\3\2\2\2\16z\3\2\2\2\20") + buf.write("\u00c2\3\2\2\2\22\u00e0\3\2\2\2\24\u010c\3\2\2\2\26\u010e") + buf.write("\3\2\2\2\30\u0110\3\2\2\2\32\u011b\3\2\2\2\34\u0129\3") + buf.write("\2\2\2\36\u0134\3\2\2\2 \u013d\3\2\2\2\"\u013f\3\2\2\2") + buf.write("$\u0155\3\2\2\2&\u0157\3\2\2\2(\u015b\3\2\2\2*\u0168\3") + buf.write("\2\2\2,\u0174\3\2\2\2.\u017e\3\2\2\2\60\u0180\3\2\2\2") + buf.write("\62\u0185\3\2\2\2\64\u018d\3\2\2\2\66\u01c4\3\2\2\28\u01c6") + buf.write("\3\2\2\2:\u01de\3\2\2\2<\u01e0\3\2\2\2>\u01ee\3\2\2\2") + buf.write("@\u01f0\3\2\2\2B\u01f7\3\2\2\2D\u01fd\3\2\2\2FN\7\37\2") + buf.write("\2GI\5\24\13\2HG\3\2\2\2IL\3\2\2\2JH\3\2\2\2JK\3\2\2\2") + buf.write("KO\3\2\2\2LJ\3\2\2\2MO\5\20\t\2NJ\3\2\2\2NM\3\2\2\2OQ") + buf.write("\3\2\2\2PR\7\62\2\2QP\3\2\2\2QR\3\2\2\2RS\3\2\2\2ST\7") + buf.write("\2\2\3T\3\3\2\2\2UZ\7/\2\2VW\7\3\2\2WY\7/\2\2XV\3\2\2") + buf.write("\2Y\\\3\2\2\2ZX\3\2\2\2Z[\3\2\2\2[\5\3\2\2\2\\Z\3\2\2") + buf.write("\2]^\7\4\2\2^_\7/\2\2_\7\3\2\2\2`a\7\5\2\2ab\t\2\2\2b") + buf.write("\t\3\2\2\2cd\7\5\2\2de\7\61\2\2e\13\3\2\2\2fk\5\20\t\2") + buf.write("gh\7\7\2\2hj\5\20\t\2ig\3\2\2\2jm\3\2\2\2ki\3\2\2\2kl") + buf.write("\3\2\2\2lo\3\2\2\2mk\3\2\2\2nf\3\2\2\2no\3\2\2\2o\r\3") + buf.write("\2\2\2p{\5\f\7\2qr\5\20\t\2rs\7\7\2\2su\3\2\2\2tq\3\2") + buf.write("\2\2ux\3\2\2\2vt\3\2\2\2vw\3\2\2\2wy\3\2\2\2xv\3\2\2\2") + buf.write("y{\5\62\32\2zp\3\2\2\2zv\3\2\2\2{\17\3\2\2\2|}\b\t\1\2") + buf.write("}~\7\b\2\2~\177\5\20\t\2\177\u0080\7\t\2\2\u0080\u00c3") + buf.write("\3\2\2\2\u0081\u0082\7\'\2\2\u0082\u00c3\5\20\t\26\u0083") + buf.write("\u00c3\5\22\n\2\u0084\u0085\7\b\2\2\u0085\u00c3\7\t\2") + buf.write("\2\u0086\u0087\7\b\2\2\u0087\u0088\5\20\t\2\u0088\u0089") + buf.write("\7\7\2\2\u0089\u008a\7\t\2\2\u008a\u00c3\3\2\2\2\u008b") + buf.write("\u008c\7\b\2\2\u008c\u008f\5\20\t\2\u008d\u008e\7\7\2") + buf.write("\2\u008e\u0090\5\20\t\2\u008f\u008d\3\2\2\2\u0090\u0091") + buf.write("\3\2\2\2\u0091\u008f\3\2\2\2\u0091\u0092\3\2\2\2\u0092") + buf.write("\u0093\3\2\2\2\u0093\u0094\7\t\2\2\u0094\u00c3\3\2\2\2") + buf.write("\u0095\u009e\7\n\2\2\u0096\u009b\5\20\t\2\u0097\u0098") + buf.write("\7\7\2\2\u0098\u009a\5\20\t\2\u0099\u0097\3\2\2\2\u009a") + buf.write("\u009d\3\2\2\2\u009b\u0099\3\2\2\2\u009b\u009c\3\2\2\2") + buf.write("\u009c\u009f\3\2\2\2\u009d\u009b\3\2\2\2\u009e\u0096\3") + buf.write("\2\2\2\u009e\u009f\3\2\2\2\u009f\u00a0\3\2\2\2\u00a0\u00c3") + buf.write("\7\13\2\2\u00a1\u00a2\7\f\2\2\u00a2\u00a3\7\b\2\2\u00a3") + buf.write("\u00a4\5\20\t\2\u00a4\u00a5\7\t\2\2\u00a5\u00a6\5@!\2") + buf.write("\u00a6\u00a7\7\r\2\2\u00a7\u00a8\5@!\2\u00a8\u00c3\3\2") + buf.write("\2\2\u00a9\u00aa\5 \21\2\u00aa\u00ab\5\20\t\2\u00ab\u00ad") + buf.write("\7\16\2\2\u00ac\u00ae\5\34\17\2\u00ad\u00ac\3\2\2\2\u00ad") + buf.write("\u00ae\3\2\2\2\u00ae\u00af\3\2\2\2\u00af\u00b0\7\17\2") + buf.write("\2\u00b0\u00c3\3\2\2\2\u00b1\u00b2\7\20\2\2\u00b2\u00b3") + buf.write("\5\60\31\2\u00b3\u00b4\7\21\2\2\u00b4\u00b5\5\20\t\2\u00b5") + buf.write("\u00b6\7\22\2\2\u00b6\u00b7\5\20\t\t\u00b7\u00c3\3\2\2") + buf.write("\2\u00b8\u00b9\5\n\6\2\u00b9\u00ba\7\21\2\2\u00ba\u00bb") + buf.write("\5\20\t\2\u00bb\u00bc\7\22\2\2\u00bc\u00bd\5\20\t\7\u00bd") + buf.write("\u00c3\3\2\2\2\u00be\u00c3\5D#\2\u00bf\u00c3\5B\"\2\u00c0") + buf.write("\u00c3\5<\37\2\u00c1\u00c3\7#\2\2\u00c2|\3\2\2\2\u00c2") + buf.write("\u0081\3\2\2\2\u00c2\u0083\3\2\2\2\u00c2\u0084\3\2\2\2") + buf.write("\u00c2\u0086\3\2\2\2\u00c2\u008b\3\2\2\2\u00c2\u0095\3") + buf.write("\2\2\2\u00c2\u00a1\3\2\2\2\u00c2\u00a9\3\2\2\2\u00c2\u00b1") + buf.write("\3\2\2\2\u00c2\u00b8\3\2\2\2\u00c2\u00be\3\2\2\2\u00c2") + buf.write("\u00bf\3\2\2\2\u00c2\u00c0\3\2\2\2\u00c2\u00c1\3\2\2\2") + buf.write("\u00c3\u00dd\3\2\2\2\u00c4\u00c5\f\25\2\2\u00c5\u00c6") + buf.write("\t\3\2\2\u00c6\u00dc\5\20\t\26\u00c7\u00c8\f\24\2\2\u00c8") + buf.write("\u00c9\t\4\2\2\u00c9\u00dc\5\20\t\25\u00ca\u00cb\f\23") + buf.write("\2\2\u00cb\u00cc\t\5\2\2\u00cc\u00dc\5\20\t\24\u00cd\u00ce") + buf.write("\f\22\2\2\u00ce\u00cf\t\6\2\2\u00cf\u00dc\5\20\t\23\u00d0") + buf.write("\u00d1\f\b\2\2\u00d1\u00d2\7\23\2\2\u00d2\u00dc\5\20\t") + buf.write("\t\u00d3\u00d4\f\27\2\2\u00d4\u00d5\7\b\2\2\u00d5\u00d6") + buf.write("\5\16\b\2\u00d6\u00d7\7\t\2\2\u00d7\u00dc\3\2\2\2\u00d8") + buf.write("\u00d9\f\n\2\2\u00d9\u00da\7\3\2\2\u00da\u00dc\7\61\2") + buf.write("\2\u00db\u00c4\3\2\2\2\u00db\u00c7\3\2\2\2\u00db\u00ca") + buf.write("\3\2\2\2\u00db\u00cd\3\2\2\2\u00db\u00d0\3\2\2\2\u00db") + buf.write("\u00d3\3\2\2\2\u00db\u00d8\3\2\2\2\u00dc\u00df\3\2\2\2") + buf.write("\u00dd\u00db\3\2\2\2\u00dd\u00de\3\2\2\2\u00de\21\3\2") + buf.write("\2\2\u00df\u00dd\3\2\2\2\u00e0\u00e2\7\24\2\2\u00e1\u00e3") + buf.write("\58\35\2\u00e2\u00e1\3\2\2\2\u00e2\u00e3\3\2\2\2\u00e3") + buf.write("\u00e4\3\2\2\2\u00e4\u00e5\7\b\2\2\u00e5\u00e6\5,\27\2") + buf.write("\u00e6\u00e9\7\t\2\2\u00e7\u00e8\7\25\2\2\u00e8\u00ea") + buf.write("\5\66\34\2\u00e9\u00e7\3\2\2\2\u00e9\u00ea\3\2\2\2\u00ea") + buf.write("\u00eb\3\2\2\2\u00eb\u00ec\5@!\2\u00ec\23\3\2\2\2\u00ed") + buf.write("\u00ee\7\26\2\2\u00ee\u00f0\5\6\4\2\u00ef\u00f1\58\35") + buf.write("\2\u00f0\u00ef\3\2\2\2\u00f0\u00f1\3\2\2\2\u00f1\u00f2") + buf.write("\3\2\2\2\u00f2\u00f3\7\b\2\2\u00f3\u00f4\5,\27\2\u00f4") + buf.write("\u00f7\7\t\2\2\u00f5\u00f6\7\25\2\2\u00f6\u00f8\5\66\34") + buf.write("\2\u00f7\u00f5\3\2\2\2\u00f7\u00f8\3\2\2\2\u00f8\u00f9") + buf.write("\3\2\2\2\u00f9\u00fa\5@!\2\u00fa\u010d\3\2\2\2\u00fb\u00fc") + buf.write("\7\27\2\2\u00fc\u00fd\7\30\2\2\u00fd\u00ff\5\4\3\2\u00fe") + buf.write("\u0100\58\35\2\u00ff\u00fe\3\2\2\2\u00ff\u0100\3\2\2\2") + buf.write("\u0100\u010d\3\2\2\2\u0101\u0102\7\30\2\2\u0102\u0104") + buf.write("\5\4\3\2\u0103\u0105\58\35\2\u0104\u0103\3\2\2\2\u0104") + buf.write("\u0105\3\2\2\2\u0105\u0106\3\2\2\2\u0106\u0108\7\16\2") + buf.write("\2\u0107\u0109\5\30\r\2\u0108\u0107\3\2\2\2\u0108\u0109") + buf.write("\3\2\2\2\u0109\u010a\3\2\2\2\u010a\u010b\7\17\2\2\u010b") + buf.write("\u010d\3\2\2\2\u010c\u00ed\3\2\2\2\u010c\u00fb\3\2\2\2") + buf.write("\u010c\u0101\3\2\2\2\u010d\25\3\2\2\2\u010e\u010f\7/\2") + buf.write("\2\u010f\27\3\2\2\2\u0110\u0115\5\32\16\2\u0111\u0112") + buf.write("\7\7\2\2\u0112\u0114\5\32\16\2\u0113\u0111\3\2\2\2\u0114") + buf.write("\u0117\3\2\2\2\u0115\u0113\3\2\2\2\u0115\u0116\3\2\2\2") + buf.write("\u0116\u0119\3\2\2\2\u0117\u0115\3\2\2\2\u0118\u011a\7") + buf.write("\7\2\2\u0119\u0118\3\2\2\2\u0119\u011a\3\2\2\2\u011a\31") + buf.write("\3\2\2\2\u011b\u0127\5\26\f\2\u011c\u011d\7\b\2\2\u011d") + buf.write("\u0122\5\66\34\2\u011e\u011f\7\7\2\2\u011f\u0121\5\66") + buf.write("\34\2\u0120\u011e\3\2\2\2\u0121\u0124\3\2\2\2\u0122\u0120") + buf.write("\3\2\2\2\u0122\u0123\3\2\2\2\u0123\u0125\3\2\2\2\u0124") + buf.write("\u0122\3\2\2\2\u0125\u0126\7\t\2\2\u0126\u0128\3\2\2\2") + buf.write("\u0127\u011c\3\2\2\2\u0127\u0128\3\2\2\2\u0128\33\3\2") + buf.write("\2\2\u0129\u012e\5\36\20\2\u012a\u012b\7\7\2\2\u012b\u012d") + buf.write("\5\36\20\2\u012c\u012a\3\2\2\2\u012d\u0130\3\2\2\2\u012e") + buf.write("\u012c\3\2\2\2\u012e\u012f\3\2\2\2\u012f\u0132\3\2\2\2") + buf.write("\u0130\u012e\3\2\2\2\u0131\u0133\7\7\2\2\u0132\u0131\3") + buf.write("\2\2\2\u0132\u0133\3\2\2\2\u0133\35\3\2\2\2\u0134\u0135") + buf.write("\5$\23\2\u0135\u013b\7\31\2\2\u0136\u0137\7\16\2\2\u0137") + buf.write("\u0138\5\20\t\2\u0138\u0139\7\17\2\2\u0139\u013c\3\2\2") + buf.write("\2\u013a\u013c\5\20\t\2\u013b\u0136\3\2\2\2\u013b\u013a") + buf.write("\3\2\2\2\u013c\37\3\2\2\2\u013d\u013e\t\7\2\2\u013e!\3") + buf.write("\2\2\2\u013f\u0140\7\b\2\2\u0140\u0145\5$\23\2\u0141\u0142") + buf.write("\7\7\2\2\u0142\u0144\5$\23\2\u0143\u0141\3\2\2\2\u0144") + buf.write("\u0147\3\2\2\2\u0145\u0143\3\2\2\2\u0145\u0146\3\2\2\2") + buf.write("\u0146\u0148\3\2\2\2\u0147\u0145\3\2\2\2\u0148\u0149\7") + buf.write("\t\2\2\u0149#\3\2\2\2\u014a\u0156\7\6\2\2\u014b\u014e") + buf.write("\5\b\5\2\u014c\u014d\7\34\2\2\u014d\u014f\5\66\34\2\u014e") + buf.write("\u014c\3\2\2\2\u014e\u014f\3\2\2\2\u014f\u0156\3\2\2\2") + buf.write("\u0150\u0152\5\26\f\2\u0151\u0153\5\"\22\2\u0152\u0151") + buf.write("\3\2\2\2\u0152\u0153\3\2\2\2\u0153\u0156\3\2\2\2\u0154") + buf.write("\u0156\5\"\22\2\u0155\u014a\3\2\2\2\u0155\u014b\3\2\2") + buf.write("\2\u0155\u0150\3\2\2\2\u0155\u0154\3\2\2\2\u0156%\3\2") + buf.write("\2\2\u0157\u0159\5\26\f\2\u0158\u015a\5(\25\2\u0159\u0158") + buf.write("\3\2\2\2\u0159\u015a\3\2\2\2\u015a\'\3\2\2\2\u015b\u015c") + buf.write("\7\b\2\2\u015c\u0161\5*\26\2\u015d\u015e\7\7\2\2\u015e") + buf.write("\u0160\5*\26\2\u015f\u015d\3\2\2\2\u0160\u0163\3\2\2\2") + buf.write("\u0161\u015f\3\2\2\2\u0161\u0162\3\2\2\2\u0162\u0164\3") + buf.write("\2\2\2\u0163\u0161\3\2\2\2\u0164\u0165\7\t\2\2\u0165)") + buf.write("\3\2\2\2\u0166\u0169\5\b\5\2\u0167\u0169\5\26\f\2\u0168") + buf.write("\u0166\3\2\2\2\u0168\u0167\3\2\2\2\u0169+\3\2\2\2\u016a") + buf.write("\u0175\5.\30\2\u016b\u016c\5\60\31\2\u016c\u016d\7\7\2") + buf.write("\2\u016d\u016f\3\2\2\2\u016e\u016b\3\2\2\2\u016f\u0172") + buf.write("\3\2\2\2\u0170\u016e\3\2\2\2\u0170\u0171\3\2\2\2\u0171") + buf.write("\u0173\3\2\2\2\u0172\u0170\3\2\2\2\u0173\u0175\5\62\32") + buf.write("\2\u0174\u016a\3\2\2\2\u0174\u0170\3\2\2\2\u0175-\3\2") + buf.write("\2\2\u0176\u017b\5\60\31\2\u0177\u0178\7\7\2\2\u0178\u017a") + buf.write("\5\60\31\2\u0179\u0177\3\2\2\2\u017a\u017d\3\2\2\2\u017b") + buf.write("\u0179\3\2\2\2\u017b\u017c\3\2\2\2\u017c\u017f\3\2\2\2") + buf.write("\u017d\u017b\3\2\2\2\u017e\u0176\3\2\2\2\u017e\u017f\3") + buf.write("\2\2\2\u017f/\3\2\2\2\u0180\u0183\5\b\5\2\u0181\u0182") + buf.write("\7\34\2\2\u0182\u0184\5\66\34\2\u0183\u0181\3\2\2\2\u0183") + buf.write("\u0184\3\2\2\2\u0184\61\3\2\2\2\u0185\u018a\5\64\33\2") + buf.write("\u0186\u0187\7\7\2\2\u0187\u0189\5\64\33\2\u0188\u0186") + buf.write("\3\2\2\2\u0189\u018c\3\2\2\2\u018a\u0188\3\2\2\2\u018a") + buf.write("\u018b\3\2\2\2\u018b\63\3\2\2\2\u018c\u018a\3\2\2\2\u018d") + buf.write("\u018e\7/\2\2\u018e\u018f\7\21\2\2\u018f\u0190\5\20\t") + buf.write("\2\u0190\65\3\2\2\2\u0191\u0192\7\b\2\2\u0192\u01c5\7") + buf.write("\t\2\2\u0193\u0194\7\b\2\2\u0194\u0195\5\66\34\2\u0195") + buf.write("\u0196\7\t\2\2\u0196\u01c5\3\2\2\2\u0197\u0198\7\b\2\2") + buf.write("\u0198\u0199\5\66\34\2\u0199\u019a\7\7\2\2\u019a\u019b") + buf.write("\7\t\2\2\u019b\u01c5\3\2\2\2\u019c\u019d\7\b\2\2\u019d") + buf.write("\u01a0\5\66\34\2\u019e\u019f\7\7\2\2\u019f\u01a1\5\66") + buf.write("\34\2\u01a0\u019e\3\2\2\2\u01a1\u01a2\3\2\2\2\u01a2\u01a0") + buf.write("\3\2\2\2\u01a2\u01a3\3\2\2\2\u01a3\u01a4\3\2\2\2\u01a4") + buf.write("\u01a5\7\t\2\2\u01a5\u01c5\3\2\2\2\u01a6\u01a7\5\4\3\2") + buf.write("\u01a7\u01a8\58\35\2\u01a8\u01c5\3\2\2\2\u01a9\u01c5\5") + buf.write("\4\3\2\u01aa\u01ab\7\35\2\2\u01ab\u01ac\7\n\2\2\u01ac") + buf.write("\u01ad\5:\36\2\u01ad\u01ae\7\7\2\2\u01ae\u01af\5\66\34") + buf.write("\2\u01af\u01b0\7\13\2\2\u01b0\u01c5\3\2\2\2\u01b1\u01b3") + buf.write("\7\24\2\2\u01b2\u01b4\58\35\2\u01b3\u01b2\3\2\2\2\u01b3") + buf.write("\u01b4\3\2\2\2\u01b4\u01b5\3\2\2\2\u01b5\u01be\7\b\2\2") + buf.write("\u01b6\u01bb\5\66\34\2\u01b7\u01b8\7\7\2\2\u01b8\u01ba") + buf.write("\5\66\34\2\u01b9\u01b7\3\2\2\2\u01ba\u01bd\3\2\2\2\u01bb") + buf.write("\u01b9\3\2\2\2\u01bb\u01bc\3\2\2\2\u01bc\u01bf\3\2\2\2") + buf.write("\u01bd\u01bb\3\2\2\2\u01be\u01b6\3\2\2\2\u01be\u01bf\3") + buf.write("\2\2\2\u01bf\u01c0\3\2\2\2\u01c0\u01c1\7\t\2\2\u01c1\u01c2") + buf.write("\7\25\2\2\u01c2\u01c5\5\66\34\2\u01c3\u01c5\7\6\2\2\u01c4") + buf.write("\u0191\3\2\2\2\u01c4\u0193\3\2\2\2\u01c4\u0197\3\2\2\2") + buf.write("\u01c4\u019c\3\2\2\2\u01c4\u01a6\3\2\2\2\u01c4\u01a9\3") + buf.write("\2\2\2\u01c4\u01aa\3\2\2\2\u01c4\u01b1\3\2\2\2\u01c4\u01c3") + buf.write("\3\2\2\2\u01c5\67\3\2\2\2\u01c6\u01c7\7\n\2\2\u01c7\u01cc") + buf.write("\5\66\34\2\u01c8\u01c9\7\7\2\2\u01c9\u01cb\5\66\34\2\u01ca") + buf.write("\u01c8\3\2\2\2\u01cb\u01ce\3\2\2\2\u01cc\u01ca\3\2\2\2") + buf.write("\u01cc\u01cd\3\2\2\2\u01cd\u01cf\3\2\2\2\u01ce\u01cc\3") + buf.write("\2\2\2\u01cf\u01d0\7\13\2\2\u01d09\3\2\2\2\u01d1\u01d2") + buf.write("\7\b\2\2\u01d2\u01df\7\t\2\2\u01d3\u01d4\7\b\2\2\u01d4") + buf.write("\u01d7\5> \2\u01d5\u01d6\7\7\2\2\u01d6\u01d8\5> \2\u01d7") + buf.write("\u01d5\3\2\2\2\u01d8\u01d9\3\2\2\2\u01d9\u01d7\3\2\2\2") + buf.write("\u01d9\u01da\3\2\2\2\u01da\u01db\3\2\2\2\u01db\u01dc\7") + buf.write("\t\2\2\u01dc\u01df\3\2\2\2\u01dd\u01df\5> \2\u01de\u01d1") + buf.write("\3\2\2\2\u01de\u01d3\3\2\2\2\u01de\u01dd\3\2\2\2\u01df") + buf.write(";\3\2\2\2\u01e0\u01e1\7\36\2\2\u01e1\u01e2\7\n\2\2\u01e2") + buf.write("\u01e3\7/\2\2\u01e3\u01e4\7\13\2\2\u01e4\u01e5\7\n\2\2") + buf.write("\u01e5\u01e6\7\61\2\2\u01e6\u01e7\7\13\2\2\u01e7=\3\2") + buf.write("\2\2\u01e8\u01ef\5<\37\2\u01e9\u01ea\7\b\2\2\u01ea\u01eb") + buf.write("\5> \2\u01eb\u01ec\7\t\2\2\u01ec\u01ef\3\2\2\2\u01ed\u01ef") + buf.write("\7\61\2\2\u01ee\u01e8\3\2\2\2\u01ee\u01e9\3\2\2\2\u01ee") + buf.write("\u01ed\3\2\2\2\u01ef?\3\2\2\2\u01f0\u01f1\7\16\2\2\u01f1") + buf.write("\u01f2\5\20\t\2\u01f2\u01f3\7\17\2\2\u01f3A\3\2\2\2\u01f4") + buf.write("\u01f8\7\60\2\2\u01f5\u01f8\7\61\2\2\u01f6\u01f8\7.\2") + buf.write("\2\u01f7\u01f4\3\2\2\2\u01f7\u01f5\3\2\2\2\u01f7\u01f6") + buf.write("\3\2\2\2\u01f8C\3\2\2\2\u01f9\u01fe\5\4\3\2\u01fa\u01fe") + buf.write("\5\6\4\2\u01fb\u01fe\5\b\5\2\u01fc\u01fe\5\n\6\2\u01fd") + buf.write("\u01f9\3\2\2\2\u01fd\u01fa\3\2\2\2\u01fd\u01fb\3\2\2\2") + buf.write("\u01fd\u01fc\3\2\2\2\u01feE\3\2\2\28JNQZknvz\u0091\u009b") + buf.write("\u009e\u00ad\u00c2\u00db\u00dd\u00e2\u00e9\u00f0\u00f7") + buf.write("\u00ff\u0104\u0108\u010c\u0115\u0119\u0122\u0127\u012e") + buf.write("\u0132\u013b\u0145\u014e\u0152\u0155\u0159\u0161\u0168") + buf.write("\u0170\u0174\u017b\u017e\u0183\u018a\u01a2\u01b3\u01bb") + buf.write("\u01be\u01c4\u01cc\u01d9\u01de\u01ee\u01f7\u01fd") return buf.getvalue() @@ -1185,7 +1183,7 @@ def expr(self, _p:int=0): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 194 + self.state = 192 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,12,self._ctx) if la_ == 1: @@ -1326,22 +1324,18 @@ def expr(self, _p:int=0): self.state = 167 self.matchType() self.state = 168 - self.match(RelayParser.T__5) - self.state = 169 self.expr(0) - self.state = 170 - self.match(RelayParser.T__6) - self.state = 171 + self.state = 169 self.match(RelayParser.T__11) - self.state = 173 + self.state = 171 self._errHandler.sync(self) _la = self._input.LA(1) - if _la==RelayParser.CNAME: - self.state = 172 + if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << RelayParser.T__2) | (1 << RelayParser.T__3) | (1 << RelayParser.T__5) | (1 << RelayParser.CNAME))) != 0): + self.state = 170 self.matchClauseList() - self.state = 175 + self.state = 173 self.match(RelayParser.T__12) pass @@ -1349,17 +1343,17 @@ def expr(self, _p:int=0): localctx = RelayParser.LetContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 177 + self.state = 175 self.match(RelayParser.T__13) - self.state = 178 + self.state = 176 self.var() - self.state = 179 + self.state = 177 self.match(RelayParser.T__14) - self.state = 180 + self.state = 178 self.expr(0) - self.state = 181 + self.state = 179 self.match(RelayParser.T__15) - self.state = 182 + self.state = 180 self.expr(7) pass @@ -1367,15 +1361,15 @@ def expr(self, _p:int=0): localctx = RelayParser.GraphContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 184 + self.state = 182 self.graphVar() - self.state = 185 + self.state = 183 self.match(RelayParser.T__14) - self.state = 186 + self.state = 184 self.expr(0) - self.state = 187 + self.state = 185 self.match(RelayParser.T__15) - self.state = 188 + self.state = 186 self.expr(5) pass @@ -1383,7 +1377,7 @@ def expr(self, _p:int=0): localctx = RelayParser.IdentExprContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 190 + self.state = 188 self.ident() pass @@ -1391,7 +1385,7 @@ def expr(self, _p:int=0): localctx = RelayParser.ScalarExprContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 191 + self.state = 189 self.scalar() pass @@ -1399,7 +1393,7 @@ def expr(self, _p:int=0): localctx = RelayParser.MetaExprContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 192 + self.state = 190 self.meta() pass @@ -1407,13 +1401,13 @@ def expr(self, _p:int=0): localctx = RelayParser.StringExprContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 193 + self.state = 191 self.match(RelayParser.QUOTED_STRING) pass self._ctx.stop = self._input.LT(-1) - self.state = 221 + self.state = 219 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,14,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: @@ -1421,17 +1415,17 @@ def expr(self, _p:int=0): if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx - self.state = 219 + self.state = 217 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,13,self._ctx) if la_ == 1: localctx = RelayParser.BinOpContext(self, RelayParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) - self.state = 196 + self.state = 194 if not self.precpred(self._ctx, 19): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 19)") - self.state = 197 + self.state = 195 localctx.op = self._input.LT(1) _la = self._input.LA(1) if not(_la==RelayParser.MUL or _la==RelayParser.DIV): @@ -1439,18 +1433,18 @@ def expr(self, _p:int=0): else: self._errHandler.reportMatch(self) self.consume() - self.state = 198 + self.state = 196 self.expr(20) pass elif la_ == 2: localctx = RelayParser.BinOpContext(self, RelayParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) - self.state = 199 + self.state = 197 if not self.precpred(self._ctx, 18): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 18)") - self.state = 200 + self.state = 198 localctx.op = self._input.LT(1) _la = self._input.LA(1) if not(_la==RelayParser.ADD or _la==RelayParser.SUB): @@ -1458,18 +1452,18 @@ def expr(self, _p:int=0): else: self._errHandler.reportMatch(self) self.consume() - self.state = 201 + self.state = 199 self.expr(19) pass elif la_ == 3: localctx = RelayParser.BinOpContext(self, RelayParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) - self.state = 202 + self.state = 200 if not self.precpred(self._ctx, 17): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 17)") - self.state = 203 + self.state = 201 localctx.op = self._input.LT(1) _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << RelayParser.LT) | (1 << RelayParser.GT) | (1 << RelayParser.LE) | (1 << RelayParser.GE))) != 0)): @@ -1477,18 +1471,18 @@ def expr(self, _p:int=0): else: self._errHandler.reportMatch(self) self.consume() - self.state = 204 + self.state = 202 self.expr(18) pass elif la_ == 4: localctx = RelayParser.BinOpContext(self, RelayParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) - self.state = 205 + self.state = 203 if not self.precpred(self._ctx, 16): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 16)") - self.state = 206 + self.state = 204 localctx.op = self._input.LT(1) _la = self._input.LA(1) if not(_la==RelayParser.EQ or _la==RelayParser.NE): @@ -1496,53 +1490,53 @@ def expr(self, _p:int=0): else: self._errHandler.reportMatch(self) self.consume() - self.state = 207 + self.state = 205 self.expr(17) pass elif la_ == 5: localctx = RelayParser.LetContext(self, RelayParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) - self.state = 208 + self.state = 206 if not self.precpred(self._ctx, 6): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 6)") - self.state = 209 + self.state = 207 self.match(RelayParser.T__16) - self.state = 210 + self.state = 208 self.expr(7) pass elif la_ == 6: localctx = RelayParser.CallContext(self, RelayParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) - self.state = 211 + self.state = 209 if not self.precpred(self._ctx, 21): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 21)") - self.state = 212 + self.state = 210 self.match(RelayParser.T__5) - self.state = 213 + self.state = 211 self.callList() - self.state = 214 + self.state = 212 self.match(RelayParser.T__6) pass elif la_ == 7: localctx = RelayParser.ProjectionContext(self, RelayParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) - self.state = 216 + self.state = 214 if not self.precpred(self._ctx, 8): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 8)") - self.state = 217 + self.state = 215 self.match(RelayParser.T__0) - self.state = 218 + self.state = 216 self.match(RelayParser.NAT) pass - self.state = 223 + self.state = 221 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,14,self._ctx) @@ -1596,33 +1590,33 @@ def func(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 224 + self.state = 222 self.match(RelayParser.T__17) - self.state = 226 + self.state = 224 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__7: - self.state = 225 + self.state = 223 self.typeParamList() - self.state = 228 + self.state = 226 self.match(RelayParser.T__5) - self.state = 229 + self.state = 227 self.argList() - self.state = 230 + self.state = 228 self.match(RelayParser.T__6) - self.state = 233 + self.state = 231 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__18: - self.state = 231 + self.state = 229 self.match(RelayParser.T__18) - self.state = 232 + self.state = 230 self.typeExpr() - self.state = 235 + self.state = 233 self.body() except RecognitionException as re: localctx.exception = re @@ -1728,57 +1722,57 @@ def defn(self): self.enterRule(localctx, 18, self.RULE_defn) self._la = 0 # Token type try: - self.state = 268 + self.state = 266 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.T__19]: localctx = RelayParser.FuncDefnContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 237 + self.state = 235 self.match(RelayParser.T__19) - self.state = 238 + self.state = 236 self.globalVar() - self.state = 240 + self.state = 238 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__7: - self.state = 239 + self.state = 237 self.typeParamList() - self.state = 242 + self.state = 240 self.match(RelayParser.T__5) - self.state = 243 + self.state = 241 self.argList() - self.state = 244 + self.state = 242 self.match(RelayParser.T__6) - self.state = 247 + self.state = 245 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__18: - self.state = 245 + self.state = 243 self.match(RelayParser.T__18) - self.state = 246 + self.state = 244 self.typeExpr() - self.state = 249 + self.state = 247 self.body() pass elif token in [RelayParser.T__20]: localctx = RelayParser.ExternAdtDefnContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 251 + self.state = 249 self.match(RelayParser.T__20) - self.state = 252 + self.state = 250 self.match(RelayParser.T__21) - self.state = 253 + self.state = 251 self.generalIdent() - self.state = 255 + self.state = 253 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__7: - self.state = 254 + self.state = 252 self.typeParamList() @@ -1786,29 +1780,29 @@ def defn(self): elif token in [RelayParser.T__21]: localctx = RelayParser.AdtDefnContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 257 + self.state = 255 self.match(RelayParser.T__21) - self.state = 258 + self.state = 256 self.generalIdent() - self.state = 260 + self.state = 258 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__7: - self.state = 259 + self.state = 257 self.typeParamList() - self.state = 262 + self.state = 260 self.match(RelayParser.T__11) - self.state = 264 + self.state = 262 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.CNAME: - self.state = 263 + self.state = 261 self.adtConsDefnList() - self.state = 266 + self.state = 264 self.match(RelayParser.T__12) pass else: @@ -1850,7 +1844,7 @@ def constructorName(self): self.enterRule(localctx, 20, self.RULE_constructorName) try: self.enterOuterAlt(localctx, 1) - self.state = 270 + self.state = 268 self.match(RelayParser.CNAME) except RecognitionException as re: localctx.exception = re @@ -1893,26 +1887,26 @@ def adtConsDefnList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 272 + self.state = 270 self.adtConsDefn() - self.state = 277 + self.state = 275 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,23,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: - self.state = 273 + self.state = 271 self.match(RelayParser.T__4) - self.state = 274 + self.state = 272 self.adtConsDefn() - self.state = 279 + self.state = 277 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,23,self._ctx) - self.state = 281 + self.state = 279 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__4: - self.state = 280 + self.state = 278 self.match(RelayParser.T__4) @@ -1961,29 +1955,29 @@ def adtConsDefn(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 283 + self.state = 281 self.constructorName() - self.state = 295 + self.state = 293 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__5: - self.state = 284 + self.state = 282 self.match(RelayParser.T__5) - self.state = 285 + self.state = 283 self.typeExpr() - self.state = 290 + self.state = 288 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 286 + self.state = 284 self.match(RelayParser.T__4) - self.state = 287 + self.state = 285 self.typeExpr() - self.state = 292 + self.state = 290 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 293 + self.state = 291 self.match(RelayParser.T__6) @@ -2028,26 +2022,26 @@ def matchClauseList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 297 + self.state = 295 self.matchClause() - self.state = 302 + self.state = 300 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,27,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: - self.state = 298 + self.state = 296 self.match(RelayParser.T__4) - self.state = 299 + self.state = 297 self.matchClause() - self.state = 304 + self.state = 302 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,27,self._ctx) - self.state = 306 + self.state = 304 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__4: - self.state = 305 + self.state = 303 self.match(RelayParser.T__4) @@ -2066,18 +2060,14 @@ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): super().__init__(parent, invokingState) self.parser = parser - def constructorName(self): - return self.getTypedRuleContext(RelayParser.ConstructorNameContext,0) + def pattern(self): + return self.getTypedRuleContext(RelayParser.PatternContext,0) def expr(self): return self.getTypedRuleContext(RelayParser.ExprContext,0) - def patternList(self): - return self.getTypedRuleContext(RelayParser.PatternListContext,0) - - def getRuleIndex(self): return RelayParser.RULE_matchClause @@ -2094,34 +2084,25 @@ def matchClause(self): localctx = RelayParser.MatchClauseContext(self, self._ctx, self.state) self.enterRule(localctx, 28, self.RULE_matchClause) - self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 308 - self.constructorName() - self.state = 310 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==RelayParser.T__5: - self.state = 309 - self.patternList() - - - self.state = 312 + self.state = 306 + self.pattern() + self.state = 307 self.match(RelayParser.T__22) - self.state = 318 + self.state = 313 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.T__11]: - self.state = 313 + self.state = 308 self.match(RelayParser.T__11) - self.state = 314 + self.state = 309 self.expr(0) - self.state = 315 + self.state = 310 self.match(RelayParser.T__12) pass elif token in [RelayParser.T__1, RelayParser.T__2, RelayParser.T__5, RelayParser.T__7, RelayParser.T__9, RelayParser.T__13, RelayParser.T__17, RelayParser.T__23, RelayParser.T__24, RelayParser.T__27, RelayParser.QUOTED_STRING, RelayParser.SUB, RelayParser.BOOL_LIT, RelayParser.CNAME, RelayParser.FLOAT, RelayParser.NAT]: - self.state = 317 + self.state = 312 self.expr(0) pass else: @@ -2162,7 +2143,7 @@ def matchType(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 320 + self.state = 315 _la = self._input.LA(1) if not(_la==RelayParser.T__23 or _la==RelayParser.T__24): self._errHandler.recoverInline(self) @@ -2210,23 +2191,23 @@ def patternList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 322 + self.state = 317 self.match(RelayParser.T__5) - self.state = 323 + self.state = 318 self.pattern() - self.state = 328 + self.state = 323 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 324 + self.state = 319 self.match(RelayParser.T__4) - self.state = 325 + self.state = 320 self.pattern() - self.state = 330 + self.state = 325 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 331 + self.state = 326 self.match(RelayParser.T__6) except RecognitionException as re: localctx.exception = re @@ -2243,32 +2224,86 @@ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): super().__init__(parent, invokingState) self.parser = parser - def localVar(self): - return self.getTypedRuleContext(RelayParser.LocalVarContext,0) + + def getRuleIndex(self): + return RelayParser.RULE_pattern + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) - def typeExpr(self): - return self.getTypedRuleContext(RelayParser.TypeExprContext,0) + class WildcardPatternContext(PatternContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a RelayParser.PatternContext + super().__init__(parser) + self.copyFrom(ctx) + + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitWildcardPattern" ): + return visitor.visitWildcardPattern(self) + else: + return visitor.visitChildren(self) + + + class ConstructorPatternContext(PatternContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a RelayParser.PatternContext + super().__init__(parser) + self.copyFrom(ctx) def constructorName(self): return self.getTypedRuleContext(RelayParser.ConstructorNameContext,0) - def patternList(self): return self.getTypedRuleContext(RelayParser.PatternListContext,0) - def getRuleIndex(self): - return RelayParser.RULE_pattern + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitConstructorPattern" ): + return visitor.visitConstructorPattern(self) + else: + return visitor.visitChildren(self) + + + class TuplePatternContext(PatternContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a RelayParser.PatternContext + super().__init__(parser) + self.copyFrom(ctx) + + def patternList(self): + return self.getTypedRuleContext(RelayParser.PatternListContext,0) + def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitPattern" ): - return visitor.visitPattern(self) + if hasattr( visitor, "visitTuplePattern" ): + return visitor.visitTuplePattern(self) else: return visitor.visitChildren(self) + class VarPatternContext(PatternContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a RelayParser.PatternContext + super().__init__(parser) + self.copyFrom(ctx) + + def localVar(self): + return self.getTypedRuleContext(RelayParser.LocalVarContext,0) + + def typeExpr(self): + return self.getTypedRuleContext(RelayParser.TypeExprContext,0) + + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitVarPattern" ): + return visitor.visitVarPattern(self) + else: + return visitor.visitChildren(self) + def pattern(self): @@ -2277,41 +2312,50 @@ def pattern(self): self.enterRule(localctx, 34, self.RULE_pattern) self._la = 0 # Token type try: - self.state = 343 + self.state = 339 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.T__3]: + localctx = RelayParser.WildcardPatternContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 333 + self.state = 328 self.match(RelayParser.T__3) pass elif token in [RelayParser.T__2]: + localctx = RelayParser.VarPatternContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 334 + self.state = 329 self.localVar() - self.state = 337 + self.state = 332 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__25: - self.state = 335 + self.state = 330 self.match(RelayParser.T__25) - self.state = 336 + self.state = 331 self.typeExpr() pass elif token in [RelayParser.CNAME]: + localctx = RelayParser.ConstructorPatternContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 339 + self.state = 334 self.constructorName() - self.state = 341 + self.state = 336 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__5: - self.state = 340 + self.state = 335 self.patternList() + pass + elif token in [RelayParser.T__5]: + localctx = RelayParser.TuplePatternContext(self, localctx) + self.enterOuterAlt(localctx, 4) + self.state = 338 + self.patternList() pass else: raise NoViableAltException(self) @@ -2358,13 +2402,13 @@ def adtCons(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 345 + self.state = 341 self.constructorName() - self.state = 347 + self.state = 343 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__5: - self.state = 346 + self.state = 342 self.adtConsParamList() @@ -2409,23 +2453,23 @@ def adtConsParamList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 349 + self.state = 345 self.match(RelayParser.T__5) - self.state = 350 + self.state = 346 self.adtConsParam() - self.state = 355 + self.state = 351 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 351 + self.state = 347 self.match(RelayParser.T__4) - self.state = 352 + self.state = 348 self.adtConsParam() - self.state = 357 + self.state = 353 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 358 + self.state = 354 self.match(RelayParser.T__6) except RecognitionException as re: localctx.exception = re @@ -2467,17 +2511,17 @@ def adtConsParam(self): localctx = RelayParser.AdtConsParamContext(self, self._ctx, self.state) self.enterRule(localctx, 40, self.RULE_adtConsParam) try: - self.state = 362 + self.state = 358 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.T__2]: self.enterOuterAlt(localctx, 1) - self.state = 360 + self.state = 356 self.localVar() pass elif token in [RelayParser.CNAME]: self.enterOuterAlt(localctx, 2) - self.state = 361 + self.state = 357 self.constructorName() pass else: @@ -2555,32 +2599,32 @@ def argList(self): self.enterRule(localctx, 42, self.RULE_argList) self._la = 0 # Token type try: - self.state = 374 + self.state = 370 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,39,self._ctx) + la_ = self._interp.adaptivePredict(self._input,38,self._ctx) if la_ == 1: localctx = RelayParser.ArgNoAttrContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 364 + self.state = 360 self.varList() pass elif la_ == 2: localctx = RelayParser.ArgWithAttrContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 370 + self.state = 366 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__2: - self.state = 365 + self.state = 361 self.var() - self.state = 366 + self.state = 362 self.match(RelayParser.T__4) - self.state = 372 + self.state = 368 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 373 + self.state = 369 self.attrSeq() pass @@ -2626,21 +2670,21 @@ def varList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 384 + self.state = 380 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__2: - self.state = 376 + self.state = 372 self.var() - self.state = 381 + self.state = 377 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 377 + self.state = 373 self.match(RelayParser.T__4) - self.state = 378 + self.state = 374 self.var() - self.state = 383 + self.state = 379 self._errHandler.sync(self) _la = self._input.LA(1) @@ -2688,15 +2732,15 @@ def var(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 386 + self.state = 382 self.localVar() - self.state = 389 + self.state = 385 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__25: - self.state = 387 + self.state = 383 self.match(RelayParser.T__25) - self.state = 388 + self.state = 384 self.typeExpr() @@ -2741,17 +2785,17 @@ def attrSeq(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 391 + self.state = 387 self.attr() - self.state = 396 + self.state = 392 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 392 + self.state = 388 self.match(RelayParser.T__4) - self.state = 393 + self.state = 389 self.attr() - self.state = 398 + self.state = 394 self._errHandler.sync(self) _la = self._input.LA(1) @@ -2795,11 +2839,11 @@ def attr(self): self.enterRule(localctx, 50, self.RULE_attr) try: self.enterOuterAlt(localctx, 1) - self.state = 399 + self.state = 395 self.match(RelayParser.CNAME) - self.state = 400 + self.state = 396 self.match(RelayParser.T__14) - self.state = 401 + self.state = 397 self.expr(0) except RecognitionException as re: localctx.exception = re @@ -2964,147 +3008,147 @@ def typeExpr(self): self.enterRule(localctx, 52, self.RULE_typeExpr) self._la = 0 # Token type try: - self.state = 454 + self.state = 450 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,48,self._ctx) + la_ = self._interp.adaptivePredict(self._input,47,self._ctx) if la_ == 1: localctx = RelayParser.TupleTypeContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 403 + self.state = 399 self.match(RelayParser.T__5) - self.state = 404 + self.state = 400 self.match(RelayParser.T__6) pass elif la_ == 2: localctx = RelayParser.TypeParenContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 405 + self.state = 401 self.match(RelayParser.T__5) - self.state = 406 + self.state = 402 self.typeExpr() - self.state = 407 + self.state = 403 self.match(RelayParser.T__6) pass elif la_ == 3: localctx = RelayParser.TupleTypeContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 409 + self.state = 405 self.match(RelayParser.T__5) - self.state = 410 + self.state = 406 self.typeExpr() - self.state = 411 + self.state = 407 self.match(RelayParser.T__4) - self.state = 412 + self.state = 408 self.match(RelayParser.T__6) pass elif la_ == 4: localctx = RelayParser.TupleTypeContext(self, localctx) self.enterOuterAlt(localctx, 4) - self.state = 414 + self.state = 410 self.match(RelayParser.T__5) - self.state = 415 + self.state = 411 self.typeExpr() - self.state = 418 + self.state = 414 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 416 + self.state = 412 self.match(RelayParser.T__4) - self.state = 417 + self.state = 413 self.typeExpr() - self.state = 420 + self.state = 416 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==RelayParser.T__4): break - self.state = 422 + self.state = 418 self.match(RelayParser.T__6) pass elif la_ == 5: localctx = RelayParser.TypeCallTypeContext(self, localctx) self.enterOuterAlt(localctx, 5) - self.state = 424 + self.state = 420 self.generalIdent() - self.state = 425 + self.state = 421 self.typeParamList() pass elif la_ == 6: localctx = RelayParser.TypeIdentTypeContext(self, localctx) self.enterOuterAlt(localctx, 6) - self.state = 427 + self.state = 423 self.generalIdent() pass elif la_ == 7: localctx = RelayParser.TensorTypeContext(self, localctx) self.enterOuterAlt(localctx, 7) - self.state = 428 + self.state = 424 self.match(RelayParser.T__26) - self.state = 429 + self.state = 425 self.match(RelayParser.T__7) - self.state = 430 + self.state = 426 self.shapeList() - self.state = 431 + self.state = 427 self.match(RelayParser.T__4) - self.state = 432 + self.state = 428 self.typeExpr() - self.state = 433 + self.state = 429 self.match(RelayParser.T__8) pass elif la_ == 8: localctx = RelayParser.FuncTypeContext(self, localctx) self.enterOuterAlt(localctx, 8) - self.state = 435 + self.state = 431 self.match(RelayParser.T__17) - self.state = 437 + self.state = 433 self._errHandler.sync(self) _la = self._input.LA(1) if _la==RelayParser.T__7: - self.state = 436 + self.state = 432 self.typeParamList() - self.state = 439 + self.state = 435 self.match(RelayParser.T__5) - self.state = 448 + self.state = 444 self._errHandler.sync(self) _la = self._input.LA(1) if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << RelayParser.T__3) | (1 << RelayParser.T__5) | (1 << RelayParser.T__17) | (1 << RelayParser.T__26) | (1 << RelayParser.CNAME))) != 0): - self.state = 440 + self.state = 436 self.typeExpr() - self.state = 445 + self.state = 441 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 441 + self.state = 437 self.match(RelayParser.T__4) - self.state = 442 + self.state = 438 self.typeExpr() - self.state = 447 + self.state = 443 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 450 + self.state = 446 self.match(RelayParser.T__6) - self.state = 451 + self.state = 447 self.match(RelayParser.T__18) - self.state = 452 + self.state = 448 self.typeExpr() pass elif la_ == 9: localctx = RelayParser.IncompleteTypeContext(self, localctx) self.enterOuterAlt(localctx, 9) - self.state = 453 + self.state = 449 self.match(RelayParser.T__3) pass @@ -3150,23 +3194,23 @@ def typeParamList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 456 + self.state = 452 self.match(RelayParser.T__7) - self.state = 457 + self.state = 453 self.typeExpr() - self.state = 462 + self.state = 458 self._errHandler.sync(self) _la = self._input.LA(1) while _la==RelayParser.T__4: - self.state = 458 + self.state = 454 self.match(RelayParser.T__4) - self.state = 459 + self.state = 455 self.typeExpr() - self.state = 464 + self.state = 460 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 465 + self.state = 461 self.match(RelayParser.T__8) except RecognitionException as re: localctx.exception = re @@ -3208,44 +3252,44 @@ def shapeList(self): self.enterRule(localctx, 56, self.RULE_shapeList) self._la = 0 # Token type try: - self.state = 480 + self.state = 476 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,51,self._ctx) + la_ = self._interp.adaptivePredict(self._input,50,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 467 + self.state = 463 self.match(RelayParser.T__5) - self.state = 468 + self.state = 464 self.match(RelayParser.T__6) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 469 + self.state = 465 self.match(RelayParser.T__5) - self.state = 470 + self.state = 466 self.shape() - self.state = 473 + self.state = 469 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 471 + self.state = 467 self.match(RelayParser.T__4) - self.state = 472 + self.state = 468 self.shape() - self.state = 475 + self.state = 471 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==RelayParser.T__4): break - self.state = 477 + self.state = 473 self.match(RelayParser.T__6) pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 479 + self.state = 475 self.shape() pass @@ -3289,19 +3333,19 @@ def meta(self): self.enterRule(localctx, 58, self.RULE_meta) try: self.enterOuterAlt(localctx, 1) - self.state = 482 + self.state = 478 self.match(RelayParser.T__27) - self.state = 483 + self.state = 479 self.match(RelayParser.T__7) - self.state = 484 + self.state = 480 self.match(RelayParser.CNAME) - self.state = 485 + self.state = 481 self.match(RelayParser.T__8) - self.state = 486 + self.state = 482 self.match(RelayParser.T__7) - self.state = 487 + self.state = 483 self.match(RelayParser.NAT) - self.state = 488 + self.state = 484 self.match(RelayParser.T__8) except RecognitionException as re: localctx.exception = re @@ -3384,29 +3428,29 @@ def shape(self): localctx = RelayParser.ShapeContext(self, self._ctx, self.state) self.enterRule(localctx, 60, self.RULE_shape) try: - self.state = 496 + self.state = 492 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.T__27]: localctx = RelayParser.MetaShapeContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 490 + self.state = 486 self.meta() pass elif token in [RelayParser.T__5]: localctx = RelayParser.ParensShapeContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 491 + self.state = 487 self.match(RelayParser.T__5) - self.state = 492 + self.state = 488 self.shape() - self.state = 493 + self.state = 489 self.match(RelayParser.T__6) pass elif token in [RelayParser.NAT]: localctx = RelayParser.IntShapeContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 495 + self.state = 491 self.match(RelayParser.NAT) pass else: @@ -3449,11 +3493,11 @@ def body(self): self.enterRule(localctx, 62, self.RULE_body) try: self.enterOuterAlt(localctx, 1) - self.state = 498 + self.state = 494 self.match(RelayParser.T__11) - self.state = 499 + self.state = 495 self.expr(0) - self.state = 500 + self.state = 496 self.match(RelayParser.T__12) except RecognitionException as re: localctx.exception = re @@ -3534,25 +3578,25 @@ def scalar(self): localctx = RelayParser.ScalarContext(self, self._ctx, self.state) self.enterRule(localctx, 64, self.RULE_scalar) try: - self.state = 505 + self.state = 501 self._errHandler.sync(self) token = self._input.LA(1) if token in [RelayParser.FLOAT]: localctx = RelayParser.ScalarFloatContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 502 + self.state = 498 self.match(RelayParser.FLOAT) pass elif token in [RelayParser.NAT]: localctx = RelayParser.ScalarIntContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 503 + self.state = 499 self.match(RelayParser.NAT) pass elif token in [RelayParser.BOOL_LIT]: localctx = RelayParser.ScalarBoolContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 504 + self.state = 500 self.match(RelayParser.BOOL_LIT) pass else: @@ -3606,30 +3650,30 @@ def ident(self): localctx = RelayParser.IdentContext(self, self._ctx, self.state) self.enterRule(localctx, 66, self.RULE_ident) try: - self.state = 511 + self.state = 507 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,54,self._ctx) + la_ = self._interp.adaptivePredict(self._input,53,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 507 + self.state = 503 self.generalIdent() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 508 + self.state = 504 self.globalVar() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 509 + self.state = 505 self.localVar() pass elif la_ == 4: self.enterOuterAlt(localctx, 4) - self.state = 510 + self.state = 506 self.graphVar() pass diff --git a/python/tvm/relay/grammar/py3/RelayVisitor.py b/python/tvm/relay/grammar/py3/RelayVisitor.py index f0a3f1964f24..c6a7b7a0558c 100644 --- a/python/tvm/relay/grammar/py3/RelayVisitor.py +++ b/python/tvm/relay/grammar/py3/RelayVisitor.py @@ -184,8 +184,23 @@ def visitPatternList(self, ctx:RelayParser.PatternListContext): return self.visitChildren(ctx) - # Visit a parse tree produced by RelayParser#pattern. - def visitPattern(self, ctx:RelayParser.PatternContext): + # Visit a parse tree produced by RelayParser#wildcardPattern. + def visitWildcardPattern(self, ctx:RelayParser.WildcardPatternContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by RelayParser#varPattern. + def visitVarPattern(self, ctx:RelayParser.VarPatternContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by RelayParser#constructorPattern. + def visitConstructorPattern(self, ctx:RelayParser.ConstructorPatternContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by RelayParser#tuplePattern. + def visitTuplePattern(self, ctx:RelayParser.TuplePatternContext): return self.visitChildren(ctx) From ea3ca0f5131dd7cee366d48c72dab6f7253f53e9 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Wed, 11 Sep 2019 18:08:33 -0700 Subject: [PATCH 09/15] Improve some prelude defs --- python/tvm/relay/prelude.py | 3 +++ python/tvm/relay/std/prelude.rly | 21 ++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/python/tvm/relay/prelude.py b/python/tvm/relay/prelude.py index 93bba57975d8..bc1a86715472 100644 --- a/python/tvm/relay/prelude.py +++ b/python/tvm/relay/prelude.py @@ -52,6 +52,9 @@ def load_prelude(self): self.rose = tree_adt.constructors[0] GLOBAL_DEFS = [ + "id", + "compose", + "flip", "hd", "tl", "nth", diff --git a/python/tvm/relay/std/prelude.rly b/python/tvm/relay/std/prelude.rly index f120cd3c7ae6..62b520b6315b 100644 --- a/python/tvm/relay/std/prelude.rly +++ b/python/tvm/relay/std/prelude.rly @@ -30,6 +30,12 @@ def @compose[A, B, C](%f: fn(B) -> C, %g: fn(A) -> B) { } } +def @flip[A, B, C](%f: fn(A, B) -> C) -> fn(B, A) -> C { + fn(%b: B, %a: A) -> C { + %f(%a, %b) + } +} + /* * A LISP-style list ADT. An empty list is represented by `Nil`, and a member * `x` can be appended to the front of a list `l` via the constructor `Cons(x, l)`. @@ -153,11 +159,7 @@ def @sum(%xs: List[Tensor[(), int32]]) { * Concatenates two lists. */ def @concat[A](%xs: List[A], %ys: List[A]) -> List[A] { - // TODO(weberlo): allow using `Cons` directly as the arg to foldr - let %updater = fn(%x: A, %yss: List[A]) -> List[A] { - Cons(%x, %yss) - }; - @foldr(%updater, %ys, %xs) + @foldr(Cons, %ys, %xs) } /* @@ -191,11 +193,8 @@ def @zip[A, B](%xs: List[A], %ys: List[B]) -> List[(A, B)] { /* * Reverses a list. */ -def @reverse[A](%xs: List[A]) -> List[A] { - let %updater = fn(%ys: List[A], %x: A) -> List[A] { - Cons(%x, %ys) - }; - @foldl(%updater, Nil, %xs) +def @rev[A](%xs: List[A]) -> List[A] { + @foldl(@flip(Cons), Nil, %xs) } /* @@ -256,7 +255,7 @@ def @unfoldr[A, B](%f: fn(A) -> Option[(A, B)], %seed: A) -> List[B] { * output values will be combined into a list, left to right. */ def @unfoldl[A, B](%f: fn(A) -> Option[(A, B)], %seed: A) -> List[B] { - @reverse(@unfoldr(%f, %seed)) + @rev(@unfoldr(%f, %seed)) } /* From 67302e99a00eb3b7d66b27f285c1a49e6491e804 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Sun, 15 Sep 2019 16:36:51 -0500 Subject: [PATCH 10/15] Fix `ImportFromStd` It needs to also follow the "add unchecked, add checked" pattern --- include/tvm/relay/module.h | 22 ++++++++++--------- src/relay/ir/module.cc | 43 ++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/include/tvm/relay/module.h b/include/tvm/relay/module.h index c7ff5bea071f..1dec29a1c3d1 100644 --- a/include/tvm/relay/module.h +++ b/include/tvm/relay/module.h @@ -87,15 +87,6 @@ class ModuleNode : public RelayNode { */ TVM_DLL void Add(const GlobalVar& var, const Function& func, bool update = false); - /*! - * \brief Add a type-level definition to the global environment. - * \param var The var of the global type definition. - * \param type The type definition. - * \param update Controls whether you can replace a definition in the - * environment. - */ - TVM_DLL void AddDef(const GlobalTypeVar& var, const TypeData& type, bool update = false); - /*! * \brief Add a function to the global environment. * \param var The name of the global function. @@ -105,14 +96,25 @@ class ModuleNode : public RelayNode { */ TVM_DLL void AddUnchecked(const GlobalVar& var, const Function& func); + /*! + * \brief Add a type-level definition to the global environment. + * \param var The var of the global type definition. + * \param type The type definition. + * \param update Controls whether you can replace a definition in the + * environment. + */ + TVM_DLL void AddDef(const GlobalTypeVar& var, const TypeData& type, bool update = false); + /*! * \brief Add a type definition to the global environment. * \param var The name of the global function. * \param func The function. + * \param update Controls whether you can replace a definition in the + * environment. * * It does not do type inference as AddDef does. */ - TVM_DLL void AddDefUnchecked(const GlobalTypeVar& var, const TypeData& type); + TVM_DLL void AddDefUnchecked(const GlobalTypeVar& var, const TypeData& type, bool update = false); /*! * \brief Update a function in the global environment. diff --git a/src/relay/ir/module.cc b/src/relay/ir/module.cc index 1ab3ad70adbf..48164d84adab 100644 --- a/src/relay/ir/module.cc +++ b/src/relay/ir/module.cc @@ -46,14 +46,14 @@ Module ModuleNode::make(tvm::Map global_funcs, for (const auto& kv : n->functions) { // set global var map - CHECK(!n->global_var_map_.count(kv.first->name_hint)) + CHECK(n->global_var_map_.count(kv.first->name_hint) == 0) << "Duplicate global function name " << kv.first->name_hint; n->global_var_map_.Set(kv.first->name_hint, kv.first); } for (const auto& kv : n->type_definitions) { // set global typevar map - CHECK(!n->global_type_var_map_.count(kv.first->var->name_hint)) + CHECK(n->global_type_var_map_.count(kv.first->var->name_hint) == 0) << "Duplicate global type definition name " << kv.first->var->name_hint; n->global_type_var_map_.Set(kv.first->var->name_hint, kv.first); n->RegisterConstructors(kv.first, kv.second); @@ -160,7 +160,7 @@ void ModuleNode::AddUnchecked(const GlobalVar& var, if (it != global_var_map_.end()) { CHECK_EQ((*it).second, var); } else { - CHECK(!global_var_map_.count(var->name_hint)) + CHECK(global_var_map_.count(var->name_hint) == 0) << "Duplicate global function name " << var->name_hint; } @@ -180,25 +180,20 @@ void ModuleNode::RegisterConstructors(const GlobalTypeVar& var, const TypeData& } void ModuleNode::AddDef(const GlobalTypeVar& var, const TypeData& type, bool update) { - this->type_definitions.Set(var, type); - // set global type var map - CHECK(update || global_type_var_map_.count(var->var->name_hint) == 0) - << "Duplicate global type definition name " << var->var->name_hint; - - global_type_var_map_.Set(var->var->name_hint, var); - RegisterConstructors(var, type); - + AddDefUnchecked(var, type, update); // need to kind check at the end because the check can look up // a definition potentially CHECK(KindCheck(type, GetRef(this)) == Kind::kTypeData) << "Invalid or malformed typedata given to module: " << type; } -void ModuleNode::AddDefUnchecked(const GlobalTypeVar& var, const TypeData& type) { +void ModuleNode::AddDefUnchecked(const GlobalTypeVar& var, const TypeData& type, bool update) { this->type_definitions.Set(var, type); - // set global type var map - CHECK(!global_type_var_map_.count(var->var->name_hint)) - << "Duplicate global type definition name " << var->var->name_hint; + if (!update) { + // set global type var map + CHECK(global_type_var_map_.count(var->var->name_hint) == 0) + << "Duplicate global type definition name " << var->var->name_hint; + } global_type_var_map_.Set(var->var->name_hint, var); RegisterConstructors(var, type); } @@ -299,12 +294,20 @@ void ModuleNode::Import(const std::string& path) { std::istreambuf_iterator() }; auto mod_to_import = FromText(file_contents, path); - for (auto func : mod_to_import->functions) { - this->Add(func.first, func.second, false); + // add type defs. we add them unchecked first, so all definitions can + // reference each other, independent of the order in which they were defined. + for (auto pair : mod_to_import->type_definitions) { + this->AddDefUnchecked(pair.first, pair.second); } - - for (auto type : mod_to_import->type_definitions) { - this->AddDef(type.first, type.second); + for (auto pair : mod_to_import->type_definitions) { + this->UpdateDef(pair.first, pair.second); + } + // then add func defs in a similar fashion + for (auto pair : mod_to_import->functions) { + this->AddUnchecked(pair.first, pair.second); + } + for (auto pair : mod_to_import->functions) { + this->Update(pair.first, pair.second); } } } From 526e5367af6c21ecddce7895ad0f9cc43929eed9 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Sun, 15 Sep 2019 21:24:27 -0500 Subject: [PATCH 11/15] Lint roller --- python/tvm/relay/_parser.py | 2 +- python/tvm/relay/prelude.py | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/python/tvm/relay/_parser.py b/python/tvm/relay/_parser.py index c63c9383e4f1..3ea016b7e888 100644 --- a/python/tvm/relay/_parser.py +++ b/python/tvm/relay/_parser.py @@ -297,7 +297,7 @@ def visitGeneralIdent(self, ctx): if type_expr is not None: # Zero-arity constructor calls fall into the general ident case, so in that case, # we construct a constructor call with no args. - if isinstance(type_expr, adt.Constructor) and len(type_expr.inputs) == 0: + if isinstance(type_expr, adt.Constructor) and not len(type_expr.inputs): type_expr = expr.Call(type_expr, []) return type_expr # Check if it's an operator. diff --git a/python/tvm/relay/prelude.py b/python/tvm/relay/prelude.py index bc1a86715472..803d8ef50db5 100644 --- a/python/tvm/relay/prelude.py +++ b/python/tvm/relay/prelude.py @@ -16,11 +16,6 @@ # under the License. # pylint: disable=no-else-return, unidiomatic-typecheck, invalid-name """A prelude containing useful global functions and ADT definitions.""" -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, PatternTuple from .module import Module class Prelude: From 7139a9302c42387dddbc3fd2553df62fd497c20e Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Sun, 15 Sep 2019 21:28:54 -0500 Subject: [PATCH 12/15] Woops --- python/tvm/relay/_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tvm/relay/_parser.py b/python/tvm/relay/_parser.py index 3ea016b7e888..d59c25fad60a 100644 --- a/python/tvm/relay/_parser.py +++ b/python/tvm/relay/_parser.py @@ -297,7 +297,7 @@ def visitGeneralIdent(self, ctx): if type_expr is not None: # Zero-arity constructor calls fall into the general ident case, so in that case, # we construct a constructor call with no args. - if isinstance(type_expr, adt.Constructor) and not len(type_expr.inputs): + if isinstance(type_expr, adt.Constructor) and not type_expr.inputs: type_expr = expr.Call(type_expr, []) return type_expr # Check if it's an operator. From 8fbe61c30b9e64cc7a72da70d2b39f8cf22d8f05 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Mon, 16 Sep 2019 07:02:11 -0500 Subject: [PATCH 13/15] Address feedback --- include/tvm/relay/module.h | 6 +++--- src/relay/ir/module.cc | 17 +---------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/include/tvm/relay/module.h b/include/tvm/relay/module.h index 1dec29a1c3d1..8b17020a1132 100644 --- a/include/tvm/relay/module.h +++ b/include/tvm/relay/module.h @@ -99,7 +99,7 @@ class ModuleNode : public RelayNode { /*! * \brief Add a type-level definition to the global environment. * \param var The var of the global type definition. - * \param type The type definition. + * \param type The ADT. * \param update Controls whether you can replace a definition in the * environment. */ @@ -108,7 +108,7 @@ class ModuleNode : public RelayNode { /*! * \brief Add a type definition to the global environment. * \param var The name of the global function. - * \param func The function. + * \param type The ADT. * \param update Controls whether you can replace a definition in the * environment. * @@ -126,7 +126,7 @@ class ModuleNode : public RelayNode { /*! * \brief Update a type definition in the global environment. * \param var The name of the global type definition to update. - * \param func The new function. + * \param type The new ADT. */ TVM_DLL void UpdateDef(const GlobalTypeVar& var, const TypeData& type); diff --git a/src/relay/ir/module.cc b/src/relay/ir/module.cc index 48164d84adab..55167ba3017e 100644 --- a/src/relay/ir/module.cc +++ b/src/relay/ir/module.cc @@ -293,22 +293,7 @@ void ModuleNode::Import(const std::string& path) { std::istreambuf_iterator(src_file), std::istreambuf_iterator() }; auto mod_to_import = FromText(file_contents, path); - - // add type defs. we add them unchecked first, so all definitions can - // reference each other, independent of the order in which they were defined. - for (auto pair : mod_to_import->type_definitions) { - this->AddDefUnchecked(pair.first, pair.second); - } - for (auto pair : mod_to_import->type_definitions) { - this->UpdateDef(pair.first, pair.second); - } - // then add func defs in a similar fashion - for (auto pair : mod_to_import->functions) { - this->AddUnchecked(pair.first, pair.second); - } - for (auto pair : mod_to_import->functions) { - this->Update(pair.first, pair.second); - } + Update(mod_to_import); } } From b93104afc562e7c6f778d3e1c258faf812a7f7a7 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Fri, 27 Sep 2019 09:45:26 -0700 Subject: [PATCH 14/15] Fix `test_list_constructor` VM test --- include/tvm/relay/expr_functor.h | 3 ++- include/tvm/relay/pattern_functor.h | 3 ++- python/tvm/relay/std/prelude.rly | 14 ++++++++++++-- src/relay/ir/module.cc | 17 ++++++++--------- src/relay/ir/pretty_printer.cc | 11 +++++++++++ 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/include/tvm/relay/expr_functor.h b/include/tvm/relay/expr_functor.h index 7e6fb7f2a5fe..e0d940c5d1a5 100644 --- a/include/tvm/relay/expr_functor.h +++ b/include/tvm/relay/expr_functor.h @@ -117,7 +117,8 @@ class ExprFunctor { virtual R VisitExpr_(const ConstructorNode* op, Args... args) EXPR_FUNCTOR_DEFAULT; virtual R VisitExpr_(const MatchNode* op, Args... args) EXPR_FUNCTOR_DEFAULT; virtual R VisitExprDefault_(const Node* op, Args...) { - throw Error(std::string("Do not have a default for ") + op->type_key()); + LOG(FATAL) << "Do not have a default for " << op->type_key(); + throw; } private: diff --git a/include/tvm/relay/pattern_functor.h b/include/tvm/relay/pattern_functor.h index 611b7431d414..7f1c47e03592 100644 --- a/include/tvm/relay/pattern_functor.h +++ b/include/tvm/relay/pattern_functor.h @@ -103,7 +103,8 @@ class PatternFunctor { virtual R VisitPattern_(const PatternTupleNode* op, Args... args) PATTERN_FUNCTOR_DEFAULT; virtual R VisitPatternDefault_(const Node* op, Args...) { - throw Error(std::string("Do not have a default for ") + op->type_key()); + LOG(FATAL) << "Do not have a default for " << op->type_key(); + throw; } private: diff --git a/python/tvm/relay/std/prelude.rly b/python/tvm/relay/std/prelude.rly index 62b520b6315b..702174892deb 100644 --- a/python/tvm/relay/std/prelude.rly +++ b/python/tvm/relay/std/prelude.rly @@ -159,7 +159,12 @@ def @sum(%xs: List[Tensor[(), int32]]) { * Concatenates two lists. */ def @concat[A](%xs: List[A], %ys: List[A]) -> List[A] { - @foldr(Cons, %ys, %xs) + let %updater = fn(%x: A, %xss: List[A]) -> List[A] { + Cons(%x, %xss) + }; + @foldr(%updater, %ys, %xs) + // TODO(weberlo): write it like below, once VM constructor compilation is fixed + // @foldr(Cons, %ys, %xs) } /* @@ -194,7 +199,12 @@ def @zip[A, B](%xs: List[A], %ys: List[B]) -> List[(A, B)] { * Reverses a list. */ def @rev[A](%xs: List[A]) -> List[A] { - @foldl(@flip(Cons), Nil, %xs) + let %updater = fn(%xss: List[A], %x: A) -> List[A] { + Cons(%x, %xss) + }; + @foldl(%updater, Nil, %xs) + // TODO(weberlo): write it like below, once VM constructor compilation is fixed + // @foldl(@flip(Cons), Nil, %xs) } /* diff --git a/src/relay/ir/module.cc b/src/relay/ir/module.cc index 55167ba3017e..0e8e6f5591dd 100644 --- a/src/relay/ir/module.cc +++ b/src/relay/ir/module.cc @@ -250,21 +250,20 @@ Constructor ModuleNode::LookupTag(const int32_t tag) { } void ModuleNode::Update(const Module& mod) { - // add type defs. we add them unchecked first, so all definitions can - // reference each other, independent of the order in which they were defined. - for (auto pair : mod->type_definitions) { - this->AddDefUnchecked(pair.first, pair.second); - } - for (auto pair : mod->type_definitions) { - this->UpdateDef(pair.first, pair.second); - } - // then add func defs in a similar fashion + // add functions and type defs. we add them unchecked first, so all definitions + // can reference each other, independent of the order in which they were defined. for (auto pair : mod->functions) { this->AddUnchecked(pair.first, pair.second); } + for (auto pair : mod->type_definitions) { + this->AddDefUnchecked(pair.first, pair.second); + } for (auto pair : mod->functions) { this->Update(pair.first, pair.second); } + for (auto pair : mod->type_definitions) { + this->UpdateDef(pair.first, pair.second); + } } Module ModuleNode::FromExpr( diff --git a/src/relay/ir/pretty_printer.cc b/src/relay/ir/pretty_printer.cc index e361a00f8d80..afc8ad9dcf6a 100644 --- a/src/relay/ir/pretty_printer.cc +++ b/src/relay/ir/pretty_printer.cc @@ -647,6 +647,17 @@ class PrettyPrinter : return doc; } + Doc VisitPattern_(const PatternTupleNode* pt) final { + Doc doc; + doc << "("; + std::vector pats; + for (const auto& pat : pt->patterns) { + pats.push_back(Print(pat)); + } + doc << PrintSep(pats) << ")"; + return doc; + } + Doc VisitPattern_(const PatternWildcardNode* pw) final { return Doc("_"); } From 284e3c2e5a0dae49ca1e63e413cfe338d782cd04 Mon Sep 17 00:00:00 2001 From: Logan Weber Date: Sat, 28 Sep 2019 14:04:20 -0700 Subject: [PATCH 15/15] Fix `test_adt.py` failures --- python/tvm/relay/_parser.py | 2 +- python/tvm/relay/std/prelude.rly | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/tvm/relay/_parser.py b/python/tvm/relay/_parser.py index d59c25fad60a..325108893d06 100644 --- a/python/tvm/relay/_parser.py +++ b/python/tvm/relay/_parser.py @@ -231,7 +231,7 @@ def exit_type_param_scope(self) -> Scope[ty.TypeVar]: def mk_typ(self, name: str, kind: ty.Kind) -> ty.TypeVar: """Create a new TypeVar and add it to the TypeVar scope.""" typ = ty.TypeVar(name, kind) - self.type_var_scopes[0].appendleft((name, typ)) + self.type_var_scopes[0].append((name, typ)) return typ def mk_global_typ_var(self, name, kind): diff --git a/python/tvm/relay/std/prelude.rly b/python/tvm/relay/std/prelude.rly index 702174892deb..a5c2c9f8a9cb 100644 --- a/python/tvm/relay/std/prelude.rly +++ b/python/tvm/relay/std/prelude.rly @@ -122,12 +122,12 @@ def @foldl[A, B](%f: fn(A, B) -> A, %acc: A, %xs: List[B]) -> A { /* * A right-way fold over a list. * - * `foldr(f, cons(a1, cons(a2, cons(..., cons(an, nil)))), z)` + * `foldr(f, z, cons(a1, cons(a2, cons(..., cons(an, nil)))))` * evaluates to `f(a1, f(a2, f(..., f(an, z)))...)`. */ -def @foldr[A, B](%f: fn(A, B) -> B, %xs: List[A], %acc: B) -> B { +def @foldr[A, B](%f: fn(A, B) -> B, %acc: B, %xs: List[A]) -> B { match (%xs) { - Cons(%x, %rest) => %f(%x, @foldr(%f, %rest, %acc)), + Cons(%x, %rest) => %f(%x, @foldr(%f, %acc, %rest)), Nil => %acc, } } @@ -218,7 +218,7 @@ def @map_accumr[A, B, C](%f: fn(A, B) -> (A, C), %init: A, %xs: List[B]) -> (A, let %f_out = %f(%acc.0, %x); (%f_out.0, Cons(%f_out.1, %acc.1)) }; - @foldr(%updater, %xs, (%init, Nil)) + @foldr(%updater, (%init, Nil), %xs) } /*