• Sunday

    • Wrote a linter, explored python’s AST.
    • https://sadh.life/post/ast/
    • The builtin module “ast” is pretty good, exposing much of the tree. ast.dump(ast.parse(code), indent=2)
    • 4 categories of nodes: Literals, Variables, Statements, Expressions.
    • Each is really just a module, which is a file, which is a list of statements.
    • AST handles the chaining of operators (like 1 < 2 < 3 < 4 < 5 < 6 < x < 10 < 11).
    • Statements can be assignments, imports, assertions.
    • Expressions evaluate to a value. 2 == 3 is an expression. Comparators, function calls…
    • Python of course lets you run any expression as a statement, just discarding the return value.
    • ctx=Load vs ctx=Store. This is the context; for variable assignment, it will be store. For most others (where you’re loading info from storage), it will be Load. There’s also Del.
    • So the AST just arranges all these statements into a tree.
    • You can specifically traverse and inspect the tree with ast.NodeVisitor.
    • This is how you implement a linter. Traverse the entire AST of a module, search for what you want (eg, cyclomatic complexity by checking nested if statements, or total args in a function, etc), and enforce some conditions on it.
    • You may compile() and exec() a tree, effectively running the python from its AST rather than its source code.
    • If you have access to the source code, you may obviously modify it. If you have access to the AST, you may obviously modify that as well. This is common with NodeTransformer. Change numbers, modify statements, whatever; then just compile and exec your modified tree to get a program that behaves how you’d like it to.
    • An AST doesn’t store whitespace or other style-related information. That’s stored in a CST, concrete syntax tree. That’s the space that formatters operate in (while linters can stay in the abstract tree).