g | x | w | all
Bytes Lang Time Link
082Python 3250328T092904Zsmots-18
001Unary141217T222904ZOptimize
026Common Lisp 23141217T214602Zcoredump

Python 3, 82 AST stmt./expr. tokens

from ast import parse, stmt, expr, iter_child_nodes
def f(node, node_list=[]):
    # node: str | AST
    # node_list: list[AST] = []
    # # Just uncomment this whole section to get normal code I guess
    # # Did you know: I can't have a docstring because that costs 1 node
    # if isinstance(node, AST):
    #     # Undefined behaviour here
    #     # (I exploit that this doesn't change node to save bytes)
    #     parsed_node = parse(node)
    # else:
    #     # Just a string
    #     parsed_node = parse(node)
    # for child in iter_child_nodes(parsed_node):
    # # So basically, just this:
    for child in iter_child_nodes(parse(node)):
        # Add this child (in place)
        node_list+=child,
        # Add the recursive-children of this child
        # (ignore return value here)
        f(child,node_list)
    # Return sum of
    return sum(
        # Amount of fields
        len(n._fields)
        # per every node in node_list
        for n in node_list
        # that is either a statement or an expression
        if isinstance(n,(stmt,expr))
    )

Try it online!


It feels really weird to not be golfing...
Unfortunately, only usable once (as node_list=[] is initialised but never reset on future calls)

f(node) takes in anything acceptable to ast.parse (e.g. string of Python code) and returns the number of statement/expression fields in it. f(node,[<stuff>, ...]) recursively appends all children of the given node to the given list, then gets the number of stmt/expr fields for EACH node.

Tried to keep it as close to the spirit as possible while remaining 'official' (That's really subjective anyways.) Strange details resulting from this include (iirc) a having 3 tokens but import antigravity having only 1 token.

Uses a technically undefined implementation detail whereby ast.parse uses compile(), but only the latter "officially" supports ast.Module types. Don't be surprised if this breaks on newer Python versions or specific implementations


Without most comments (but still readable):

from ast import parse, stmt, expr, iter_child_nodes
def f(node, node_list=[]):
    # node: str | AST
    # node_list: list[AST] = []
    for child in iter_child_nodes(parse(node)):
        node_list+=child,
        f(child,node_list)
    return sum(
        len(n._fields)
        for n in node_list
        if isinstance(n,(stmt,expr))
    )

Unary, 1

The program is a string of 47297560408284 zeroes

i.e.

000000000000000000000000000000000000000000.... 47297560408284 times

A brainfuck quivalent code would be

+[>+<+++++]>--.

which just prints 1

as in unary, the whole program is made up of just 0 which are all a single token.

Common Lisp - 23 26

Here is the example answer:

(labels ((sum (s form)
           (if (typep form 'sequence)
               (max (1+ s) (reduce #'sum form :initial-value s))
               (1+ s))))
  (defmacro atomic-count (form) (sum 0 form)))

And here we can see the macro scoring itself:

(atomic-count
 (labels ((sum (s form)
            (if (typep form 'sequence)
                (max (1+ s) (reduce #'sum form :initial-value s))
                (1+ s))))
   (defmacro atomic-count (form) (sum 0 form))))
=> 26

NB. This never terminates (or, badly) with cyclic expressions built with #1= and #1# reader macros.

(edit) Empty sequences should count as 1 token