-
-
Save panesofglass/e6a70f2d09995a6fada049164811df70 to your computer and use it in GitHub Desktop.
Python from F#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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