|
| 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