Skip to content

Instantly share code, notes, and snippets.

@panesofglass
Forked from nasser/python.fsx
Created April 26, 2020 13:55
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save panesofglass/e6a70f2d09995a6fada049164811df70 to your computer and use it in GitHub Desktop.
Python from F#
// 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<AST>) with
| case, x -> pythonAstNode case.Name (Array.map toPythonAst x)
| :? seq<AST> as s -> toList (Seq.map toPythonAst s) :> obj
| :? option<AST> 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))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment