Skip to content

Commit c0521e5

Browse files
committed
Adds prototype implementation of python backend.
1 parent 64e3e8c commit c0521e5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+11932
-2
lines changed

src/core/initializer.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ let initializerType (iargs : Args.args) =
151151
| LuaCode -> NewObject
152152
| JavaCode -> NewObject
153153
| JuliaCode -> NewObject
154+
| PythonCode -> NewObject
154155

155156

156157
let createInitFunction custom_initializers (iargs : Args.args) stmt =

src/driver/cli.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ let generateCode args file_deps (stmts, vm, acc) =
7474
| JSCode -> Js.generate args stmts
7575
| JavaCode -> Java.generate args stmts
7676
| JuliaCode -> Julia.generate args stmts
77+
| PythonCode -> Python.generate args stmts
7778
in
7879
(GeneratedCode code :: prog_out) @ acc
7980
else

src/generators/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
Cpp
77
Java
88
Julia
9+
Python
910
Common
1011
Tocode
1112
Tables

src/generators/python.ml

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
(*
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2014-2024 Leonardo Laguna Ruiz
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
*)
24+
25+
open Core.Prog
26+
27+
let runtime =
28+
{%pla|import math
29+
import random as random_module
30+
31+
def eps():
32+
return 1e-18
33+
34+
def pi():
35+
return 3.1415926535897932384
36+
37+
def random():
38+
return random_module.random()
39+
40+
def irandom():
41+
return int(random_module.random() * 4294967296)
42+
43+
def clip(x, low, high):
44+
return low if x < low else (high if x > high else x)
45+
46+
def not_(x):
47+
return 0 if x != 0 else 1
48+
49+
def real(x):
50+
return float(x)
51+
52+
def int_(x):
53+
return int(x)
54+
55+
def int_to_float(i):
56+
return float(i)
57+
58+
def float_to_int(i):
59+
return int(math.floor(i))
60+
61+
def initializeArray(v, size):
62+
return [v for _ in range(size)]
63+
64+
|}
65+
66+
67+
let operator (op : operator) =
68+
match op with
69+
| OpAdd -> Pla.string "+"
70+
| OpSub -> Pla.string "-"
71+
| OpMul -> Pla.string "*"
72+
| OpDiv -> Pla.string "/"
73+
| OpMod -> Pla.string "%"
74+
| OpLand -> Pla.string "and"
75+
| OpLor -> Pla.string "or"
76+
| OpBor -> Pla.string "|"
77+
| OpBand -> Pla.string "&"
78+
| OpBxor -> Pla.string "^"
79+
| OpLsh -> Pla.string "<<"
80+
| OpRsh -> Pla.string ">>"
81+
| OpEq -> Pla.string "=="
82+
| OpNe -> Pla.string "!="
83+
| OpLt -> Pla.string "<"
84+
| OpLe -> Pla.string "<="
85+
| OpGt -> Pla.string ">"
86+
| OpGe -> Pla.string ">="
87+
88+
89+
let uoperator (op : uoperator) =
90+
match op with
91+
| UOpNeg -> Pla.string "-"
92+
| UOpNot -> Pla.string "not "
93+
94+
95+
let rec print_exp (e : exp) =
96+
match e.e with
97+
| EEmptyValue -> Pla.string "{}"
98+
| EUnit -> Pla.string "None"
99+
| EBool v ->
100+
Pla.string
101+
(if v then
102+
"True"
103+
else
104+
"False")
105+
| EInt n -> {%pla|<#n#i>|}
106+
| EReal n -> Pla.string (Util.Vfloat.to_string n)
107+
| EFixed n -> Pla.string (Util.Vfloat.to_string n)
108+
| EString s -> Pla.string_quoted s
109+
| EId id -> Pla.string id
110+
| EIndex { e; index = { e = EInt i; _ } } ->
111+
let e = print_exp e in
112+
let index = i in
113+
{%pla|<#e#>[<#index#i>]|}
114+
| EIndex { e; index } ->
115+
let e = print_exp e in
116+
let index = print_exp index in
117+
{%pla|<#e#>[<#index#>]|}
118+
| EArray l -> Pla.wrap (Pla.string "[") (Pla.string "]") (Pla.map_sep Pla.commaspace print_exp l)
119+
| ECall { path; args } ->
120+
let args = Pla.map_sep Pla.commaspace print_exp args in
121+
{%pla|<#path#s>(<#args#>)|}
122+
| EUnOp (op, e) ->
123+
let e = print_exp e in
124+
let op = uoperator op in
125+
{%pla|(<#op#><#e#>)|}
126+
| EOp (op, e1, e2) ->
127+
let se1 = print_exp e1 in
128+
let se2 = print_exp e2 in
129+
let op = operator op in
130+
{%pla|(<#se1#> <#op#> <#se2#>)|}
131+
| EIf { cond; then_; else_ } ->
132+
let cond = print_exp cond in
133+
let then_ = print_exp then_ in
134+
let else_ = print_exp else_ in
135+
{%pla|(<#then_#> if <#cond#> else <#else_#>)|}
136+
| ETuple l ->
137+
let l = Pla.map_sep Pla.commaspace print_exp l in
138+
{%pla|[<#l#>]|}
139+
| EMember (e, m) ->
140+
let e = print_exp e in
141+
{%pla|<#e#>["<#m#s>"]|}
142+
| ETMember (e, i) ->
143+
let e = print_exp e in
144+
let m = i in
145+
{%pla|<#e#>[<#m#i>]|}
146+
| ERecord { elems; _ } ->
147+
let printElem (n, v) =
148+
let v = print_exp v in
149+
{%pla|"<#n#s>": <#v#>|}
150+
in
151+
let elems = Pla.map_sep Pla.commaspace printElem elems in
152+
{%pla|{<#elems#>}|}
153+
154+
155+
let rec print_lexp (e : lexp) =
156+
match e.l with
157+
| LWild -> Pla.string "_"
158+
| LId s -> Pla.string s
159+
| LMember (e, m) ->
160+
let e = print_lexp e in
161+
{%pla|<#e#>["<#m#s>"]|}
162+
| LIndex { e; index = { e = EInt i; _ } } ->
163+
let e = print_lexp e in
164+
let index = i in
165+
{%pla|<#e#>[<#index#i>]|}
166+
| LIndex { e; index } ->
167+
let e = print_lexp e in
168+
let index = print_exp index in
169+
{%pla|<#e#>[<#index#>]|}
170+
| _ -> failwith "Python:print_lexp LTuple"
171+
172+
173+
let print_dexp (e : dexp) =
174+
match e.d with
175+
| DId (id, None) -> {%pla|<#id#s>|}
176+
| DId (id, Some dim) -> {%pla|<#id#s>[<#dim#i>]|}
177+
178+
179+
let rec print_stmt (s : stmt) =
180+
match s.s with
181+
(* if the name is _ctx, initialize as empty dict *)
182+
| StmtDecl (({ d = DId ("_ctx", _); t = { t = TStruct _; _ }; _ } as lhs), None) ->
183+
let lhs = print_dexp lhs in
184+
{%pla|<#lhs#> = {}|}
185+
(* needs allocation - call allocator function *)
186+
| StmtDecl (({ t = { t = TStruct { path; _ }; _ }; _ } as lhs), None) ->
187+
let lhs = print_dexp lhs in
188+
{%pla|<#lhs#> = <#path#s>_alloc()|}
189+
(* declaration without value - initialize to None *)
190+
| StmtDecl (lhs, None) ->
191+
let lhs = print_dexp lhs in
192+
{%pla|<#lhs#> = None|}
193+
(* declaration with value *)
194+
| StmtDecl (lhs, Some rhs) ->
195+
let lhs = print_dexp lhs in
196+
let rhs = print_exp rhs in
197+
{%pla|<#lhs#> = <#rhs#>|}
198+
(* wildcard binding - just evaluate the expression *)
199+
| StmtBind ({ l = LWild; _ }, rhs) ->
200+
let rhs = print_exp rhs in
201+
{%pla|_ = <#rhs#>|}
202+
(* normal assignment *)
203+
| StmtBind (lhs, rhs) ->
204+
let lhs = print_lexp lhs in
205+
let rhs = print_exp rhs in
206+
{%pla|<#lhs#> = <#rhs#>|}
207+
(* return statement *)
208+
| StmtReturn e ->
209+
let e = print_exp e in
210+
{%pla|return <#e#>|}
211+
(* if without else *)
212+
| StmtIf (cond, then_, None) ->
213+
let e = print_exp cond in
214+
let then_ = print_stmt then_ in
215+
{%pla|if <#e#>:<#then_#+>|}
216+
(* if with else *)
217+
| StmtIf (cond, then_, Some else_) ->
218+
let cond = print_exp cond in
219+
let then_ = print_stmt then_ in
220+
let else_ = print_stmt else_ in
221+
{%pla|if <#cond#>:<#then_#+><#>else:<#else_#+>|}
222+
(* while loop *)
223+
| StmtWhile (cond, stmt) ->
224+
let cond = print_exp cond in
225+
let stmt = print_stmt stmt in
226+
{%pla|while <#cond#>:<#stmt#+>|}
227+
(* block of statements *)
228+
| StmtBlock stmts ->
229+
let stmt = Pla.map_sep_all Pla.newline print_stmt stmts in
230+
{%pla|<#stmt#>|}
231+
(* switch converted to if/elif/else chain *)
232+
| StmtSwitch (e1, cases, default) -> (
233+
let if_ =
234+
CCList.fold_right
235+
(fun (e2, body) else_ ->
236+
let cond = C.eeq e1 e2 in
237+
Some (C.sif cond body else_))
238+
cases
239+
default
240+
in
241+
match if_ with
242+
| None -> Pla.string "pass"
243+
| Some if_ -> print_stmt if_)
244+
245+
246+
let print_arg ({ name; _ } : param) = {%pla|<#name#s>|}
247+
248+
let print_function_def (def : function_def) =
249+
let name = def.name in
250+
let args = Pla.map_sep Pla.commaspace print_arg def.args in
251+
{%pla|def <#name#s>(<#args#>):|}
252+
253+
254+
let print_body (body : stmt) =
255+
match body.s with
256+
| StmtBlock [] -> {%pla|<#> pass|}
257+
| StmtBlock stmts ->
258+
let stmts = Pla.map_sep_all Pla.newline print_stmt stmts in
259+
{%pla|<#stmts#+>|}
260+
| _ ->
261+
let stmt = print_stmt body in
262+
{%pla|<#stmt#+>|}
263+
264+
265+
let print_top_stmt (args : Util.Args.args) (t : top_stmt) =
266+
match t.top with
267+
| TopFunction (def, body) ->
268+
let def = print_function_def def in
269+
let body = print_body body in
270+
{%pla|<#def#><#body#><#><#>|}
271+
| TopExternal _ -> Pla.unit
272+
| TopType _ -> Pla.unit
273+
| TopAlias _ -> Pla.unit
274+
| TopConstant (name, _, _, _, _) when args.test_mode -> {%pla|<#name#s> = {}<#>|}
275+
| TopConstant (name, _, _, rhs, _) ->
276+
let rhs = print_exp rhs in
277+
{%pla|<#name#s> = <#rhs#><#>|}
278+
279+
280+
let print_prog (args : Util.Args.args) (t : top_stmt list) = Pla.map_join (print_top_stmt args) t
281+
282+
let getTemplateCode (args : Util.Args.args) =
283+
match args.template with
284+
| None -> Pla.unit, Pla.unit
285+
| Some "performance" -> T_performance.generatePython args
286+
| Some name -> Util.Error.raiseErrorMsg ("Unknown template '" ^ name ^ "' for Python")
287+
288+
289+
let generate (args : Util.Args.args) (stmts : top_stmt list) =
290+
let file = Common.setExt ".py" args.output in
291+
let code = print_prog args stmts in
292+
let pre, post = getTemplateCode args in
293+
[ {%pla|<#runtime#><#pre#><#code#><#post#>|}, file ]

0 commit comments

Comments
 (0)