Commit 2dac17d8 by Logan Weber Committed by Jared Roesch

[Relay] Move prelude to text format (#3939)

* Fix parser

* Doc fix

* Add module utility functions necessary for prelude

* Implement prelude in text format

* Remove programmatically constructed prelude defs

* Fix 0-arity type conses in pretty printer and test

* Make prelude loading backwards-compatible

* Fix patterns

* Improve some prelude defs

* Fix `ImportFromStd`

It needs to also follow the "add unchecked, add checked" pattern

* Lint roller

* Woops

* Address feedback

* Fix `test_list_constructor` VM test

* Fix `test_adt.py` failures
parent 9b46ace1
......@@ -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
......
......@@ -117,7 +117,8 @@ class ExprFunctor<R(const Expr& n, Args...)> {
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:
......
......@@ -88,20 +88,33 @@ class ModuleNode : public RelayNode {
TVM_DLL void Add(const GlobalVar& var, const Function& func, bool update = false);
/*!
* \brief Add a function to the global environment.
* \param var The name of the global function.
* \param func The function.
*
* It does not do type inference as Add does.
*/
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 type The ADT.
* \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.
* \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.
*
* It does not do type inference as Add does.
* It does not do type inference as AddDef does.
*/
TVM_DLL void AddUnchecked(const GlobalVar& var, const Function& func);
TVM_DLL void AddDefUnchecked(const GlobalTypeVar& var, const TypeData& type, bool update = false);
/*!
* \brief Update a function in the global environment.
......@@ -111,6 +124,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 type The new ADT.
*/
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.
*/
......@@ -131,6 +151,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<GlobalVar> GetGlobalVars() const;
/*!
* \brief Look up a global function by its name.
* \param str The unique string specifying the global variable.
* \returns The global variable.
......@@ -138,6 +164,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<GlobalTypeVar> GetGlobalTypeVars() const;
/*!
* \brief Look up a global function by its variable.
* \param var The global var to lookup.
* \returns The function named by the variable argument.
......
......@@ -103,7 +103,8 @@ class PatternFunctor<R(const Pattern& n, Args...)> {
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:
......
......@@ -231,7 +231,7 @@ class ParseTreeToRelayIR(RelayVisitor):
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):
......@@ -242,7 +242,7 @@ class ParseTreeToRelayIR(RelayVisitor):
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 @@ class ParseTreeToRelayIR(RelayVisitor):
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 not type_expr.inputs:
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 @@ class ParseTreeToRelayIR(RelayVisitor):
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
......@@ -361,6 +363,10 @@ class ParseTreeToRelayIR(RelayVisitor):
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 @@ class ParseTreeToRelayIR(RelayVisitor):
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 @@ class ParseTreeToRelayIR(RelayVisitor):
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 @@ class ParseTreeToRelayIR(RelayVisitor):
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 @@ class ParseTreeToRelayIR(RelayVisitor):
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:
......@@ -562,39 +567,36 @@ class ParseTreeToRelayIR(RelayVisitor):
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()
# 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,
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):
text = ctx.getText()
if text == "_":
return adt.PatternWildcard()
elif text.startswith("%"):
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 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)
......@@ -610,16 +612,14 @@ class ParseTreeToRelayIR(RelayVisitor):
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 +634,7 @@ class ParseTreeToRelayIR(RelayVisitor):
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 +654,24 @@ class ParseTreeToRelayIR(RelayVisitor):
# 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 +684,10 @@ class ParseTreeToRelayIR(RelayVisitor):
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 +695,7 @@ class ParseTreeToRelayIR(RelayVisitor):
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 +730,7 @@ class StrictErrorListener(ErrorListener):
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.")
......
......@@ -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,14 +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)?
: '_' # wildcardPattern
| localVar (':' typeExpr)? # varPattern
| constructorName patternList? # constructorPattern
| patternList # tuplePattern
;
adtCons: constructorName adtConsParamList? ;
......@@ -155,6 +157,7 @@ attr: CNAME '=' expr ;
typeExpr
: '(' ')' # tupleType
| '(' typeExpr ')' # typeParen
| '(' typeExpr ',' ')' # tupleType
| '(' typeExpr (',' typeExpr)+ ')' # tupleType
| generalIdent typeParamList # typeCallType
......@@ -164,7 +167,7 @@ typeExpr
| '_' # incompleteType
;
typeParamList: '[' generalIdent (',' generalIdent)* ']' ;
typeParamList: '[' typeExpr (',' typeExpr)* ']' ;
shapeList
: '(' ')'
......
......@@ -9,7 +9,7 @@ import sys
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("\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,238 +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\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("\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\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\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("\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("\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("\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\u0156\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("\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("\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()
......@@ -1180,7 +1183,7 @@ class RelayParser ( Parser ):
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:
......@@ -1321,22 +1324,18 @@ class RelayParser ( Parser ):
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
......@@ -1344,17 +1343,17 @@ class RelayParser ( Parser ):
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
......@@ -1362,15 +1361,15 @@ class RelayParser ( Parser ):
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
......@@ -1378,7 +1377,7 @@ class RelayParser ( Parser ):
localctx = RelayParser.IdentExprContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
self.state = 190
self.state = 188
self.ident()
pass
......@@ -1386,7 +1385,7 @@ class RelayParser ( Parser ):
localctx = RelayParser.ScalarExprContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
self.state = 191
self.state = 189
self.scalar()
pass
......@@ -1394,7 +1393,7 @@ class RelayParser ( Parser ):
localctx = RelayParser.MetaExprContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
self.state = 192
self.state = 190
self.meta()
pass
......@@ -1402,13 +1401,13 @@ class RelayParser ( Parser ):
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:
......@@ -1416,17 +1415,17 @@ class RelayParser ( Parser ):
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):
......@@ -1434,18 +1433,18 @@ class RelayParser ( Parser ):
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):
......@@ -1453,18 +1452,18 @@ class RelayParser ( Parser ):
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)):
......@@ -1472,18 +1471,18 @@ class RelayParser ( Parser ):
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):
......@@ -1491,53 +1490,53 @@ class RelayParser ( Parser ):
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)
......@@ -1591,33 +1590,33 @@ class RelayParser ( Parser ):
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
......@@ -1723,57 +1722,57 @@ class RelayParser ( Parser ):
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()
......@@ -1781,29 +1780,29 @@ class RelayParser ( Parser ):
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:
......@@ -1845,7 +1844,7 @@ class RelayParser ( Parser ):
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
......@@ -1888,26 +1887,26 @@ class RelayParser ( Parser ):
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)
......@@ -1956,29 +1955,29 @@ class RelayParser ( Parser ):
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)
......@@ -2023,26 +2022,26 @@ class RelayParser ( Parser ):
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)
......@@ -2061,18 +2060,14 @@ class RelayParser ( Parser ):
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
......@@ -2089,34 +2084,25 @@ class RelayParser ( Parser ):
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:
......@@ -2157,7 +2143,7 @@ class RelayParser ( Parser ):
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)
......@@ -2205,23 +2191,23 @@ class RelayParser ( Parser ):
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
......@@ -2238,26 +2224,88 @@ class RelayParser ( Parser ):
super().__init__(parent, invokingState)
self.parser = parser
def getRuleIndex(self):
return RelayParser.RULE_pattern
def copyFrom(self, ctx:ParserRuleContext):
super().copyFrom(ctx)
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 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, "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 getRuleIndex(self):
return RelayParser.RULE_pattern
def accept(self, visitor:ParseTreeVisitor):
if hasattr( visitor, "visitPattern" ):
return visitor.visitPattern(self)
if hasattr( visitor, "visitVarPattern" ):
return visitor.visitVarPattern(self)
else:
return visitor.visitChildren(self)
def pattern(self):
localctx = RelayParser.PatternContext(self, self._ctx, self.state)
......@@ -2268,25 +2316,47 @@ class RelayParser ( Parser ):
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 = 334
self.constructorName()
self.state = 336
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==RelayParser.T__5:
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)
......@@ -2800,6 +2870,23 @@ class RelayParser ( Parser ):
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,7 +3008,7 @@ class RelayParser ( Parser ):
self.enterRule(localctx, 52, self.RULE_typeExpr)
self._la = 0 # Token type
try:
self.state = 446
self.state = 450
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,47,self._ctx)
if la_ == 1:
......@@ -2934,123 +3021,134 @@ class RelayParser ( Parser ):
pass
elif la_ == 2:
localctx = RelayParser.TupleTypeContext(self, localctx)
localctx = RelayParser.TypeParenContext(self, localctx)
self.enterOuterAlt(localctx, 2)
self.state = 401
self.match(RelayParser.T__5)
self.state = 402
self.typeExpr()
self.state = 403
self.match(RelayParser.T__4)
self.state = 404
self.match(RelayParser.T__6)
pass
elif la_ == 3:
localctx = RelayParser.TupleTypeContext(self, localctx)
self.enterOuterAlt(localctx, 3)
self.state = 406
self.state = 405
self.match(RelayParser.T__5)
self.state = 406
self.typeExpr()
self.state = 407
self.match(RelayParser.T__4)
self.state = 408
self.match(RelayParser.T__6)
pass
elif la_ == 4:
localctx = RelayParser.TupleTypeContext(self, localctx)
self.enterOuterAlt(localctx, 4)
self.state = 410
self.match(RelayParser.T__5)
self.state = 411
self.typeExpr()
self.state = 410
self.state = 414
self._errHandler.sync(self)
_la = self._input.LA(1)
while True:
self.state = 408
self.state = 412
self.match(RelayParser.T__4)
self.state = 409
self.state = 413
self.typeExpr()
self.state = 412
self.state = 416
self._errHandler.sync(self)
_la = self._input.LA(1)
if not (_la==RelayParser.T__4):
break
self.state = 414
self.state = 418
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 = 420
self.generalIdent()
self.state = 417
self.state = 421
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 = 423
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 = 424
self.match(RelayParser.T__26)
self.state = 421
self.state = 425
self.match(RelayParser.T__7)
self.state = 422
self.state = 426
self.shapeList()
self.state = 423
self.state = 427
self.match(RelayParser.T__4)
self.state = 424
self.state = 428
self.typeExpr()
self.state = 425
self.state = 429
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 = 431
self.match(RelayParser.T__17)
self.state = 429
self.state = 433
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==RelayParser.T__7:
self.state = 428
self.state = 432
self.typeParamList()
self.state = 431
self.state = 435
self.match(RelayParser.T__5)
self.state = 440
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 = 432
self.state = 436
self.typeExpr()
self.state = 437
self.state = 441
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==RelayParser.T__4:
self.state = 433
self.state = 437
self.match(RelayParser.T__4)
self.state = 434
self.state = 438
self.typeExpr()
self.state = 439
self.state = 443
self._errHandler.sync(self)
_la = self._input.LA(1)
self.state = 442
self.state = 446
self.match(RelayParser.T__6)
self.state = 443
self.state = 447
self.match(RelayParser.T__18)
self.state = 444
self.state = 448
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 = 449
self.match(RelayParser.T__3)
pass
......@@ -3070,11 +3168,11 @@ class RelayParser ( Parser ):
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 +3194,23 @@ class RelayParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
self.state = 448
self.state = 452
self.match(RelayParser.T__7)
self.state = 449
self.generalIdent()
self.state = 454
self.state = 453
self.typeExpr()
self.state = 458
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==RelayParser.T__4:
self.state = 450
self.state = 454
self.match(RelayParser.T__4)
self.state = 451
self.generalIdent()
self.state = 456
self.state = 455
self.typeExpr()
self.state = 460
self._errHandler.sync(self)
_la = self._input.LA(1)
self.state = 457
self.state = 461
self.match(RelayParser.T__8)
except RecognitionException as re:
localctx.exception = re
......@@ -3154,44 +3252,44 @@ class RelayParser ( Parser ):
self.enterRule(localctx, 56, self.RULE_shapeList)
self._la = 0 # Token type
try:
self.state = 472
self.state = 476
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,50,self._ctx)
if la_ == 1:
self.enterOuterAlt(localctx, 1)
self.state = 459
self.state = 463
self.match(RelayParser.T__5)
self.state = 460
self.state = 464
self.match(RelayParser.T__6)
pass
elif la_ == 2:
self.enterOuterAlt(localctx, 2)
self.state = 461
self.state = 465
self.match(RelayParser.T__5)
self.state = 462
self.state = 466
self.shape()
self.state = 465
self.state = 469
self._errHandler.sync(self)
_la = self._input.LA(1)
while True:
self.state = 463
self.state = 467
self.match(RelayParser.T__4)
self.state = 464
self.state = 468
self.shape()
self.state = 467
self.state = 471
self._errHandler.sync(self)
_la = self._input.LA(1)
if not (_la==RelayParser.T__4):
break
self.state = 469
self.state = 473
self.match(RelayParser.T__6)
pass
elif la_ == 3:
self.enterOuterAlt(localctx, 3)
self.state = 471
self.state = 475
self.shape()
pass
......@@ -3235,19 +3333,19 @@ class RelayParser ( Parser ):
self.enterRule(localctx, 58, self.RULE_meta)
try:
self.enterOuterAlt(localctx, 1)
self.state = 474
self.state = 478
self.match(RelayParser.T__27)
self.state = 475
self.state = 479
self.match(RelayParser.T__7)
self.state = 476
self.state = 480
self.match(RelayParser.CNAME)
self.state = 477
self.state = 481
self.match(RelayParser.T__8)
self.state = 478
self.state = 482
self.match(RelayParser.T__7)
self.state = 479
self.state = 483
self.match(RelayParser.NAT)
self.state = 480
self.state = 484
self.match(RelayParser.T__8)
except RecognitionException as re:
localctx.exception = re
......@@ -3330,29 +3428,29 @@ class RelayParser ( Parser ):
localctx = RelayParser.ShapeContext(self, self._ctx, self.state)
self.enterRule(localctx, 60, self.RULE_shape)
try:
self.state = 488
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 = 482
self.state = 486
self.meta()
pass
elif token in [RelayParser.T__5]:
localctx = RelayParser.ParensShapeContext(self, localctx)
self.enterOuterAlt(localctx, 2)
self.state = 483
self.state = 487
self.match(RelayParser.T__5)
self.state = 484
self.state = 488
self.shape()
self.state = 485
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 = 487
self.state = 491
self.match(RelayParser.NAT)
pass
else:
......@@ -3395,11 +3493,11 @@ class RelayParser ( Parser ):
self.enterRule(localctx, 62, self.RULE_body)
try:
self.enterOuterAlt(localctx, 1)
self.state = 490
self.state = 494
self.match(RelayParser.T__11)
self.state = 491
self.state = 495
self.expr(0)
self.state = 492
self.state = 496
self.match(RelayParser.T__12)
except RecognitionException as re:
localctx.exception = re
......@@ -3480,25 +3578,25 @@ class RelayParser ( Parser ):
localctx = RelayParser.ScalarContext(self, self._ctx, self.state)
self.enterRule(localctx, 64, self.RULE_scalar)
try:
self.state = 497
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 = 494
self.state = 498
self.match(RelayParser.FLOAT)
pass
elif token in [RelayParser.NAT]:
localctx = RelayParser.ScalarIntContext(self, localctx)
self.enterOuterAlt(localctx, 2)
self.state = 495
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 = 496
self.state = 500
self.match(RelayParser.BOOL_LIT)
pass
else:
......@@ -3552,30 +3650,30 @@ class RelayParser ( Parser ):
localctx = RelayParser.IdentContext(self, self._ctx, self.state)
self.enterRule(localctx, 66, self.RULE_ident)
try:
self.state = 503
self.state = 507
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,53,self._ctx)
if la_ == 1:
self.enterOuterAlt(localctx, 1)
self.state = 499
self.state = 503
self.generalIdent()
pass
elif la_ == 2:
self.enterOuterAlt(localctx, 2)
self.state = 500
self.state = 504
self.globalVar()
pass
elif la_ == 3:
self.enterOuterAlt(localctx, 3)
self.state = 501
self.state = 505
self.localVar()
pass
elif la_ == 4:
self.enterOuterAlt(localctx, 4)
self.state = 502
self.state = 506
self.graphVar()
pass
......
......@@ -184,8 +184,23 @@ class RelayVisitor(ParseTreeVisitor):
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)
......@@ -239,6 +254,11 @@ class RelayVisitor(ParseTreeVisitor):
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)
......
......@@ -96,7 +96,7 @@ class Module(RelayNode):
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 @@ class Module(RelayNode):
"""
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.
......
......@@ -16,502 +16,61 @@
# 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:
"""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<a, b>(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<a, b>(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<a, b>(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<a>(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<a>(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<a>(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<a, b>(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<a>(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<a, b, c>(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<a, b, c>(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<a, b>(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<a, b>(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<a, b>(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<a>(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<a>(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 load_prelude(self):
"""
Parses the portions of the Prelude written in Relay's text format and adds
them to the 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()
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()
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.define_iterate()
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 = [
"id",
"compose",
"flip",
"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))
......@@ -18,12 +18,299 @@
*/
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))
}
}
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)`.
*/
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))
}
}
/*
* 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,
}
}
def @compose[a, b, c](%f: fn(b) -> c, %g: fn(a) -> b) {
fn (%x: a) -> c {
%f(%g(%x))
}
/*
* A right-way fold over a list.
*
* `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, %acc: B, %xs: List[A]) -> B {
match (%xs) {
Cons(%x, %rest) => %f(%x, @foldr(%f, %acc, %rest)),
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] {
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)
}
/*
* 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, %ys) {
(Cons(%x, %x_rest), Cons(%y, %y_rest)) => Cons((%x, %y), @zip(%x_rest, %y_rest)),
_ => Nil,
}
}
/*
* Reverses a list.
*/
def @rev[A](%xs: List[A]) -> List[A] {
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)
}
/*
* 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, (%init, 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 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] {
@rev(@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))
}
}
......@@ -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
......
......@@ -46,14 +46,14 @@ Module ModuleNode::make(tvm::Map<GlobalVar, Function> 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);
......@@ -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<Module>(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<GlobalVar> ModuleNode::GetGlobalVars() const {
std::vector<GlobalVar> 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<GlobalVar>(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<GlobalTypeVar> ModuleNode::GetGlobalTypeVars() const {
std::vector<GlobalTypeVar> global_type_vars;
for (const auto& pair : global_type_var_map_) {
global_type_vars.push_back(pair.second);
}
return tvm::Array<GlobalTypeVar>(global_type_vars);
}
template<typename T>
tvm::Array<T> concat(const tvm::Array<T>& l, const tvm::Array<T>& r) {
tvm::Array<T> 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<Module>(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) == 0)
<< "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,25 +179,33 @@ void ModuleNode::RegisterConstructors(const GlobalTypeVar& var, const TypeData&
}
}
void ModuleNode::AddDef(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::AddDef(const GlobalTypeVar& var, const TypeData& type, bool update) {
AddDefUnchecked(var, type, update);
// need to kind check at the end because the check can look up
// a definition potentially
CHECK(KindCheck(type, GetRef<Module>(this)) == Kind::kTypeData)
<< "Invalid or malformed typedata given to module: " << type;
}
void ModuleNode::AddDefUnchecked(const GlobalTypeVar& var, const TypeData& type, bool update) {
this->type_definitions.Set(var, type);
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);
}
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,9 +250,20 @@ Constructor ModuleNode::LookupTag(const int32_t tag) {
}
void ModuleNode::Update(const Module& mod) {
// 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(
......@@ -257,14 +292,7 @@ void ModuleNode::Import(const std::string& path) {
std::istreambuf_iterator<char>(src_file),
std::istreambuf_iterator<char>() };
auto mod_to_import = FromText(file_contents, path);
for (auto func : mod_to_import->functions) {
this->Add(func.first, func.second, false);
}
for (auto type : mod_to_import->type_definitions) {
this->AddDef(type.first, type.second);
}
Update(mod_to_import);
}
}
......@@ -315,6 +343,12 @@ TVM_REGISTER_API("relay._module.Module_AddDef")
TVM_REGISTER_API("relay._module.Module_GetGlobalVar")
.set_body_method<Module>(&ModuleNode::GetGlobalVar);
TVM_REGISTER_API("relay._module.Module_GetGlobalVars")
.set_body_method<Module>(&ModuleNode::GetGlobalVars);
TVM_REGISTER_API("relay._module.Module_GetGlobalTypeVars")
.set_body_method<Module>(&ModuleNode::GetGlobalTypeVars);
TVM_REGISTER_API("relay._module.Module_ContainGlobalVar")
.set_body_method<Module>(&ModuleNode::ContainGlobalVar);
......
......@@ -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 {
......@@ -641,6 +647,17 @@ class PrettyPrinter :
return doc;
}
Doc VisitPattern_(const PatternTupleNode* pt) final {
Doc doc;
doc << "(";
std::vector<Doc> 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("_");
}
......
......@@ -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(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment