def evaluateFunctionDeclaration(node, sphinxContext, args):
    overriddenVariables = {}

    if isinstance(args, dict):
        # args may not all be used in the function declaration, just want used ones
        argDict = dict((name, value)
                       for name, value in args.items()
                       if name in node.params)
    else:  # purely positional args      
        # positional parameters named according to function prototype
        if len(args) != len(node.params):
            sphinxContext.modelXbrl.log("ERROR", "sphinx.functionArgumentsMismatch",
                                        _("Function %(name)s requires %(required)s parameters but %(provided)s are provided"),
                                        sourceFileLine=node.sourceFileLine,
                                        name=node.name, required=len(node.params), provided=len(args))
            return None
        argDict = dict((paramName, args[i])
                       for i, paramName in enumerate(node.params))
    for name, value in argDict.items():
        if name in sphinxContext.localVariables:
            overriddenVariables[name] = sphinxContext.localVariables[name]
        sphinxContext.localVariables[name] = value
    
    def clearFunctionArgs():
        for name in argDict.keys():
            del sphinxContext.localVariables[name]
        sphinxContext.localVariables.update(overriddenVariables)
        overriddenVariables.clear()

    try:
        result = evaluate(node.expr, sphinxContext)
        clearFunctionArgs()
        return result
    except __HOLE__ as ex:
        clearFunctionArgs()
        raise ex  # reraise exception
dataset/ETHPy150Open Arelle/Arelle/arelle/plugin/sphinx/SphinxEvaluator.py/evaluateFunctionDeclaration