// make sure codegen.py (https://github.com/CensoredUsername/codegen/blob/master/codegen.py) is in the same folder // and you've added the IronPython package open System.IO open IronPython.Hosting open IronPython.Runtime open Microsoft.FSharp.Reflection let engine = Python.CreateEngine() let pythonPath = [|"/usr/lib/python2.7" Directory.GetCurrentDirectory()|] engine.SetSearchPaths(pythonPath) // based on https://docs.python.org/2.7/library/ast.html type AST = | Compare of AST * AST seq * AST seq | Call of AST * AST seq * AST seq * AST option * AST option | BinOp of AST * AST * AST | If of AST * AST seq * AST seq | IfExp of AST * AST * AST | Add | Sub | Mult | Div | Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn | Num of obj | Name of string let code = IfExp( Compare(Name "a", [Gt], [Name "b"]), Call (Name "some_function", [Num 100], [], None, None), Call (Name "some_other_function", [Num 50], [], None, None)) let ast = engine.ImportModule("ast") /// Given a name and an array of arguments returns a Python AST node instance /// /// This function handles some special casing and heuristics as well let pythonAstNode name args = // look up ast type in ast module by name let astType = ast.GetVariable(name) :?> Types.PythonType match name with // Name takes an extra argument that we always want to be null for now | "Name" -> engine.Operations.Invoke(astType, Array.append args [|null|]) // invoke the ast type on the provided arguments to return a new instance | _ -> engine.Operations.Invoke(astType, args) /// Convert an F# sequence into a Python list let toList<'a> (s:'a seq) = let l = List() for v in s do l.Add(v) |> ignore l /// Given an instance of our AST union (or sequences or options thereof) /// return a Python AST node instance, Python list, or null let rec toPythonAst (a:obj) = match a with | :? AST -> match FSharpValue.GetUnionFields(a, typeof) with | case, x -> pythonAstNode case.Name (Array.map toPythonAst x) | :? seq as s -> toList (Seq.map toPythonAst s) :> obj | :? option as o -> match o with | Some v -> toPythonAst v | None -> null | _ -> a let codegen = engine.ImportModule("codegen") let codegenToSource = codegen.GetVariable("to_source") :?> PythonFunction let pythonCode = toPythonAst code printfn "%A" (engine.Operations.Invoke(codegenToSource, pythonCode))