Handle FuncDef nodes

        :node: TODO
        :scope: TODO
        :ctxt: TODO
        :stream: TODO
        :returns: TODO
327600
def _handle_func_def(self, node, scope, ctxt, stream):
        
        self._dlog("handling function definition")
        func = self._handle_node(node.decl, scope, ctxt, stream)
        func.body = node.body
1226812
def decoratable_funcdef_stmt_handle(self, original, loc, tokens, is_async=False):
        """"""
        if len(tokens) == 1:
            decorators, funcdef = "", tokens[0]
        elif len(tokens) == 2:
            decorators, funcdef = tokens
        else:
            raise CoconutInternalException("invalid function definition tokens", tokens)

        # extract information about the function
        raw_lines = funcdef.splitlines(True)
        def_stmt = raw_lines.pop(0)
        func_name, func_args, func_params = None, None, None
        with self.complain_on_err():
            func_name, func_args, func_params = parse(self.split_func_name_args_params, def_stmt)

        undotted_name = None  # the function __name__ if func_name is a dotted name
        if func_name is not None:
            if "." in func_name:
                undotted_name = func_name.rsplit(".", 1)[-1]
                def_stmt = def_stmt.replace(func_name, undotted_name)

        # handle async functions
        if is_async:
            if not self.target:
                raise self.make_err(
                    CoconutTargetError,
                    "async function definition requires a specific target",
                    original, loc,
                    target="sys",
                )
            elif self.target_info >= (3, 5):
                def_stmt = "async " + def_stmt
            else:
                decorators += "@_coconut.asyncio.coroutine\n"

            # only Python 3.3+ supports returning values inside generators
            if self.target_info < (3, 3):
                func_code = self.transform_returns(raw_lines, is_async=True)
            else:
                func_code = "".join(raw_lines)

        # handle normal functions
        else:
            # tre does not work with decorators, though tco does
            attempt_tre = func_name is not None and not decorators
            if attempt_tre:
                use_mock = func_args and func_args != func_params[1:-1]
                func_store = tre_store_var + "_" + str(self.tre_store_count)
                self.tre_store_count += 1
                tre_return_grammar = self.tre_return(func_name, func_args, func_store, use_mock)
            else:
                use_mock = func_store = tre_return_grammar = None

            func_code, tco, tre = self.transform_returns(
                raw_lines,
                tre_return_grammar,
                use_mock,
            )

            if tre:
                comment, rest = split_leading_comment(func_code)
                indent, base, dedent = split_leading_trailing_indent(rest, 1)
                base, base_dedent = split_trailing_indent(base)
                docstring, base = self.split_docstring(base)
                func_code = (
                    comment + indent
                    + (docstring + "\n" if docstring is not None else "")
                    + (
                        "def " + tre_mock_var + func_params + ": return " + func_args + "\n"
                        if use_mock else ""
                    ) + "while True:\n"
                        + openindent + base + base_dedent
                        + ("\n" if "\n" not in base_dedent else "") + "return None"
                        + ("\n" if "\n" not in dedent else "") + closeindent + dedent
                    + func_store + " = " + (func_name if undotted_name is None else undotted_name) + "\n"
                )
            if tco:
                decorators += "@_coconut_tco\n"  # binds most tightly

        out = decorators + def_stmt + func_code
        if undotted_name is not None:
            out += func_name + " = " + undotted_name + "\n"
        return out
67865
def _handle_decl(self, node, scope, ctxt, stream):
        
        self._dlog("handling decl")

        metadata_processor = None
        if node.metadata is not None:
            #metadata_info = self._handle_metadata(node, scope, ctxt, stream)
            def process_metadata():
                metadata_info = self._handle_metadata(node, scope, ctxt, stream)
                return metadata_info
            metadata_processor = process_metadata

        field_name = self._get_node_name(node)
        field = self._handle_node(node.type, scope, ctxt, stream)
        bitsize = None
        bitfield_rw = None
        if getattr(node, "bitsize", None) is not None:
            bitsize = self._handle_node(node.bitsize, scope, ctxt, stream)
            has_prev = len(ctxt._pfp__children) > 0

            bitfield_rw = None
            if has_prev:
                prev = ctxt._pfp__children[-1]
                # if it was a bitfield as well
                # TODO I don't think this will handle multiple bitfield groups in a row.
                # E.g.
                #     char a: 8, b:8;
                #    char c: 8, d:8;
                if ((self._padded_bitfield and prev.__class__.width == field.width) or not self._padded_bitfield) \
                        and prev.bitsize is not None and prev.bitfield_rw.reserve_bits(bitsize, stream):
                    bitfield_rw = prev.bitfield_rw

            # either because there was no previous bitfield, or the previous was full
            if bitfield_rw is None:
                bitfield_rw = fields.BitfieldRW(self, field)
                bitfield_rw.reserve_bits(bitsize, stream)

        if getattr(node, "is_func_param", False):
            # we want to keep this as a class and not instantiate it
            # instantiation will be done in functions.ParamListDef.instantiate
            field = (field_name, field)
        
        # locals and consts still get a field instance, but DON'T parse the
        # stream!
        elif "local" in node.quals or "const" in node.quals:
            is_struct = issubclass(field, fields.Struct)
            if not isinstance(field, fields.Field) and not is_struct:
                field = field()
            scope.add_local(field_name, field)

            # this should only be able to be done with locals, right?
            # if not, move it to the bottom of the function
            if node.init is not None:
                val = self._handle_node(node.init, scope, ctxt, stream)
                if is_struct:
                    field = val
                    scope.add_local(field_name, field)
                else:
                    field._pfp__set_value(val)

            if "const" in node.quals:
                field._pfp__freeze()

            field._pfp__interp = self

        elif isinstance(field, functions.Function):
            # eh, just add it as a local...
            # maybe the whole local/vars thinking needs to change...
            # and we should only have ONE map TODO
            field.name = field_name
            scope.add_local(field_name, field)

        elif field_name is not None:
            added_child = False

    
            # by this point, structs are already instantiated (they need to be
            # in order to set the new context)
            if not isinstance(field, fields.Field):
                if issubclass(field, fields.NumberBase):
                    # use the default bitfield direction
                    if self._bitfield_direction is self.BITFIELD_DIR_DEFAULT:
                        bitfield_left_right = True if field.endian == fields.BIG_ENDIAN else False
                    else:
                        bitfield_left_right = (self._bitfield_direction is self.BITFIELD_DIR_LEFT_RIGHT)

                    field = field(
                        stream,
                        bitsize=bitsize,
                        metadata_processor=metadata_processor,
                        bitfield_rw=bitfield_rw,
                        bitfield_padded=self._padded_bitfield,
                        bitfield_left_right=bitfield_left_right
                    )

                # TODO
                # for now if there's a struct inside of a union that is being
                # parsed when there's an error, the user will lose information
                # about how far the parsing got. Here we are explicitly checking for
                # adding structs and unions to a parent union.
                elif (issubclass(field, fields.Struct) or issubclass(field, fields.Union)) \
                        and not isinstance(ctxt, fields.Union) \
                        and hasattr(field, "_pfp__init"):

                    # this is so that we can have all nested structs added to
                    # the root DOM, even if there's an error in parsing the data.
                    # If we didn't do this, any errors parsing the data would cause
                    # the new struct to not be added to its parent, and the user would
                    # not be able to see how far the script got
                    field = field(stream, metadata_processor=metadata_processor, do_init=False)
                    field._pfp__interp = self
                    field_res = ctxt._pfp__add_child(field_name, field, stream)

                    # when adding a new field to a struct/union/fileast, add it to the
                    # root of the ctxt's scope so that it doesn't get lost by being declared
                    # from within a function
                    scope.add_var(field_name, field_res, root=True)

                    field_res._pfp__interp = self
                    field._pfp__init(stream)
                    added_child = True
                else:
                    field = field(stream, metadata_processor=metadata_processor)

            if not added_child:
                field._pfp__interp = self
                field_res = ctxt._pfp__add_child(field_name, field, stream)
                field_res._pfp__interp = self

                # when adding a new field to a struct/union/fileast, add it to the
                # root of the ctxt's scope so that it doesn't get lost by being declared
                # from within a function
                scope.add_var(field_name, field_res, root=True)

                # this shouldn't be used elsewhere, but should still be explicit with
                # this flag
                added_child = True

        # enums will get here. If there is no name, then no
        # field is being declared (but the enum values _will_
        # get defined). E.g.:
        #     enum <uchar blah {
        #         BLAH1,
        #        BLAH2,
        #        BLAH3
        #     };
        elif field_name is None:
            pass

        return field
427266
def _handle_node(self, node, scope=None, ctxt=None, stream=None):
        
        if scope is None:
            if self._scope is None:
                self._scope = scope = self._create_scope()
            else:
                scope = self._scope

        if ctxt is None and self._ctxt is not None:
            ctxt = self._ctxt
        else:
            self._ctxt = ctxt

        if type(node) is tuple:
            node = node[1]

        # TODO probably a better way to do this...
        # this occurs with if-statements that have a single statement
        # instead of a compound statement (no curly braces)
        elif type(node) is list and len(list(filter(lambda x: isinstance(x, AST.Node), node))) == len(node):
            node = AST.Compound(
                block_items=node,
                coord=node[0].coord
            )
            return self._handle_node(node, scope, ctxt, stream)

        # need to check this so that debugger-eval'd statements
        # don't mess with the current state
        if not self._no_debug:
            self._coord = node.coord

        self._dlog("handling node type {}, line {}".format(node.__class__.__name__, node.coord.line if node.coord is not None else "?"))
        self._log.inc()

        breakable = self._node_is_breakable(node)

        if breakable and not self._no_debug and self._break_type != self.BREAK_NONE:
            # always break
            if self._break_type == self.BREAK_INTO:
                self._break_level = self._scope.level()
                self.debugger.cmdloop()

            # level <= _break_level
            elif self._break_type == self.BREAK_OVER:
                if self._scope.level() <= self._break_level:
                    self._break_level = self._scope.level()
                    self.debugger.cmdloop()
                else:
                    pass

        if node.__class__ not in self._node_switch:
            raise errors.UnsupportedASTNode(node.coord, node.__class__.__name__)

        res = self._node_switch[node.__class__](node, scope, ctxt, stream)

        self._log.dec()

        return res
797171
function processFunction(funcNode) {
            const node = isEmbedded(funcNode) ? funcNode.parent : funcNode;

            if (!IIFEs && isIIFE(node)) {
                return;
            }
            let lineCount = 0;

            for (let i = node.loc.start.line - 1; i < node.loc.end.line; ++i) {
                const line = lines[i];

                if (skipComments) {
                    if (commentLineNumbers.has(i + 1) && isFullLineComment(line, i + 1, commentLineNumbers.get(i + 1))) {
                        continue;
                    }
                }

                if (skipBlankLines) {
                    if (line.match(/^\s*$/u)) {
                        continue;
                    }
                }

                lineCount++;
            }

            if (lineCount > maxLines) {
                const name = astUtils.getFunctionNameWithKind(funcNode);

                context.report({
                    node,
                    messageId: "exceed",
                    data: { name, lineCount, maxLines }
                });
            }
        }
1266216
def nodes_callback(self, data):
        
        for node_id, tags, coords in data:
            # Discard the coords because they go into add_coords
            self.nodes[node_id] = tags
878092
function handleFunction (node, options) {
  const args = handleExprList(node.args, options)
  return `${node.name}${args}`
}
447454
def CLASSDEF(self, node):
        
        for deco in node.decorator_list:
            self.handleNode(deco, node)
        for baseNode in node.bases:
            self.handleNode(baseNode, node)
        if not PY2:
            for keywordNode in node.keywords:
                self.handleNode(keywordNode, node)
        self.pushScope(ClassScope)
        # doctest does not process doctest within a doctest
        # classes within classes are processed.
        if (self.withDoctest and
                not self._in_doctest() and
                not isinstance(self.scope, FunctionScope)):
            self.deferFunction(lambda: self.handleDoctests(node))
        for stmt in node.body:
            self.handleNode(stmt, node)
        self.popScope()
        self.addBinding(node, ClassDefinition(node.name, node))
1083131
def parse_Element(self, node):
        
        name = node.tagName
        ignores = self.ignores
        if name in ignores:
            return
        attr = "do_%s" % name
        if hasattr(self, attr):
            handlerMethod = getattr(self, attr)
            handlerMethod(node)
        else:
            self.generic_parse(node)
677685
def on_sclass(node)
      parent       = node.children[0]
      definition   = evaluate_node(parent)
      @method_type = definition.method_call_type

      associate_node(node, definition)

      push_scope(definition)
    end
544315
def _handle_file_ast(self, node, scope, ctxt, stream):
        
        self._root = ctxt = fields.Dom(stream)
        ctxt._pfp__scope = scope
        self._root._pfp__name = "__root"
        self._root._pfp__interp = self
        self._dlog("handling file AST with {} children".format(len(node.children())))

        for child in node.children():
            self._handle_node(child, scope, ctxt, stream)

        ctxt._pfp__process_fields_metadata()

        return ctxt
33893
def _handle_exists(self, node, scope, ctxt, stream):
        
        res = fields.Int()
        try:
            self._handle_node(node.expr, scope, ctxt, stream)
            res._pfp__set_value(1)
        except AttributeError:
            res._pfp__set_value(0)
        return res
917816
def visit_Call(self, node: AST, dfltChaining: bool = True) -> str:
        """"""
        args = node.args
        try:
            kwds = node.keywords
        except AttributeError:
            kwds = []
        self.compact = True
        args_src = (self.visit(arg) for arg in args)
        kwds_src = (self.visit(kwd) for kwd in kwds)
        param_src = ', '.join(chain(args_src, kwds_src))
        src = f"{self.visit(node.func)}({param_src})"
        self.compact = False
        return src
1363687
def expr(self, callback):
        
        nodes = []
        for node in self.nodes:
            if callback(node):
                nodes.append(node)
        self.nodes = nodes
        return self
255208
def on_def(node)
      receiver = nil

      if node.type == :defs
        receiver = evaluate_node(node.children[0])
      end

      builder = DefinitionBuilder::RubyMethod.new(
        node,
        self,
        :type       => @method_type,
        :receiver   => receiver,
        :visibility => @visibility
      )

      definition = builder.build

      builder.scope.add_definition(definition)

      associate_node(node, definition)

      buffer_docstring_tags(node)

      if docstring_tags and docstring_tags.return_tag
        assign_return_value_from_tag(
          docstring_tags.return_tag,
          definition
        )
      end

      push_scope(definition)
    end
1137178
def visit_FunctionDef(self, node):
        
        # Ensure there are no nested functions.
        assert self.current_function is None
        self.current_function = node
        self.naming = dict()
        self.in_cond = False  # True when we are in a if, while or for
        self.generic_visit(node)
        self.current_function = None
665380
function handleFunction(fn, scope, thisVal) {
  var localScope = fn.node && fn.node.getAnnotation("scope") ? fn.node.getAnnotation("scope") : new Scope(scope);
  localScope.declare('__return');
  if(fn.node) {
    fn.node.setAnnotation("scope", localScope);
    fn.node.rewrite('Function(name, fargs, body)', function(b) {
      b.fargs.forEach(function(farg) {
        localScope.declare(farg.value);
        localScope.hint(farg.value, new Value());
      });
      localScope.declare('__this');
      localScope.hint('__this', thisVal);
      inferAllTypes(localScope, b.body);
      return this;
    });
  } else if(fn.returnValue) {
    localScope.hint('__return', fn.returnValue);
  }
  return localScope;
}