def construction_rename(node, scope, fname=None, index=None, depth=0): # NOTE to self: the depth parameter here is used exclusively to give nested # patterns distinguishable parameter names. if node.constructor not in scope: raise FunkyRenamingError("Constructor '{}' not " \ "defined.".format(node.constructor)) elif scope[node.constructor]["arity"] != len(node.parameters): raise FunkyRenamingError("Expected {} parameters for constructor " \ "'{}'.".format(scope[node.constructor], node.constructor)) localizer = get_parameter_name(fname, index, depth) for i, param in enumerate(node.parameters): if isinstance(param, Parameter): rename(param, scope, fname=node.constructor, index=i, localizer=localizer) elif isinstance(param, Construction): rename(param, scope, fname=node.constructor, index=i, depth=depth + 1) else: rename(param, scope)
def function_definition_rename(node, scope): if node.lhs.identifier in BUILTIN_FUNCTIONS: raise FunkyRenamingError( "Cannot redefine builtin function '{}'.".format( node.lhs.identifier)) if node.lhs.identifier not in scope.local: if scope.is_pending_definition(node.lhs.identifier): newid = scope.get_pending_name(node.lhs.identifier) if node.lhs.identifier in scope.pending_definition: del scope.pending_definition[node.lhs.identifier] else: newid = get_unique_varname() scope[node.lhs.identifier] = { "id": newid, "arity": len(node.lhs.parameters) } tmp_scope = Scope(parent=scope) rename(node.lhs, tmp_scope) node.lhs.identifier = scope[node.lhs.identifier]["id"] tmp_scope2 = Scope(parent=tmp_scope) rename(node.rhs, tmp_scope2) scope.pending_definition.update(tmp_scope.pending_definition) scope.pending_definition.update(tmp_scope2.pending_definition)
def new_cons_statement_rename(node, scope): if node.identifier in scope: raise FunkyRenamingError("Duplicate definition of constructor type " \ "'{}'.".format(node.identifier)) elif node.identifier in BUILTIN_PRIMITIVES: raise FunkyRenamingError("Cannot define type with builtin name " \ "'{}'.".format(node.identifier)) # we don't rename the type, only the variables scope[node.identifier] = node.identifier tmp_scope_1 = Scope(parent=scope) for i, param in enumerate(node.type_parameters): tmp_scope_1[param] = get_parameter_name(node.identifier, i) tmp_scope_2 = Scope(parent=tmp_scope_1) for cons in node.constructors: rename(cons, tmp_scope_2) scope.local.update(tmp_scope_2.local)
def function_lhs_rename(node, scope): if scope[node.identifier]["arity"] != len(node.parameters): raise FunkyRenamingError("Definition of '{}' has different " \ "number of parameters than previous " \ "definition.".format(node.identifier)) for i, param in enumerate(node.parameters): if isinstance(param, Parameter) or isinstance(param, Construction): rename(param, scope, fname=scope[node.identifier]["id"], index=i) else: rename(param, scope)
def pattern_definition_rename(node, scope): if node.variable.name in BUILTIN_FUNCTIONS: raise FunkyRenamingError( "Cannot redefine built-in function '{}'.".format( node.variable.name)) rename(node.variable, scope, is_main=isinstance(node.variable, Parameter) and \ node.variable.name == "main") tmp_scope = Scope(parent=scope) rename(node.expression, tmp_scope) scope.pending_definition.update(tmp_scope.pending_definition)
def constructor_type_rename(node, scope): # anything goes for the node's identifier itself -- however, the types # beneath it must be valid. if node.identifier in scope: raise FunkyRenamingError("Duplicate usage of constructor " \ "'{}'.".format(node.identifier)) scope[node.identifier] = { "id": node.identifier, "arity": len(node.parameters), } for i, param in enumerate(node.parameters): if isinstance(node, Parameter): rename(param, scope, fname=node.identifier, index=i) else: rename(param, scope)
def parameter_rename(node, scope, fname=None, index=None, localizer=None, is_main=False): if node.name == "_": return if node.name in scope.local: raise FunkyRenamingError("Duplicate definition of parameter " \ "'{}'.".format(node.name)) if is_main: newid = MAIN elif scope.is_pending_definition(node.name): newid = scope.get_pending_name(node.name) if node.name in scope.pending_definition: del scope.pending_definition[node.name] else: newid = get_parameter_name(fname, localizer, index) if fname or index or \ localizer \ else get_unique_varname() scope[node.name] = newid node.name = newid
def check_scope_for_errors(scope): err_msg = "\n".join("Referenced item '{}' was never defined.".format(ident) for ident in scope.pending_definition) if err_msg: raise FunkyRenamingError(err_msg)
def type_rename(node, scope): if node.type_name not in scope and node.type_name not in BUILTIN_PRIMITIVES: raise FunkyRenamingError("Undefined type '{}'.".format(node.type_name))