Metastatic.Adapters.Python
(Metastatic v0.10.4)
View Source
Python language adapter for MetaAST transformations.
Bridges between Python AST (M1) and MetaAST (M2), enabling cross-language code analysis and transformation for Python source code.
Python AST Structure (M1)
Python's ast module represents AST as nested dictionaries with a _type field:
%{"_type" => "BinOp", "op" => %{"_type" => "Add"}, "left" => ..., "right" => ...}Examples
# Integer literal
%{"_type" => "Constant", "value" => 42}
# Variable
%{"_type" => "Name", "id" => "x", "ctx" => %{"_type" => "Load"}}
# Addition
%{"_type" => "BinOp",
"op" => %{"_type" => "Add"},
"left" => %{"_type" => "Name", "id" => "x"},
"right" => %{"_type" => "Constant", "value" => 5}}
# Function call
%{"_type" => "Call",
"func" => %{"_type" => "Name", "id" => "foo"},
"args" => [...]}M1 ↔ M2 Transformations
This adapter performs bidirectional transformations between Python AST (M1) and MetaAST (M2):
Literals
# M1 → M2
%{"_type" => "Constant", "value" => 42} → {:literal, :integer, 42}
%{"_type" => "Constant", "value" => 3.14} → {:literal, :float, 3.14}
%{"_type" => "Constant", "value" => "hi"} → {:literal, :string, "hi"}
%{"_type" => "Constant", "value" => true} → {:literal, :boolean, true}
%{"_type" => "Constant", "value" => nil} → {:literal, :null, nil}Variables
%{"_type" => "Name", "id" => "x"} → {:variable, "x"}Binary Operations
BinOp(op=Add()) → {:binary_op, :arithmetic, :+, left, right}
Compare(ops=[Eq()]) → {:binary_op, :comparison, :==, left, right}
BoolOp(op=And()) → {:binary_op, :boolean, :and, left, right}Function Calls
Call(func=Name("foo"), args=[...]) → {:function_call, "foo", [...]}Conditionals
If(test=..., body=..., orelse=...) → {:conditional, test, body, orelse}
IfExp(test=..., body=..., orelse=...) → {:conditional, test, body, orelse}Communication Strategy
Since Python parsing requires the ast module, this adapter uses subprocess
communication:
- Parse: Spawn
priv/parsers/python/parser.py→ receives JSON AST - Unparse: Spawn
priv/parsers/python/unparser.py→ receives source
All communication uses stdin/stdout with JSON serialization.
Round-Trip Fidelity
Target >90% round-trip fidelity (Python's AST is lossy for formatting). Metadata preserves:
- Line numbers (
lineno,col_offset) - End positions (
end_lineno,end_col_offset)
Usage
# Parse Python source
{:ok, ast} = Metastatic.Adapters.Python.parse("x + 5")
# Transform to MetaAST
{:ok, meta_ast, metadata} = Metastatic.Adapters.Python.to_meta(ast)
# Transform back to Python AST
{:ok, ast2} = Metastatic.Adapters.Python.from_meta(meta_ast, metadata)
# Unparse to source
{:ok, source} = Metastatic.Adapters.Python.unparse(ast2)Theory
This adapter implements the Galois connection:
α_Python: AS_Python → MetaAST × Metadata
ρ_Python: MetaAST × Metadata → AS_PythonWhere:
α_Pythonisto_meta/1(abstraction)ρ_Pythonisfrom_meta/2(reification)
Python and Elixir/Erlang produce semantically equivalent MetaAST for equivalent code:
# Python: x + 5
# Elixir: x + 5
# Erlang: X + 5.
# All → {:binary_op, :arithmetic, :+, {:variable, _}, {:literal, :integer, 5}}