OMCompiler/Compiler/Template/AbsynToJulia.tpl
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of OpenModelica. | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), | ||
| 5 | * c/o Linköpings universitet, Department of Computer and Information Science, | ||
| 6 | * SE-58183 Linköping, Sweden. | ||
| 7 | * | ||
| 8 | * All rights reserved. | ||
| 9 | * | ||
| 10 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR | ||
| 11 | * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. | ||
| 12 | * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES | ||
| 13 | * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL | ||
| 14 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. | ||
| 15 | * | ||
| 16 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium) | ||
| 17 | * Public License (OSMC-PL) are obtained from OSMC, either from the above | ||
| 18 | * address, from the URLs: | ||
| 19 | * http://www.openmodelica.org or | ||
| 20 | * https://github.com/OpenModelica/ or | ||
| 21 | * http://www.ida.liu.se/projects/OpenModelica, | ||
| 22 | * and in the OpenModelica distribution. | ||
| 23 | * | ||
| 24 | * GNU AGPL version 3 is obtained from: | ||
| 25 | * https://www.gnu.org/licenses/licenses.html#GPL | ||
| 26 | * | ||
| 27 | * This program is distributed WITHOUT ANY WARRANTY; without | ||
| 28 | * even the implied warranty of MERCHANTABILITY or FITNESS | ||
| 29 | * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH | ||
| 30 | * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. | ||
| 31 | * | ||
| 32 | * See the full OSMC Public License conditions for more details. | ||
| 33 | * | ||
| 34 | */ | ||
| 35 | |||
| 36 | package AbsynToJulia | ||
| 37 | " | ||
| 38 | Translates Absyn to Julia. | ||
| 39 | @Authors: John Tinnerholm & Martin Sjoelund | ||
| 40 | " | ||
| 41 | /* TODOS: | ||
| 42 | |||
| 43 | TODO: Public/Private semantics : ( | ||
| 44 | TODO: Julia does string concatination with * instead of + | ||
| 45 | |||
| 46 | */ | ||
| 47 | |||
| 48 | import interface AbsynToJuliaTV; | ||
| 49 | import AbsynDumpTpl; | ||
| 50 | |||
| 51 | ✗ | template dumpProgram(Absyn.Program program) | |
| 52 | ::= | ||
| 53 | match program | ||
| 54 | case PROGRAM(classes = {}) then "" | ||
| 55 | case PROGRAM(__) then | ||
| 56 | /* Necessary forward declarations */ | ||
| 57 | let cls_str = (classes |> cls => dumpClass(cls, defaultDumpOptions) ;separator="\n\n") | ||
| 58 | << | ||
| 59 | <%cls_str%> | ||
| 60 | >> | ||
| 61 | end dumpProgram; | ||
| 62 | |||
| 63 | ✗ | template dumpSCodeElements(list<SCode.Element> elements) | |
| 64 | " | ||
| 65 | Dumps forward declaration of uniontypes and partial functions unless elements is empty. | ||
| 66 | Recursion needed to find all partial functions!. This should be call on a per module basis" | ||
| 67 | ::= dumpSCodeElements2(filterElements(elements, defaultOptions)) | ||
| 68 | end dumpSCodeElements; | ||
| 69 | |||
| 70 | ✗ | template dumpSCodeElements2(list<SCode.Element> elements) | |
| 71 | ::= | ||
| 72 | let str = elements |> el hasindex i1 fromindex 1 => | ||
| 73 | ( | ||
| 74 | match el | ||
| 75 | case CLASS(restriction=SCode.R_UNIONTYPE(__)) then | ||
| 76 | '@UniontypeDecl <%name%> <%\n%>' | ||
| 77 | case CLASS(classDef = parts as SCode.PARTS(__), partialPrefix = SCode.NOT_PARTIAL(), restriction=SCode.R_FUNCTION(__)) then | ||
| 78 | dumpSCodeElements2(parts.elementLst) | ||
| 79 | case CLASS(partialPrefix = SCode.PARTIAL(), restriction=SCode.R_FUNCTION(__)) then | ||
| 80 | '<%name%> = Function<%\n%>' | ||
| 81 | else '' | ||
| 82 | ) | ||
| 83 | if str then | ||
| 84 | '<%\n%><%str%>' | ||
| 85 | else '' | ||
| 86 | end dumpSCodeElements2; | ||
| 87 | |||
| 88 | ✗ | template dumpClass(Absyn.Class cls, DumpOptions options) | |
| 89 | /*We do not yet know our context in Absyn */ | ||
| 90 | ::= dumpClassElement(cls, options, noContext) | ||
| 91 | end dumpClass; | ||
| 92 | |||
| 93 | ✗ | template dumpClassElement(Absyn.Class class, DumpOptions options, Context context) | |
| 94 | " | ||
| 95 | Note that partial functions are not handled here. They cannot really be translated to Julia in the way they are used in MetaModelica | ||
| 96 | they are dumped as forward decls along with Uniontypes within the packages they occur. | ||
| 97 | " | ||
| 98 | ::= | ||
| 99 | match class | ||
| 100 | case CLASS(body=parts as PARTS(__), restriction=R_UNIONTYPE(__)) then | ||
| 101 | let commentStr = dumpCommentStrOpt(parts.comment) | ||
| 102 | let class_def_str = dumpClassDef(parts, makeUniontypeContext(name), options) | ||
| 103 | << | ||
| 104 | <%commentStr%> | ||
| 105 | @Uniontype <%name%> begin | ||
| 106 | <%class_def_str%> | ||
| 107 | end | ||
| 108 | >> | ||
| 109 | /* We need to forward declare partial functions in Julia */ | ||
| 110 | case CLASS(partialPrefix=true, restriction=R_FUNCTION(__)) then '' | ||
| 111 | case CLASS(partialPrefix=false, body=parts as PARTS(__), restriction=R_FUNCTION(__)) then | ||
| 112 | let commentStr = dumpCommentStrOpt(parts.comment) | ||
| 113 | let returnType = (parts.classParts |> cp => dumpReturnTypeJL(getElementItemsInClassPart(cp))) | ||
| 114 | let return_str = '<%(parts.classParts |> cp => dumpReturnStrJL(getElementItemsInClassPart(cp), functionContext))%>' | ||
| 115 | let inputs_str = (parts.classParts |> cp => dumpInputsJL(getElementItemsInClassPart(cp), inputContext)) | ||
| 116 | let typevar_inputs = System.stringReplace(inputs_str, "<:", "") | ||
| 117 | let header = dumpClassHeader(parts, restriction) | ||
| 118 | let functionBodyStr = dumpClassDef(parts, makeFunctionContext(return_str), options) | ||
| 119 | /* | ||
| 120 | Input output variables are treated as parameters | ||
| 121 | output and bidirectional variables occurs as local variables in Julia | ||
| 122 | */ | ||
| 123 | << | ||
| 124 | <%commentStr%> | ||
| 125 | function <%name%>(<%if header then typevar_inputs else inputs_str%>) <%if header then "" else returnType%> <%header%> | ||
| 126 | <%functionBodyStr%> | ||
| 127 | <%return_str%> | ||
| 128 | end | ||
| 129 | >> | ||
| 130 | case CLASS(body=parts as PARTS(__)) then | ||
| 131 | let enc_str = if encapsulatedPrefix then "" /*Should we use a macro here?*/ else "" | ||
| 132 | let partial_str = if partialPrefix then "#=TODO: Originally partial =# " else "" | ||
| 133 | let class_type_str = dumpClassType(restriction) | ||
| 134 | let cdef_str1 = match restriction | ||
| 135 | case R_PACKAGE(__) then | ||
| 136 | dumpClassDef(parts, packageContext, options) | ||
| 137 | case R_RECORD(__) then | ||
| 138 | dumpClassDef(parts, makeUniontypeContext(""), options) | ||
| 139 | else | ||
| 140 | dumpClassDef(parts, context, options) | ||
| 141 | let forwardDeclarations = dumpSCodeElements(AbsynToSCode.translateClassdefElements(parts.classParts)) | ||
| 142 | let inform = if forwardDeclarations then | ||
| 143 | '#= Necessary to write declarations for your uniontypes until Julia adds support for mutually recursive types =#' | ||
| 144 | else '' | ||
| 145 | let cdef_str2 = match restriction | ||
| 146 | case R_PACKAGE(__) then | ||
| 147 | << | ||
| 148 | <%\n%> | ||
| 149 | using MetaModelica | ||
| 150 | #= ExportAll is not good practice but it makes it so that we do not have to write export after each function :( =# | ||
| 151 | using ExportAll | ||
| 152 | <%inform%> | ||
| 153 | <%forwardDeclarations%> | ||
| 154 | <%\n%> | ||
| 155 | <%cdef_str1%> | ||
| 156 | <%\n%> | ||
| 157 | #= So that we can use wildcard imports and named imports when they do occur. Not good Julia practice =# | ||
| 158 | @exportAll() | ||
| 159 | >> | ||
| 160 | else | ||
| 161 | << | ||
| 162 | <%cdef_str1%> | ||
| 163 | >> | ||
| 164 | let begin_str = match restriction | ||
| 165 | case R_RECORD(__) then 'begin' | ||
| 166 | else '' | ||
| 167 | |||
| 168 | let cdef_str = cdef_str2 | ||
| 169 | let cmt_str = dumpCommentStrOpt(parts.comment) | ||
| 170 | /* Investigate header_str and annotation string*/ | ||
| 171 | //let ann_str = dumpClassAnnotation(cmt) | ||
| 172 | let header_str = dumpClassHeader(parts, restriction) | ||
| 173 | let footer_str = dumpClassFooter(parts, cdef_str, name, cmt_str, "" /*ann_str*/) | ||
| 174 | let partial_str_and_class_type = '<%partial_str%><%class_type_str%>' | ||
| 175 | << | ||
| 176 | <%partial_str_and_class_type%> <%name%> <%begin_str%> | ||
| 177 | <%header_str%> | ||
| 178 | <%\n%> | ||
| 179 | <%footer_str%> | ||
| 180 | >> | ||
| 181 | /*Regular type redefinitions*/ | ||
| 182 | case CLASS(body=parts as DERIVED(__), restriction=R_TYPE(__)) then | ||
| 183 | /* Derived should have the last context as it's context right? */ | ||
| 184 | let comment = dumpCommentOpt(parts.comment, context) | ||
| 185 | let spec = dumpTypeSpec(parts.typeSpec, context) | ||
| 186 | let args = (parts.arguments |> earg => dumpElementArg(earg, context) ;separator=', ') | ||
| 187 | let attr = dumpElementAttr(parts.attributes) | ||
| 188 | << | ||
| 189 | <%name%> = <%spec%> <%attr%><%comment%> | ||
| 190 | >> | ||
| 191 | /* | ||
| 192 | This is a special case that seems to occur from time to time! | ||
| 193 | Modelica style function redfinition something that is not support in Julia. | ||
| 194 | I solve this using a macro @FunctionExtend.. | ||
| 195 | function pathStringNoQual = pathString(usefq=false); | ||
| 196 | => | ||
| 197 | @ExtendedFunction pathStringNoQual pathString(usefq=false); | ||
| 198 | */ | ||
| 199 | case CLASS(body=parts as DERIVED(__), restriction=R_FUNCTION(__)) then | ||
| 200 | let comment = dumpCommentOpt(parts.comment, context) | ||
| 201 | let spec = dumpTypeSpec(parts.typeSpec, context) | ||
| 202 | let args = (parts.arguments |> earg => dumpElementArg(earg, context) ;separator=', ') | ||
| 203 | let attr = dumpElementAttr(parts.attributes) | ||
| 204 | let name_of_new_function = '<%name%>' | ||
| 205 | << | ||
| 206 | <%comment%> | ||
| 207 | @ExtendedFunction <%name_of_new_function%> <%spec%>(<%args%>) | ||
| 208 | >> | ||
| 209 | /*PDER. Should not occur. Derived Enumeration and Overload might?*/ | ||
| 210 | end dumpClassElement; | ||
| 211 | |||
| 212 | ✗ | template dumpClassHeader(Absyn.ClassDef classDef, Absyn.Restriction restriction) | |
| 213 | ::= | ||
| 214 | match classDef | ||
| 215 | case CLASS_EXTENDS(__) then AbsynDumpTpl.errorMsg("Extend not supported") | ||
| 216 | case PARTS(__) then '<%dumpClassTypeTypeVars(restriction, typeVars)%><%dumpClassTypeSuperType(restriction)%>' | ||
| 217 | else AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassHeader: <%dumpClassTypeSuperType(classDef)%>") | ||
| 218 | end dumpClassHeader; | ||
| 219 | |||
| 220 | ✗ | template dumpClassTypeSuperType(Absyn.Restriction r) | |
| 221 | ::= | ||
| 222 | match r | ||
| 223 | case R_METARECORD(__) then '<: <%dumpPathJL(name)%>' | ||
| 224 | case R_FUNCTION(__) then '' //Do nothing here for functions.. For now | ||
| 225 | end dumpClassTypeSuperType; | ||
| 226 | |||
| 227 | ✗ | template dumpClassTypeTypeVars(Absyn.Restriction restriction, list<String> typeVars) | |
| 228 | ::= | ||
| 229 | match restriction | ||
| 230 | case R_UNIONTYPE(__) then | ||
| 231 | (if typeVars then ("{" + (typeVars |> tv => tv ; separator=",") + "}")) | ||
| 232 | /*Not pretty. But should solve generic functions scathered here and there*/ | ||
| 233 | case R_FUNCTION(__) then | ||
| 234 | (if typeVars then 'where {<%((typeVars |> tv => tv ; separator=", "))%>}') | ||
| 235 | else "" | ||
| 236 | end dumpClassTypeTypeVars; | ||
| 237 | |||
| 238 | ✗ | template dumpClassFooter(Absyn.ClassDef classDef, String cdefStr, String name, String cmt, String ann) | |
| 239 | ::= | ||
| 240 | match classDef | ||
| 241 | case DERIVED(__) then AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassFooter: Derived not yet supported.") | ||
| 242 | case ENUMERATION(__) then AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassFooterf: ENUMERATION not yet supported.") | ||
| 243 | case _ then | ||
| 244 | let annotation_str = if ann then '<%ann%> ' else '' | ||
| 245 | if cdefStr then | ||
| 246 | << | ||
| 247 | <%cdefStr%> | ||
| 248 | <%if annotation_str then " "%><%annotation_str%> | ||
| 249 | end | ||
| 250 | >> | ||
| 251 | else | ||
| 252 | << | ||
| 253 | <%annotation_str%>end | ||
| 254 | >> | ||
| 255 | end dumpClassFooter; | ||
| 256 | |||
| 257 | ✗ | template dumpInputsJL(list<ElementItem> inputs, Context context) | |
| 258 | ::= | ||
| 259 | let inputStr = (listReverse((MMToJuliaUtil.filterOnDirection(inputs, MMToJuliaUtil.makeInputDirection()))) | ||
| 260 | |> ei | ||
| 261 | => '<%dumpComponentItems(getComponentItemsFromElementItem(ei), makeInputContext(dumpTypeSpecOpt(getTypeSpecFromElementItemOpt(ei), inputContext)))%>' | ||
| 262 | ;separator=", ") | ||
| 263 | '<%inputStr%>' | ||
| 264 | end dumpInputsJL; | ||
| 265 | |||
| 266 | ✗ | template dumpReturnTypeJL(list<ElementItem> outputs) | |
| 267 | ::= | ||
| 268 | match MMToJuliaUtil.filterOnDirection(outputs, MMToJuliaUtil.makeOutputDirection()) | ||
| 269 | case {} then "" | ||
| 270 | case L as H::{} then '::<%dumpOutputsJL(L)%>' | ||
| 271 | case L as H::T then '::Tuple{<%dumpOutputsJL(L)%>}' | ||
| 272 | end dumpReturnTypeJL; | ||
| 273 | |||
| 274 | ✗ | template dumpReturnStrJL(list<ElementItem> outputs, Context context) | |
| 275 | ::= | ||
| 276 | match listReverse(MMToJuliaUtil.filterOnDirection(outputs, MMToJuliaUtil.makeOutputDirection())) | ||
| 277 | case {} then "" | ||
| 278 | case L as H::{} then | ||
| 279 | '<%(L |> e => dumpElementItemRaw(e, defaultDumpOptions, context); separator=", ")%>' | ||
| 280 | case L as H::T then | ||
| 281 | << | ||
| 282 | (<%(L |> e => dumpElementItemRaw(e, defaultDumpOptions, context); separator=", ")%>) | ||
| 283 | >> | ||
| 284 | end dumpReturnStrJL; | ||
| 285 | |||
| 286 | |||
| 287 | ✗ | template dumpClassDef(Absyn.ClassDef cdef, Context context, DumpOptions options) | |
| 288 | ::= | ||
| 289 | match cdef | ||
| 290 | case PARTS(__) then | ||
| 291 | let body_str = (classParts |> class_part hasindex idx => | ||
| 292 | dumpClassPart(class_part, idx, context, options) ;separator="\n") | ||
| 293 | << | ||
| 294 | <%body_str%> | ||
| 295 | >> | ||
| 296 | case DERIVED(__) then | ||
| 297 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassDef: Derived not yet supported.") | ||
| 298 | case CLASS_EXTENDS(__) then | ||
| 299 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassDef: CLASS_EXETENDS not yet supported.") | ||
| 300 | case ENUMERATION(__) then | ||
| 301 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassDef: CLASS_ENUMERATION not yet supported.") | ||
| 302 | else "TODO Unkown class definition" | ||
| 303 | end dumpClassDef; | ||
| 304 | |||
| 305 | ✗ | template dumpClassType(Absyn.Restriction restriction) | |
| 306 | ::= | ||
| 307 | match restriction | ||
| 308 | case R_PACKAGE(__) then "module" | ||
| 309 | case R_METARECORD(__) then "struct" | ||
| 310 | case R_RECORD(__) then '@Record' //Only handles Metamodelica records(!) | ||
| 311 | case R_UNIONTYPE(__) then "uniontype" | ||
| 312 | case R_TYPE(__) then '' // Should be const iff we are in a global scope (Julia 1.0 (Packages are not)) | ||
| 313 | case R_FUNCTION(__) then "function" | ||
| 314 | /* TODO: The other ones are probably not relevant for now */ | ||
| 315 | else AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassType: Unknown restriction for class." + AbsynDumpTpl.dumpRestriction(restriction)) | ||
| 316 | end dumpClassType; | ||
| 317 | |||
| 318 | ✗ | template dumpClassPart(Absyn.ClassPart class_part, Integer idx, Context context, DumpOptions options) | |
| 319 | ::= | ||
| 320 | match class_part | ||
| 321 | case PUBLIC(__) then | ||
| 322 | let el_str = if isFunctionContext(context) then | ||
| 323 | dumpElementItems(filterOnDirection(contents, makeOutputDirection()), context, "", true, options) | ||
| 324 | else | ||
| 325 | dumpElementItems(contents, context,"", true, options) | ||
| 326 | << | ||
| 327 | <%el_str%> | ||
| 328 | >> | ||
| 329 | case PROTECTED(__) then | ||
| 330 | let el_str = dumpElementItems(contents, context, "", true, options) | ||
| 331 | << | ||
| 332 | <%el_str%> | ||
| 333 | >> | ||
| 334 | case CONSTRAINTS(__) then | ||
| 335 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassPart: CONSTRAINTS(__) not supported.") | ||
| 336 | case EQUATIONS(__) then | ||
| 337 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassPart: EQUATIONS(__) not supported.") | ||
| 338 | case INITIALEQUATIONS(__) then | ||
| 339 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassPart: INITIALEQUATIONS() not supported.") | ||
| 340 | case ALGORITHMS(__) then | ||
| 341 | << | ||
| 342 | <%(contents |> eq => dumpAlgorithmItem(eq, context) ;separator="\n")%> | ||
| 343 | >> | ||
| 344 | case INITIALALGORITHMS(__) then | ||
| 345 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassPart: INITIALALGORITHMS() not supported.") | ||
| 346 | case EXTERNAL(__) then | ||
| 347 | let ann_str = match annotation_ case SOME(ann) then ' <%dumpAnnotation(ann, context)%>;' | ||
| 348 | match externalDecl | ||
| 349 | case EXTERNALDECL(__) then //Turned of temporary to translate builtin | ||
| 350 | "#= TODO: Defined in the runtime =#" //AbsynDumpTpl.errorMsg("AbsynToJulia.dumpClassPart: EXTERNALDECL(__) not supported.") | ||
| 351 | end dumpClassPart; | ||
| 352 | |||
| 353 | ✗ | template dumpElementItems(list<Absyn.ElementItem> items, Context context, String prevSpacing, Boolean first, DumpOptions options) | |
| 354 | ::= | ||
| 355 | match items | ||
| 356 | case item :: rest_items then | ||
| 357 | let spacing = dumpElementItemSpacing(item) | ||
| 358 | let pre_spacing = if not first then | ||
| 359 | dumpElementItemPreSpacing(spacing, prevSpacing) | ||
| 360 | let item_str = dumpElementItem(item, options, context) | ||
| 361 | let rest_str = dumpElementItems(rest_items, context, spacing, false, options) | ||
| 362 | let post_spacing = if rest_str then spacing | ||
| 363 | << | ||
| 364 | <%pre_spacing%> | ||
| 365 | <%item_str%><%post_spacing%><%\n%> | ||
| 366 | <%if rest_str then rest_str%> | ||
| 367 | >> | ||
| 368 | end dumpElementItems; | ||
| 369 | |||
| 370 | ✗ | template dumpElementItemPreSpacing(String curSpacing, String prevSpacing) | |
| 371 | ::= if not prevSpacing then curSpacing | ||
| 372 | end dumpElementItemPreSpacing; | ||
| 373 | |||
| 374 | ✗ | template dumpElementItemSpacing(Absyn.ElementItem item) | |
| 375 | ::= | ||
| 376 | match item | ||
| 377 | case ELEMENTITEM(element = ELEMENT(specification = CLASSDEF(class_ = CLASS(body = cdef)))) | ||
| 378 | then dumpClassDefSpacing(cdef) | ||
| 379 | end dumpElementItemSpacing; | ||
| 380 | |||
| 381 | ✗ | template dumpClassDefSpacing(Absyn.ClassDef cdef) | |
| 382 | ::= | ||
| 383 | match cdef | ||
| 384 | case PARTS(__) then '<%\n%>' | ||
| 385 | case CLASS_EXTENDS(__) then '<%\n%>' | ||
| 386 | end dumpClassDefSpacing; | ||
| 387 | |||
| 388 | ✗ | template dumpElementItem(Absyn.ElementItem eitem, DumpOptions options, Context context) | |
| 389 | ::= | ||
| 390 | match eitem | ||
| 391 | case ELEMENTITEM(__) then '<%dumpElement(element, options, context)%>' | ||
| 392 | case LEXER_COMMENT(__) then dumpCommentStr(comment) | ||
| 393 | end dumpElementItem; | ||
| 394 | |||
| 395 | ✗ | template dumpElementItemRaw(Absyn.ElementItem eitem, DumpOptions options, Context context) | |
| 396 | "Same as dumpElementItem but does not add the local prefix" | ||
| 397 | ::= | ||
| 398 | match eitem | ||
| 399 | case ELEMENTITEM(__) then | ||
| 400 | match element | ||
| 401 | case ELEMENT(__) then | ||
| 402 | match specification | ||
| 403 | case COMPONENTS(__) then | ||
| 404 | let comps_str = (components |> comp => dumpComponentItem(comp, context) ;separator=", ") | ||
| 405 | '<%comps_str%>' | ||
| 406 | else | ||
| 407 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpElementItem: on none component type") | ||
| 408 | else | ||
| 409 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpElementItem: on none component type") | ||
| 410 | case LEXER_COMMENT(__) then dumpCommentStr(comment) | ||
| 411 | end dumpElementItemRaw; | ||
| 412 | |||
| 413 | ✗ | template dumpElement(Absyn.Element elem, DumpOptions options, Context context) | |
| 414 | ::= | ||
| 415 | match elem | ||
| 416 | case ELEMENT(__) then | ||
| 417 | if boolOr(boolUnparseFileFromInfo(info, options), boolNot(isClassdef(elem))) then | ||
| 418 | let final_str = dumpFinal(finalPrefix) | ||
| 419 | let redecl_str = match redeclareKeywords case SOME(re) then dumpRedeclare(re) | ||
| 420 | let repl_str = match redeclareKeywords case SOME(re) then dumpReplaceable(re) | ||
| 421 | let elementSpec_str = dumpElementSpec(specification, options, context) | ||
| 422 | let constrainClass_str = match constrainClass case SOME(cc) then dumpConstrainClass(cc, context) | ||
| 423 | '<%elementSpec_str%><%constrainClass_str%>' | ||
| 424 | case DEFINEUNIT(__) then AbsynDumpTpl.errorMsg("AbsynToJulia.dumpElement: DEFINEUNIT(__) not supported") | ||
| 425 | case TEXT(__) then | ||
| 426 | if boolUnparseFileFromInfo(info, options) then | ||
| 427 | let name_str = match optName case SOME(name) then name | ||
| 428 | let info_str = dumpInfo(info) | ||
| 429 | '/* Absyn.TEXT(SOME("<%name_str%>"), "<%string%>", "<%info_str%>"); */' | ||
| 430 | end dumpElement; | ||
| 431 | |||
| 432 | ✗ | template dumpInfo(builtin.SourceInfo info) | |
| 433 | ::= | ||
| 434 | match info | ||
| 435 | case SOURCEINFO(__) then | ||
| 436 | let rm_str = if isReadOnly then "readonly" else "writable" | ||
| 437 | 'SOURCEINFO("<%fileName%>", <%rm_str%>, <%lineNumberStart%>, <%columnNumberStart%>, <%lineNumberEnd%>, <%columnNumberEnd%>)\n' | ||
| 438 | end dumpInfo; | ||
| 439 | |||
| 440 | ✗ | template dumpAnnotation(Absyn.Annotation ann, Context context) | |
| 441 | ::= | ||
| 442 | match ann | ||
| 443 | case ANNOTATION(elementArgs={}) then "#= annotation() =#" | ||
| 444 | case ANNOTATION(__) then | ||
| 445 | << | ||
| 446 | #= annotation( | ||
| 447 | <%(elementArgs |> earg => dumpElementArg(earg, context) ;separator=',<%\n%>')%>) =# | ||
| 448 | >> | ||
| 449 | end dumpAnnotation; | ||
| 450 | |||
| 451 | ✗ | template dumpAnnotationOpt(Option<Absyn.Annotation> oann, Context context) | |
| 452 | ::= match oann case SOME(ann) then dumpAnnotation(ann, context) | ||
| 453 | end dumpAnnotationOpt; | ||
| 454 | |||
| 455 | ✗ | template dumpAnnotationOptSpace(Option<Absyn.Annotation> oann, Context context) | |
| 456 | ::= match oann case SOME(ann) then " " + dumpAnnotation(ann, context) | ||
| 457 | end dumpAnnotationOptSpace; | ||
| 458 | |||
| 459 | ✗ | template dumpComment(Absyn.Comment cmt, Context context) | |
| 460 | ::= | ||
| 461 | match cmt | ||
| 462 | case COMMENT(__) then | ||
| 463 | dumpCommentStrOpt(comment) + dumpAnnotationOptSpace(annotation_, context) | ||
| 464 | end dumpComment; | ||
| 465 | |||
| 466 | ✗ | template dumpCommentOpt(Option<Absyn.Comment> ocmt, Context context) | |
| 467 | ::= match ocmt case SOME(cmt) then dumpComment(cmt, context) | ||
| 468 | end dumpCommentOpt; | ||
| 469 | |||
| 470 | ✗ | template dumpCommentStrOpt(Option<String> comment) | |
| 471 | ::= match comment case SOME(cmt) then dumpCommentStr(cmt) | ||
| 472 | end dumpCommentStrOpt; | ||
| 473 | |||
| 474 | ✗ | template dumpCommentStr(String comment) | |
| 475 | ::= | ||
| 476 | let replaceAllRegular = '<%\ %>#= <%System.stringReplace(System.escapedString(comment, false), "//","")%> =#' | ||
| 477 | '<%replaceAllRegular%>' | ||
| 478 | end dumpCommentStr; | ||
| 479 | |||
| 480 | ✗ | template dumpElementArg(Absyn.ElementArg earg, Context context) | |
| 481 | ::= | ||
| 482 | match earg | ||
| 483 | case MODIFICATION(__) then | ||
| 484 | let each_str = dumpEach(eachPrefix) | ||
| 485 | let final_str = dumpFinal(finalPrefix) | ||
| 486 | let path_str = dumpPathJL(path) | ||
| 487 | let mod_str = match modification case SOME(mod) then dumpModification(mod, context) | ||
| 488 | let cmt_str = dumpCommentStrOpt(comment) | ||
| 489 | '<%each_str%><%final_str%><%path_str%><%mod_str%><%cmt_str%>' | ||
| 490 | case REDECLARATION(__) then | ||
| 491 | let each_str = dumpEach(eachPrefix) | ||
| 492 | let final_str = dumpFinal(finalPrefix) | ||
| 493 | let redecl_str = dumpRedeclare(redeclareKeywords) | ||
| 494 | let repl_str = dumpReplaceable(redeclareKeywords) | ||
| 495 | let eredecl_str = '<%redecl_str%><%each_str%>' | ||
| 496 | let elem_str = dumpElementSpec(elementSpec, defaultDumpOptions, context) | ||
| 497 | let cc_str = match constrainClass case SOME(cc) then dumpConstrainClass(cc, context) | ||
| 498 | '<%elem_str%><%cc_str%>' | ||
| 499 | end dumpElementArg; | ||
| 500 | |||
| 501 | ✗ | template dumpEach(Absyn.Each each) | |
| 502 | ::= match each case EACH() then "each " | ||
| 503 | end dumpEach; | ||
| 504 | |||
| 505 | ✗ | template dumpFinal(Boolean final) | |
| 506 | ::= if final then "final " | ||
| 507 | end dumpFinal; | ||
| 508 | |||
| 509 | ✗ | template dumpRedeclare(Absyn.RedeclareKeywords redecl) | |
| 510 | ::= | ||
| 511 | match redecl | ||
| 512 | case REDECLARE() then "redeclare " | ||
| 513 | case REDECLARE_REPLACEABLE() then "redeclare " | ||
| 514 | end dumpRedeclare; | ||
| 515 | |||
| 516 | ✗ | template dumpReplaceable(Absyn.RedeclareKeywords repl) | |
| 517 | ::= | ||
| 518 | match repl | ||
| 519 | case REPLACEABLE() then "replaceable " | ||
| 520 | case REDECLARE_REPLACEABLE() then "replaceable " | ||
| 521 | end dumpReplaceable; | ||
| 522 | |||
| 523 | ✗ | template dumpModification(Absyn.Modification mod, Context context) | |
| 524 | ::= | ||
| 525 | match mod | ||
| 526 | case CLASSMOD(__) then | ||
| 527 | let arg_str = if elementArgLst then | ||
| 528 | '(<%(elementArgLst |> earg => dumpElementArg(earg, context) ;separator=", ")%>)' | ||
| 529 | let eq_str = dumpEqMod(eqMod, context) | ||
| 530 | '<%arg_str%><%eq_str%>' | ||
| 531 | end dumpModification; | ||
| 532 | |||
| 533 | ✗ | template dumpEqMod(Absyn.EqMod eqmod, Context context) | |
| 534 | ::= match eqmod case EQMOD(__) then '<%\ %>= <%dumpExp(exp, context)%>' | ||
| 535 | end dumpEqMod; | ||
| 536 | |||
| 537 | ✗ | template dumpElementSpec(ElementSpec specification, DumpOptions options, Context context) | |
| 538 | ::= | ||
| 539 | match specification | ||
| 540 | case CLASSDEF(__) then dumpClassElement(class_, options, context) | ||
| 541 | case EXTENDS(__) then | ||
| 542 | let bc_str = dumpPathJL(path) | ||
| 543 | let args_str = (elementArg |> earg => dumpElementArg(earg, context) ;separator=", ") | ||
| 544 | let mod_str = if args_str then '(<%args_str%>)' | ||
| 545 | let ann_str = dumpAnnotationOptSpace(annotationOpt, context) | ||
| 546 | 'extends <%bc_str%><%mod_str%><%ann_str%>' | ||
| 547 | case COMPONENTS(__) then | ||
| 548 | let attr_str = dumpElementAttr(attributes) | ||
| 549 | /* Remove all items with input-output specification. They are handled earlier and separate! */ | ||
| 550 | let ty_str = dumpTypeSpec(typeSpec, context) | ||
| 551 | let comps_str = if elementSpecIsOUTPUT_OR_BIDIR(specification) then | ||
| 552 | (components |> comp => | ||
| 553 | let comp_str = dumpComponentItem(comp, makeFunctionReturnContext("",ty_str)) | ||
| 554 | 'local <%comp_str%>' | ||
| 555 | ;separator="\n") | ||
| 556 | else '' | ||
| 557 | let comps_str_no_local = if elementSpecIsOUTPUT_OR_BIDIR(specification) then | ||
| 558 | (components |> comp => | ||
| 559 | let comp_str = dumpComponentItem(comp, noContext) | ||
| 560 | ' <%match context case PACKAGE(__) then "const "%><%comp_str%>::<%ty_str%>' | ||
| 561 | ;separator="\n") | ||
| 562 | else '' | ||
| 563 | /*If our context is a function context we need to redefine comps_str*/ | ||
| 564 | let rStr = match context | ||
| 565 | case FUNCTION(__) then | ||
| 566 | '<%retValsStr%>' | ||
| 567 | else'' | ||
| 568 | /* No local decl if we do not have a comps_str! */ | ||
| 569 | match context | ||
| 570 | case FUNCTION(__) then | ||
| 571 | if comps_str then | ||
| 572 | '<%comps_str%>' | ||
| 573 | else '' | ||
| 574 | case UNIONTYPE(__) then | ||
| 575 | '<%comps_str_no_local%>' | ||
| 576 | case PACKAGE(__) then | ||
| 577 | '<%comps_str_no_local%>' | ||
| 578 | else 'ERROR' | ||
| 579 | case IMPORT(__) then | ||
| 580 | let imp_str = dumpImport(import_) | ||
| 581 | '<%imp_str%>' | ||
| 582 | end dumpElementSpec; | ||
| 583 | |||
| 584 | ✗ | template dumpElementSpecForComponents(ElementSpec specification, DumpOptions options, Context context) | |
| 585 | ::= | ||
| 586 | match specification | ||
| 587 | case COMPONENTS(__) then | ||
| 588 | let comps_str = (components |> comp => dumpComponentItem(comp, context) ;separator=", ") | ||
| 589 | '<%comps_str%>' | ||
| 590 | end dumpElementSpecForComponents; | ||
| 591 | |||
| 592 | ✗ | template dumpElementAttr(Absyn.ElementAttributes attr) | |
| 593 | ::= | ||
| 594 | match attr | ||
| 595 | case ATTR(__) then | ||
| 596 | let var_str = dumpVariability(variability) | ||
| 597 | '<%var_str%>' | ||
| 598 | end dumpElementAttr; | ||
| 599 | |||
| 600 | ✗ | template dumpVariability(Absyn.Variability var) | |
| 601 | ::= | ||
| 602 | match var | ||
| 603 | /* | ||
| 604 | Constants are currently only allowed in the global scope (Julia 1.1). | ||
| 605 | TODO: Global scope is only defined as a scope outside a module. | ||
| 606 | What do to here, Scope as a parameter? | ||
| 607 | */ | ||
| 608 | case VAR() then "" | ||
| 609 | case CONST() then "" | ||
| 610 | else AbsynDumpTpl.errorMsg("AbsynToJulia.dumpVariability: Only const and var are supported") | ||
| 611 | end dumpVariability; | ||
| 612 | |||
| 613 | ✗ | template dumpConstrainClass(Absyn.ConstrainClass cc, Context context) | |
| 614 | ::= | ||
| 615 | match cc | ||
| 616 | case CONSTRAINCLASS(elementSpec = Absyn.EXTENDS(path = p, elementArg = el)) then | ||
| 617 | let path_str = dumpPathJL(p) | ||
| 618 | let el_str = if el then '(<%(el |> e => dumpElementArg(e, context) ;separator=", ")%>)' | ||
| 619 | let cmt_str = dumpCommentOpt(comment, context) | ||
| 620 | ' constrainedby <%path_str%><%el_str%><%cmt_str%>' | ||
| 621 | end dumpConstrainClass; | ||
| 622 | |||
| 623 | ✗ | template dumpComponentItems(list<Absyn.ComponentItem> componentItems, Context context) | |
| 624 | "Returns a comma separated list of component items without the condition string" | ||
| 625 | ::= (componentItems |> ci => dumpComponentItemWithoutCondString(ci, context) ;separator=", ") | ||
| 626 | end dumpComponentItems; | ||
| 627 | |||
| 628 | ✗ | template dumpComponentItem(Absyn.ComponentItem comp, Context context) | |
| 629 | ::= | ||
| 630 | match comp | ||
| 631 | case COMPONENTITEM(__) then | ||
| 632 | let comp_str = dumpComponent(component, context) | ||
| 633 | let cond_str = dumpComponentCondition(condition, context) //TODO. This will complicate things... | ||
| 634 | let cmt = dumpCommentOpt(comment, context) | ||
| 635 | '<%comp_str%><%cond_str%><%cmt%>' | ||
| 636 | end dumpComponentItem; | ||
| 637 | |||
| 638 | ✗ | template dumpComponentItemWithoutCondString(Absyn.ComponentItem comp, Context context) | |
| 639 | ::= | ||
| 640 | match comp | ||
| 641 | case COMPONENTITEM(__) then | ||
| 642 | let comp_str = dumpComponent(component, context) | ||
| 643 | let cmt = dumpCommentOpt(comment, context) | ||
| 644 | '<%comp_str%><%cmt%>' | ||
| 645 | end dumpComponentItemWithoutCondString; | ||
| 646 | |||
| 647 | ✗ | template dumpComponent(Absyn.Component comp, Context context) | |
| 648 | ::= | ||
| 649 | match comp | ||
| 650 | case COMPONENT(__) then | ||
| 651 | let dim_str = dumpSubscripts(arrayDim, context) | ||
| 652 | let mod_str = match modification case SOME(mod) then dumpModification(mod, context) | ||
| 653 | let component_name = '<%name%>' | ||
| 654 | /*REFACTOR INVERSE NAME INVERSE MEANING!*/ | ||
| 655 | match context | ||
| 656 | case FUNCTION_RETURN_CONTEXT(__) then '<%component_name%>::<%ty_str%><%dim_str%><%mod_str%>' | ||
| 657 | case FUNCTION(__) then '<%component_name%>' | ||
| 658 | case INPUT_CONTEXT(__) then '<%component_name%>::<%ty_str%><%dim_str%><%mod_str%>' | ||
| 659 | else '<%component_name%><%dim_str%><%mod_str%>' | ||
| 660 | end dumpComponent; | ||
| 661 | |||
| 662 | ✗ | template dumpComponentCondition(Option<Absyn.ComponentCondition> cond, Context context) | |
| 663 | ::= | ||
| 664 | match cond | ||
| 665 | case SOME(cexp) then | ||
| 666 | let exp_str = dumpExp(cexp, context) | ||
| 667 | ' if <%exp_str%>' | ||
| 668 | end dumpComponentCondition; | ||
| 669 | |||
| 670 | ✗ | template dumpImport(Absyn.Import imp) | |
| 671 | "This will depend on my ExportAll.jl package. Not good practice but seem to be needed at places" | ||
| 672 | ::= | ||
| 673 | match imp | ||
| 674 | case NAMED_IMPORT(__) then | ||
| 675 | 'import <%dumpPathJL(path)%>; <%name%>=<%dumpPathJL(path)%>' | ||
| 676 | case QUAL_IMPORT(__) then | ||
| 677 | let path_str = dumpPathJL(path) | ||
| 678 | match path_str | ||
| 679 | case "Array" then 'import ArrayUtil' | ||
| 680 | case "List" then 'import ListUtil' | ||
| 681 | else 'import <%path_str%>' | ||
| 682 | case UNQUAL_IMPORT(__) then 'using <%dumpPathJL(path)%>' | ||
| 683 | case GROUP_IMPORT(__) then | ||
| 684 | let prefix_str = dumpPathJL(prefix) | ||
| 685 | let groups_str = (groups |> group => dumpGroupImport(group) ;separator=", ") | ||
| 686 | 'using <%prefix_str%>: <%groups_str%>' | ||
| 687 | end dumpImport; | ||
| 688 | |||
| 689 | ✗ | template dumpGroupImport(Absyn.GroupImport gimp) | |
| 690 | ::= | ||
| 691 | match gimp | ||
| 692 | case GROUP_IMPORT_NAME(__) then name | ||
| 693 | case GROUP_IMPORT_RENAME(__) then '<%rename%> = <%name%>' | ||
| 694 | end dumpGroupImport; | ||
| 695 | |||
| 696 | ✗ | template dumpEquation(Absyn.Equation eq) | |
| 697 | ::= "No equations allowed. Translate them to algorithms" | ||
| 698 | end dumpEquation; | ||
| 699 | |||
| 700 | ✗ | template dumpAlgorithmItems(list<Absyn.AlgorithmItem> algs, Context context) | |
| 701 | ::= (algs |> alg => dumpAlgorithmItem(alg, context) ;separator="\n") | ||
| 702 | end dumpAlgorithmItems; | ||
| 703 | |||
| 704 | ✗ | template dumpAlgorithmItem(Absyn.AlgorithmItem alg, Context context) | |
| 705 | ::= | ||
| 706 | match alg | ||
| 707 | case ALGORITHMITEM(__) then | ||
| 708 | let alg_str = dumpAlgorithm(algorithm_, context) | ||
| 709 | let cmt_str = dumpCommentOpt(comment, context) | ||
| 710 | '<%alg_str%><%cmt_str%>' | ||
| 711 | case ALGORITHMITEMCOMMENT(__) then dumpCommentStr(comment) | ||
| 712 | end dumpAlgorithmItem; | ||
| 713 | |||
| 714 | ✗ | template dumpAlgorithm(Absyn.Algorithm alg, Context context) | |
| 715 | ::= | ||
| 716 | match alg | ||
| 717 | case ALG_ASSIGN(__) then | ||
| 718 | let lhs_str = dumpLhsExp(assignComponent, makeFunctionContext("listMatchAssign")) | ||
| 719 | let rhs_str = dumpExp(value, context) | ||
| 720 | /* Somtimes assignments are used as assertions. There are probably more cases...*/ | ||
| 721 | if AbsynUtil.complexIsCref(assignComponent) then | ||
| 722 | match assignComponent | ||
| 723 | case CONS(__) then | ||
| 724 | '@match <%lhs_str%> = <%rhs_str%>' | ||
| 725 | else | ||
| 726 | '<%lhs_str%> = <%rhs_str%>' | ||
| 727 | else | ||
| 728 | '@match <%lhs_str%> = <%rhs_str%>' | ||
| 729 | case ALG_IF(__) then | ||
| 730 | let if_str = dumpAlgorithmBranch(ifExp, trueBranch, "if", context) | ||
| 731 | let elseif_str = (elseIfAlgorithmBranch |> (c, b) => | ||
| 732 | dumpAlgorithmBranch(c, b, "elseif", context) ;separator="\n") | ||
| 733 | let else_branch_str = dumpAlgorithmItems(elseBranch, context) | ||
| 734 | let else_str = if else_branch_str then | ||
| 735 | << | ||
| 736 | else | ||
| 737 | <%else_branch_str%> | ||
| 738 | >> | ||
| 739 | << | ||
| 740 | <%if_str%> | ||
| 741 | <%elseif_str%> | ||
| 742 | <%else_str%> | ||
| 743 | end | ||
| 744 | >> | ||
| 745 | case ALG_FOR(__) then | ||
| 746 | let iter_str = dumpForIterators(iterators, context) | ||
| 747 | let body_str = dumpAlgorithmItems(forBody, context) | ||
| 748 | << | ||
| 749 | for <%iter_str%> | ||
| 750 | <%body_str%> | ||
| 751 | end | ||
| 752 | >> | ||
| 753 | case ALG_WHILE(__) then | ||
| 754 | let while_str = dumpAlgorithmBranch(boolExpr, whileBody, "while", context) | ||
| 755 | << | ||
| 756 | <%while_str%> | ||
| 757 | end | ||
| 758 | >> | ||
| 759 | case ALG_WHEN_A(__) then AbsynDumpTpl.errorMsg("When statements are not allowed!.") | ||
| 760 | case ALG_NORETCALL(__) then | ||
| 761 | let name_str = dumpCref(functionCall, context) | ||
| 762 | let args_str = dumpFunctionArgs(functionArgs, context) | ||
| 763 | '<%name_str%>(<%args_str%>)' | ||
| 764 | /*Here we need to gather all return values for the function*/ | ||
| 765 | case ALG_RETURN(__) then dumpAlgReturnString(context) | ||
| 766 | case ALG_BREAK(__) then "break" | ||
| 767 | case ALG_FAILURE(__) then | ||
| 768 | let arg_str = if equ then dumpAlgorithmItems(equ, context) else "..." | ||
| 769 | '@shouldFail <%arg_str%>' | ||
| 770 | case ALG_TRY(__) then | ||
| 771 | let arg1 = dumpAlgorithmItems(body, context) | ||
| 772 | let arg2 = dumpAlgorithmItems(elseBody, context) | ||
| 773 | << | ||
| 774 | try | ||
| 775 | <%arg1%> | ||
| 776 | catch | ||
| 777 | <%arg2%> | ||
| 778 | end | ||
| 779 | >> | ||
| 780 | case ALG_CONTINUE(__) then "continue" | ||
| 781 | end dumpAlgorithm; | ||
| 782 | |||
| 783 | ✗ | template dumpAlgReturnString(Context context) | |
| 784 | "Dumps the return string for a specific function context" | ||
| 785 | ::= match context | ||
| 786 | case FUNCTION(__) then 'return <%retValsStr%>' | ||
| 787 | /*TODO: Should not occur? Models with sections?*/ | ||
| 788 | else "return" | ||
| 789 | end dumpAlgReturnString; | ||
| 790 | |||
| 791 | ✗ | template dumpAlgorithmBranch(Absyn.Exp cond, list<Absyn.AlgorithmItem> body, | |
| 792 | String header, Context context) | ||
| 793 | ::= | ||
| 794 | let cond_str = dumpExp(cond, context) | ||
| 795 | let body_str = (body |> eq => dumpAlgorithmItem(eq, context) ;separator="\n") | ||
| 796 | << | ||
| 797 | <%header%> <%cond_str%> | ||
| 798 | <%body_str%> | ||
| 799 | >> | ||
| 800 | end dumpAlgorithmBranch; | ||
| 801 | |||
| 802 | ✗ | template dumpPathJL(Absyn.Path path) | |
| 803 | "Wrapper function for dump path. | ||
| 804 | Needed since certain keywords will have a sligthly different meaning in Julia" | ||
| 805 | ::= | ||
| 806 | match path | ||
| 807 | case FULLYQUALIFIED(__) then | ||
| 808 | '.<%AbsynDumpTpl.dumpPath(path)%>' | ||
| 809 | case QUALIFIED(__) then | ||
| 810 | if (Flags.getConfigBool(Flags.MODELICA_OUTPUT)) then | ||
| 811 | '<%name%>__<%AbsynDumpTpl.dumpPath(path)%>' | ||
| 812 | else | ||
| 813 | '<%name%>.<%AbsynDumpTpl.dumpPath(path)%>' | ||
| 814 | case IDENT(__) then | ||
| 815 | match name | ||
| 816 | case "Real" then 'Float' | ||
| 817 | case "Integer" then 'Integer' | ||
| 818 | case "Boolean" then 'Bool' | ||
| 819 | case "list" then 'List' | ||
| 820 | case "array" then 'Array' | ||
| 821 | case "tuple" then 'Tuple' | ||
| 822 | case "polymorphic" then 'Any' | ||
| 823 | case "Mutable" then 'MutableType' | ||
| 824 | else '<%name%>' | ||
| 825 | else | ||
| 826 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpPathJL: Unknown path.") | ||
| 827 | end dumpPathJL; | ||
| 828 | |||
| 829 | ✗ | template dumpPathNoQual(Absyn.Path path) | |
| 830 | ::= | ||
| 831 | match path | ||
| 832 | case FULLYQUALIFIED(__) then | ||
| 833 | dumpPathJL(path) | ||
| 834 | else | ||
| 835 | dumpPathJL(path) | ||
| 836 | end dumpPathNoQual; | ||
| 837 | |||
| 838 | ✗ | template dumpTypeSpecOpt(Option<Absyn.TypeSpec> typespecOpt, Context context) | |
| 839 | ::= match typespecOpt case SOME(ts) then dumpTypeSpec(ts, context) else "" | ||
| 840 | end dumpTypeSpecOpt; | ||
| 841 | |||
| 842 | ✗ | template dumpTypeSpec(Absyn.TypeSpec typeSpec, Context context) | |
| 843 | " | ||
| 844 | Dumps the type specification: | ||
| 845 | |||
| 846 | TODO add several <: for the different types. Not important at the present time. | ||
| 847 | |||
| 848 | TODO: Any types should not have the <: syntax | ||
| 849 | " | ||
| 850 | ::= | ||
| 851 | match typeSpec | ||
| 852 | case TPATH(__) then | ||
| 853 | let path_str = dumpPathJL(path) | ||
| 854 | let arraydim_str = dumpArrayDimOpt(arrayDim, context) | ||
| 855 | '<%path_str%><%arraydim_str%>' | ||
| 856 | case TCOMPLEX(__) then | ||
| 857 | let path_str = dumpPathJL(path) | ||
| 858 | let ty_str = (typeSpecs |> ty => dumpTypeSpec(ty, context) ;separator=", ") | ||
| 859 | let arraydim_str = dumpArrayDimOpt(arrayDim, context) | ||
| 860 | /* For input context/Function context we use special Julia syntax to allow covariance (ML style typing) */ | ||
| 861 | let isFunc = match context | ||
| 862 | case INPUT_CONTEXT(__) then "iofunc" | ||
| 863 | else "" | ||
| 864 | let isPackage = match context | ||
| 865 | case PACKAGE(__) then "package" | ||
| 866 | else "" | ||
| 867 | let ty_str2 ='{<:<%ty_str%>}' | ||
| 868 | let res = '<%path_str%><%ty_str2%><%arraydim_str%>' | ||
| 869 | if isFunc then | ||
| 870 | '<%res%>' | ||
| 871 | else | ||
| 872 | if isPackage then | ||
| 873 | '<%path_str%>' | ||
| 874 | else | ||
| 875 | '<%path_str%>{<%ty_str%>}<%arraydim_str%>' | ||
| 876 | end dumpTypeSpec; | ||
| 877 | |||
| 878 | ✗ | template dumpArrayDimOptTypeSpec(Option<Absyn.ArrayDim> arraydim, Context context) | |
| 879 | "Not in use" | ||
| 880 | ::= match arraydim case SOME(ad) then dumpSubscriptsTypeSpec(ad, context) | ||
| 881 | end dumpArrayDimOptTypeSpec; | ||
| 882 | |||
| 883 | ✗ | template dumpSubscriptsTypeSpec(list<Absyn.Subscript> subscripts, Context context) | |
| 884 | "Not in use" | ||
| 885 | ::= | ||
| 886 | if subscripts then | ||
| 887 | let sub_str = (subscripts |> s => 'Array' ;separator=", ") | ||
| 888 | 'Array{<%sub_str%>}' | ||
| 889 | end dumpSubscriptsTypeSpec; | ||
| 890 | |||
| 891 | ✗ | template dumpArrayDimOpt(Option<Absyn.ArrayDim> arraydim, Context context) | |
| 892 | ::= match arraydim case SOME(ad) then dumpSubscripts(ad, context) | ||
| 893 | end dumpArrayDimOpt; | ||
| 894 | |||
| 895 | ✗ | template dumpSubscripts(list<Absyn.Subscript> subscripts, Context context) | |
| 896 | ::= | ||
| 897 | if subscripts then | ||
| 898 | let sub_str = (subscripts |> s => dumpSubscript(s, context) ;separator=", ") | ||
| 899 | '[<%sub_str%>]' | ||
| 900 | end dumpSubscripts; | ||
| 901 | |||
| 902 | ✗ | template dumpSubscript(Absyn.Subscript subscript, Context context) | |
| 903 | ::= | ||
| 904 | match subscript | ||
| 905 | case NOSUB(__) then ':' | ||
| 906 | case SUBSCRIPT(__) then dumpExp(subscript, context) | ||
| 907 | end dumpSubscript; | ||
| 908 | |||
| 909 | ✗ | template dumpExp(Absyn.Exp exp, Context context) | |
| 910 | ::= | ||
| 911 | match exp | ||
| 912 | case INTEGER(__) then value | ||
| 913 | case REAL(__) then value | ||
| 914 | case CREF(__) then dumpCref(componentRef, context) | ||
| 915 | case STRING(__) then '"<%Util.escapeModelicaStringToJLString(value)%>"' | ||
| 916 | case BOOL(__) then value | ||
| 917 | case e as BINARY(__) then | ||
| 918 | let lhs_str = dumpOperand(exp1, e, true, context) | ||
| 919 | let rhs_str = dumpOperand(exp2, e, false, context) | ||
| 920 | let op_str = dumpOperator(op) | ||
| 921 | '<%lhs_str%> <%op_str%> <%rhs_str%>' | ||
| 922 | case e as UNARY(__) then | ||
| 923 | let exp_str = dumpOperand(exp, e, false, context) | ||
| 924 | let op_str = dumpOperator(op) | ||
| 925 | '<%op_str%><%exp_str%>' | ||
| 926 | case e as LBINARY(__) then | ||
| 927 | let lhs_str = dumpOperand(exp1, e, true, context) | ||
| 928 | let rhs_str = dumpOperand(exp2, e, false, context) | ||
| 929 | let op_str = dumpOperator(op) | ||
| 930 | '<%lhs_str%> <%op_str%> <%rhs_str%>' | ||
| 931 | case e as LUNARY(__) then | ||
| 932 | let exp_str = dumpOperand(exp, e, false, context) | ||
| 933 | let op_str = dumpOperator(op) | ||
| 934 | '<%op_str%> <%exp_str%>' | ||
| 935 | case e as RELATION(__) then | ||
| 936 | let lhs_str = dumpOperand(exp1, e, true, context) | ||
| 937 | let rhs_str = dumpOperand(exp2, e, false, context) | ||
| 938 | let op_str = dumpOperator(op) | ||
| 939 | '<%lhs_str%> <%op_str%> <%rhs_str%>' | ||
| 940 | case IFEXP(__) then dumpIfExp(exp, context) | ||
| 941 | case CALL(function_=Absyn.CREF_IDENT(name="$array")) then | ||
| 942 | let args_str = dumpFunctionArgs(functionArgs, context) | ||
| 943 | '{<%args_str%>}' | ||
| 944 | case CALL(__) then | ||
| 945 | let func_str = dumpCref(function_, context) | ||
| 946 | let args_str = dumpFunctionArgs(functionArgs, context) | ||
| 947 | '<%func_str%>(<%args_str%>)' | ||
| 948 | case PARTEVALFUNCTION(__) then | ||
| 949 | let func_str = dumpCref(function_, context) | ||
| 950 | let args_str = dumpFunctionArgs(functionArgs, context) | ||
| 951 | /* Same scenario when extending functions. | ||
| 952 | We pass a function and change the parameters | ||
| 953 | */ | ||
| 954 | let args2_str = match functionArgs | ||
| 955 | case FUNCTIONARGS(__) then | ||
| 956 | '<%(argNames |> na => dumpNamedArgPattern3(na) ;separator=", ")%>' | ||
| 957 | else | ||
| 958 | '' | ||
| 959 | '(<%args2_str%>) -> <%func_str%>(<%args_str%>)' | ||
| 960 | case ARRAY(__) /*MM grammar changing behaviour... Remember to change this IF regular arrays would occur... Probably not used so can be ignored */ then | ||
| 961 | let array_str = (arrayExp |> e => dumpExp(e, context) ;separator=", ") | ||
| 962 | if array_str then | ||
| 963 | 'list(<%array_str%>)' | ||
| 964 | else | ||
| 965 | 'nil' | ||
| 966 | case MATRIX(__) then | ||
| 967 | let matrix_str = (matrix |> row => | ||
| 968 | (row |> e => dumpExp(e, context) ;separator=", ") ;separator="; ") | ||
| 969 | '[<%matrix_str%>]' | ||
| 970 | case e as RANGE(step = SOME(step)) then | ||
| 971 | let start_str = dumpOperand(start, e, false, context) | ||
| 972 | let step_str = dumpOperand(step, e, false, context) | ||
| 973 | let stop_str = dumpOperand(stop, e, false, context) | ||
| 974 | '<%start_str%>:<%step_str%>:<%stop_str%>' | ||
| 975 | case e as RANGE(step = NONE()) then | ||
| 976 | let start_str = dumpOperand(start, e, false, context) | ||
| 977 | let stop_str = dumpOperand(stop, e, false, context) | ||
| 978 | '<%start_str%>:<%stop_str%>' | ||
| 979 | case TUPLE(__) then | ||
| 980 | /* Paranthesis does not seem to be needed for tuples in Julia | ||
| 981 | and gives parse errors.. In certain situations that is | ||
| 982 | Readded paranthesis and added linebreaks to if expressions. Not | ||
| 983 | safe to generate one line if exprs | ||
| 984 | */ | ||
| 985 | let tuple_str = (expressions |> e => dumpExp(e,context); separator=", " ;empty) | ||
| 986 | if tuple_str then '(<%tuple_str%>)' | ||
| 987 | else '()' | ||
| 988 | case END(__) then 'end' | ||
| 989 | case CODE(__) then '$Code(<%dumpCodeNode(code, context)%>)' | ||
| 990 | case AS(__) then | ||
| 991 | let exp_str = dumpExp(exp, context) | ||
| 992 | /* TODO Macro might be needed for this case*/ | ||
| 993 | '(@match <%exp_str%> = <%id%>)' | ||
| 994 | case CONS(__) then | ||
| 995 | let head_str = dumpExp(head, context) | ||
| 996 | let rest_str = dumpExp(rest, context) | ||
| 997 | '_cons(<%head_str%>, <%rest_str%>)' | ||
| 998 | case MATCHEXP(__) then dumpMatchExp(exp) | ||
| 999 | case LIST(__) then | ||
| 1000 | let list_str = (exps |> e => dumpExp(e, context) ;separator=", ") | ||
| 1001 | 'list(<%list_str%>)' | ||
| 1002 | case DOT(__) then | ||
| 1003 | '<%dumpExp(exp, context)%>.<%dumpExp(index, context)%>' | ||
| 1004 | case _ then '/* AbsynDumpTpl.dumpExp: UNHANDLED Abyn.Exp */' | ||
| 1005 | end dumpExp; | ||
| 1006 | |||
| 1007 | ✗ | template dumpPattern(Absyn.Exp exp, Context context, Text &as_str) | |
| 1008 | ::= | ||
| 1009 | match exp | ||
| 1010 | case INTEGER(__) then value | ||
| 1011 | case REAL(__) then value | ||
| 1012 | case CREF(__) then dumpCref(componentRef, functionContext /*Only occurs in fc*/) | ||
| 1013 | case STRING(__) then ('"<%stringReplace(value,"\$","\\$"); absIndent=0%>"') | ||
| 1014 | case BOOL(__) then value | ||
| 1015 | case ARRAY(arrayExp=exps) | ||
| 1016 | case LIST(__) | ||
| 1017 | case CALL(function_=Absyn.CREF_IDENT(name="list"), functionArgs=FUNCTIONARGS(args=exps)) | ||
| 1018 | case CALL(function_=Absyn.CREF_IDENT(name="$array"), functionArgs=FUNCTIONARGS(args=exps)) then | ||
| 1019 | /*Using nil() is only ok for matchexpressions*/ | ||
| 1020 | '<%exps |> e => '<%dumpPattern(e, context, &as_str)%> <| '%> nil()' | ||
| 1021 | case CALL(function_=function_ as CREF_IDENT(name=id)) then | ||
| 1022 | let args_str = dumpFunctionArgsPattern(functionArgs) | ||
| 1023 | let func_str = (match id | ||
| 1024 | case "list" then "List" | ||
| 1025 | else dumpCref(function_, functionContext)) | ||
| 1026 | if args_str then | ||
| 1027 | '<%func_str%>(<%args_str%>)' | ||
| 1028 | else | ||
| 1029 | /*We have a wildcard*/ | ||
| 1030 | let isNone = match func_str | ||
| 1031 | case "NONE" then "NONE" | ||
| 1032 | else "" | ||
| 1033 | if isNone then | ||
| 1034 | '<%func_str%>()' | ||
| 1035 | else | ||
| 1036 | '<%func_str%>(__)' | ||
| 1037 | case CALL(__) then | ||
| 1038 | let func_str = dumpCref(function_, functionContext) | ||
| 1039 | let args_str = dumpFunctionArgsPattern(functionArgs) | ||
| 1040 | if args_str then | ||
| 1041 | '<%func_str%>(<%args_str%>)' | ||
| 1042 | else | ||
| 1043 | /* This means we have a wildcard */ | ||
| 1044 | '<%func_str%>(__)' | ||
| 1045 | case TUPLE(__) then | ||
| 1046 | let tuple_str = (expressions |> e => dumpPattern(e, context, &as_str); separator=", " ;empty) | ||
| 1047 | '(<%tuple_str%>)' | ||
| 1048 | case AS(__) then | ||
| 1049 | let exp_str = dumpPattern(exp, context, &as_str) | ||
| 1050 | let id_str = '<%id%>' | ||
| 1051 | '<%id_str%> && <%exp_str%>' | ||
| 1052 | case CONS(__) then | ||
| 1053 | let consOp = dumpCons(dumpPattern(head, context, &as_str), dumpPattern(rest, context, &as_str)) | ||
| 1054 | '<%consOp%>' | ||
| 1055 | case _ then '#= AbsynDumpTpl.dumpPattern: UNHANDLED Abyn.Exp =#' | ||
| 1056 | end dumpPattern; | ||
| 1057 | |||
| 1058 | ✗ | template dumpCons(String headString, String tailString) | |
| 1059 | ::= '<%headString%> <| <%tailString%>' | ||
| 1060 | end dumpCons; | ||
| 1061 | |||
| 1062 | ✗ | template dumpFunctionArgsPattern(Absyn.FunctionArgs args) | |
| 1063 | ::= | ||
| 1064 | match args | ||
| 1065 | case FUNCTIONARGS(__) then | ||
| 1066 | let args_str = (args |> arg => dumpPattern(arg, functionContext, emptyTxt) ;separator=", ") | ||
| 1067 | let namedargs_str = (argNames |> narg => dumpNamedArgPattern(narg) ;separator=", ") | ||
| 1068 | let separator = if args_str then if argNames then ', ' | ||
| 1069 | '<%args_str%><%separator%><%namedargs_str%>' | ||
| 1070 | else 'ERROR FOR_ITER_FARG in pattern' | ||
| 1071 | end dumpFunctionArgsPattern; | ||
| 1072 | |||
| 1073 | ✗ | template dumpNamedArgPattern(Absyn.NamedArg narg) | |
| 1074 | ::= | ||
| 1075 | match narg | ||
| 1076 | case NAMEDARG(__) then | ||
| 1077 | '<%argName%> = <%dumpPattern(argValue, functionContext, emptyTxt)%>' | ||
| 1078 | end dumpNamedArgPattern; | ||
| 1079 | |||
| 1080 | |||
| 1081 | ✗ | template dumpNamedArgPattern2(Absyn.NamedArg narg) | |
| 1082 | "Returns the argument name" | ||
| 1083 | ::= | ||
| 1084 | match narg | ||
| 1085 | case NAMEDARG(__) then | ||
| 1086 | "<%argName%>" | ||
| 1087 | end dumpNamedArgPattern2; | ||
| 1088 | |||
| 1089 | |||
| 1090 | ✗ | template dumpNamedArgPattern3(Absyn.NamedArg narg) | |
| 1091 | "Returns the argument value" | ||
| 1092 | ::= | ||
| 1093 | match narg | ||
| 1094 | case NAMEDARG(__) then | ||
| 1095 | '<%dumpPattern(argValue, functionContext, emptyTxt)%>' | ||
| 1096 | end dumpNamedArgPattern3; | ||
| 1097 | |||
| 1098 | ✗ | template dumpLhsExp(Absyn.Exp lhs, Context context) | |
| 1099 | ::= | ||
| 1100 | match lhs | ||
| 1101 | case IFEXP(__) then '<%dumpExp(lhs, context)%>' | ||
| 1102 | else dumpExp(lhs, context) | ||
| 1103 | end dumpLhsExp; | ||
| 1104 | |||
| 1105 | ✗ | template dumpOperand(Absyn.Exp operand, Absyn.Exp operation, Boolean lhs, Context context) | |
| 1106 | ::= | ||
| 1107 | let op_str = dumpExp(operand, context) | ||
| 1108 | if shouldParenthesize(operand, operation, lhs) then | ||
| 1109 | '(<%op_str%>)' | ||
| 1110 | else | ||
| 1111 | op_str | ||
| 1112 | end dumpOperand; | ||
| 1113 | |||
| 1114 | ✗ | template dumpIfExp(Absyn.Exp if_exp, Context context) | |
| 1115 | ::= | ||
| 1116 | match if_exp | ||
| 1117 | case IFEXP(__) then | ||
| 1118 | let cond_str = dumpExp(ifExp, context) | ||
| 1119 | let true_branch_str = dumpExp(trueBranch, context) | ||
| 1120 | let else_branch_str = dumpExp(elseBranch, context) | ||
| 1121 | let else_if_str = dumpElseIfExp(elseIfBranch, context) | ||
| 1122 | 'if <%cond_str%> | ||
| 1123 | <%true_branch_str%> | ||
| 1124 | <%else_if_str%> | ||
| 1125 | else | ||
| 1126 | <%else_branch_str%> | ||
| 1127 | end' | ||
| 1128 | end dumpIfExp; | ||
| 1129 | |||
| 1130 | ✗ | template dumpElseIfExp(list<tuple<Absyn.Exp, Absyn.Exp>> else_if, Context context) | |
| 1131 | ::= | ||
| 1132 | else_if |> eib as (cond, branch) => | ||
| 1133 | let cond_str = dumpExp(cond, context) | ||
| 1134 | let branch_str = dumpExp(branch, context) | ||
| 1135 | 'elseif (<%cond_str%>) | ||
| 1136 | <%branch_str%>' ;separator="\n" | ||
| 1137 | end dumpElseIfExp; | ||
| 1138 | |||
| 1139 | ✗ | template dumpCodeNode(Absyn.CodeNode code, Context context) | |
| 1140 | ::= | ||
| 1141 | match code | ||
| 1142 | case C_TYPENAME(__) then dumpPathJL(path) | ||
| 1143 | case C_VARIABLENAME(__) then dumpCref(componentRef, context) | ||
| 1144 | case C_CONSTRAINTSECTION(__) then | ||
| 1145 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpCodeNode: C_CONSTRAINTSECTION not supported") | ||
| 1146 | case C_EQUATIONSECTION(__) then | ||
| 1147 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpCodeNode: C_CONSTRAINTSECTION not supported") | ||
| 1148 | case C_ALGORITHMSECTION(__) then | ||
| 1149 | AbsynDumpTpl.errorMsg("AbsynToJulia.dumpCodeNode: C_ALGORITHMSECTION not supported") | ||
| 1150 | case C_ELEMENT(__) then dumpElement(element, Dump.defaultDumpOptions, context) | ||
| 1151 | case C_EXPRESSION(__) then dumpExp(exp, context) | ||
| 1152 | case C_MODIFICATION(__) then dumpModification(modification, context) | ||
| 1153 | end dumpCodeNode; | ||
| 1154 | |||
| 1155 | //John: look at this one more time... | ||
| 1156 | ✗ | template dumpMatchExp(Absyn.Exp match_exp) | |
| 1157 | ::= | ||
| 1158 | match match_exp | ||
| 1159 | case MATCHEXP(__) then | ||
| 1160 | let match_ty_str = dumpMatchType(matchTy) | ||
| 1161 | let input_str = dumpExp(inputExp, functionContext) | ||
| 1162 | let locals_str = dumpMatchLocals(localDecls) | ||
| 1163 | /* Input string is a tuple or a single variable*/ | ||
| 1164 | let cases_str = (cases |> c => dumpMatchCase(c, makeMatchContext(inputExp)) ;separator="\n\n") | ||
| 1165 | let cmt_str = dumpCommentStrOpt(comment) | ||
| 1166 | << | ||
| 1167 | begin | ||
| 1168 | <%locals_str%> | ||
| 1169 | <%match_ty_str%> <%input_str%> begin | ||
| 1170 | <%cases_str%><%cmt_str%> | ||
| 1171 | end | ||
| 1172 | end | ||
| 1173 | >> | ||
| 1174 | end dumpMatchExp; | ||
| 1175 | |||
| 1176 | ✗ | template dumpMatchType(Absyn.MatchType match_type) | |
| 1177 | ::= | ||
| 1178 | match match_type | ||
| 1179 | case MATCH() then "@match" | ||
| 1180 | case MATCHCONTINUE() then "@matchcontinue" | ||
| 1181 | end dumpMatchType; | ||
| 1182 | |||
| 1183 | ✗ | template dumpMatchContents(ClassPart cp) | |
| 1184 | ::= | ||
| 1185 | match cp | ||
| 1186 | case EQUATIONS(contents={}) then "" | ||
| 1187 | case EQUATIONS(__) then | ||
| 1188 | << | ||
| 1189 | <%(Static.fromEquationsToAlgAssignments(cp) |> alg => dumpAlgorithmItem(alg, functionContext) ;separator="\n")%> | ||
| 1190 | >> | ||
| 1191 | case ALGORITHMS(contents={}) then "" | ||
| 1192 | case ALGORITHMS(contents=algs) then | ||
| 1193 | << | ||
| 1194 | <%(algs |> alg => dumpAlgorithmItem(alg, functionContext) ;separator="\n")%> | ||
| 1195 | >> | ||
| 1196 | end dumpMatchContents; | ||
| 1197 | |||
| 1198 | ✗ | template dumpMatchLocals(list<ElementItem> locals) | |
| 1199 | ::= if locals then | ||
| 1200 | << | ||
| 1201 | <%(locals |> decl => dumpElementItem(decl, defaultDumpOptions, functionContext) ;separator="\n")%> | ||
| 1202 | >> | ||
| 1203 | end dumpMatchLocals; | ||
| 1204 | |||
| 1205 | ✗ | template dumpMatchCase(Absyn.Case c, Context context) | |
| 1206 | ::= | ||
| 1207 | match c | ||
| 1208 | case CASE(__) then | ||
| 1209 | let &as_str = buffer "" | ||
| 1210 | let pattern_str = dumpPattern(pattern, context, &as_str) | ||
| 1211 | let guard_str = match patternGuard case SOME(g) then 'where (<%dumpExp(g, context)%>) ' | ||
| 1212 | let eql_str = dumpMatchContents(classPart) | ||
| 1213 | let result_str = dumpExp(result, context) | ||
| 1214 | let cmt_str = dumpCommentStrOpt(comment) | ||
| 1215 | let input_str = match context | ||
| 1216 | case MATCH_CONTEXT(__) then dumpExp(inputExp, context) | ||
| 1217 | else '' | ||
| 1218 | /* | ||
| 1219 | There are more cases in which this as statements can be used to mess up rematch.jl | ||
| 1220 | only a partial fix. | ||
| 1221 | */ | ||
| 1222 | if as_str then | ||
| 1223 | << | ||
| 1224 | <%pattern_str%> <%guard_str%><%cmt_str%> => begin | ||
| 1225 | <%&as_str%> | ||
| 1226 | <%eql_str%> | ||
| 1227 | <%result_str%> | ||
| 1228 | end | ||
| 1229 | >> | ||
| 1230 | else | ||
| 1231 | << | ||
| 1232 | <%pattern_str%> <%guard_str%><%cmt_str%> => begin | ||
| 1233 | <%eql_str%> | ||
| 1234 | <%result_str%> | ||
| 1235 | end | ||
| 1236 | >> | ||
| 1237 | case ELSE(__) then | ||
| 1238 | let eql_str = dumpMatchContents(classPart) | ||
| 1239 | let result_str = dumpExp(result, context) | ||
| 1240 | let cmt_str = dumpCommentStrOpt(comment) | ||
| 1241 | << | ||
| 1242 | _ <%cmt_str%> => begin | ||
| 1243 | <%eql_str%> | ||
| 1244 | <%result_str%> | ||
| 1245 | end | ||
| 1246 | >> | ||
| 1247 | end dumpMatchCase; | ||
| 1248 | |||
| 1249 | ✗ | template dumpOperator(Absyn.Operator op) | |
| 1250 | ::= match op | ||
| 1251 | case AND(__) then '&&' | ||
| 1252 | case OR(__) then '||' | ||
| 1253 | case NOT(__) then '!' | ||
| 1254 | case NEQUAL(__) then '!=' | ||
| 1255 | else AbsynDumpTpl.dumpOperator(op) | ||
| 1256 | end dumpOperator; | ||
| 1257 | |||
| 1258 | ✗ | template dumpCref(Absyn.ComponentRef cref, Context context) | |
| 1259 | ::= | ||
| 1260 | match cref | ||
| 1261 | case CREF_QUAL(__) then | ||
| 1262 | let ss_str = dumpSubscripts(subscripts, context) | ||
| 1263 | let c_str = dumpCref(componentRef, context) | ||
| 1264 | match name | ||
| 1265 | case "List" then 'ListUtil<%ss_str%>.<%c_str%>' | ||
| 1266 | case "Array" then 'ArrayUtil<%ss_str%>.<%c_str%>' | ||
| 1267 | else '<%name%>.<%c_str%>' | ||
| 1268 | case CREF_IDENT(__) then | ||
| 1269 | '<%name%><%dumpSubscripts(subscripts, context)%>' | ||
| 1270 | case CREF_FULLYQUALIFIED(__) then '.<%dumpCref(componentRef, context)%>' | ||
| 1271 | case WILD(__) then if Config.acceptMetaModelicaGrammar() then "_" else "" | ||
| 1272 | case ALLWILD(__) then '__' | ||
| 1273 | end dumpCref; | ||
| 1274 | |||
| 1275 | ✗ | template dumpFunctionArgs(Absyn.FunctionArgs args, Context context) | |
| 1276 | ::= | ||
| 1277 | match args | ||
| 1278 | case FUNCTIONARGS(__) then | ||
| 1279 | let args_str = (args |> arg => dumpExp(arg, context) ;separator=", ") | ||
| 1280 | let namedargs_str = (argNames |> narg => dumpNamedArg(narg, context) ;separator=", ") | ||
| 1281 | let separator = if args_str then if argNames then ', ' | ||
| 1282 | '<%args_str%><%separator%><%namedargs_str%>' | ||
| 1283 | case FOR_ITER_FARG(__) then | ||
| 1284 | let exp_str = dumpExp(exp, context) | ||
| 1285 | let iter_str = (iterators |> i => dumpForIterator(i, context) ;separator=", ") | ||
| 1286 | let iter_names = (iterators |> i => dumpForIteratorName(i, context) ;separator=", ") | ||
| 1287 | let iter_ranges = (iterators |> i => dumpForIteratorRanges(i, context) ;separator=", ") | ||
| 1288 | match iterType | ||
| 1289 | case THREAD(__) then | ||
| 1290 | '@do_threaded_for <%exp_str%> (<%iter_names%>) (<%iter_ranges%>)' | ||
| 1291 | else | ||
| 1292 | '<%exp_str%> for <%iter_str%>' | ||
| 1293 | end dumpFunctionArgs; | ||
| 1294 | |||
| 1295 | ✗ | template dumpNamedArg(Absyn.NamedArg narg, Context context) | |
| 1296 | ::= | ||
| 1297 | match narg | ||
| 1298 | case NAMEDARG(__) then | ||
| 1299 | '<%argName%> = <%dumpExp(argValue, context)%>' | ||
| 1300 | end dumpNamedArg; | ||
| 1301 | |||
| 1302 | ✗ | template dumpForIterators(Absyn.ForIterators iters, Context context) | |
| 1303 | ::= (iters |> i => dumpForIterator(i, context) ;separator=", ") | ||
| 1304 | end dumpForIterators; | ||
| 1305 | |||
| 1306 | ✗ | template dumpForIterator(Absyn.ForIterator iterator, Context context) | |
| 1307 | ::= | ||
| 1308 | match iterator | ||
| 1309 | case ITERATOR(__) then | ||
| 1310 | let range_str = match range case SOME(r) then ' in <%dumpExp(r, context)%>' | ||
| 1311 | let guard_str = match guardExp case SOME(g) then ' if <%dumpExp(g, context)%>' | ||
| 1312 | '<%name%><%range_str%><%guard_str%>' | ||
| 1313 | end dumpForIterator; | ||
| 1314 | |||
| 1315 | ✗ | template dumpForIteratorRanges(Absyn.ForIterator iterator, Context context) | |
| 1316 | ::= | ||
| 1317 | match iterator | ||
| 1318 | case ITERATOR(__) then | ||
| 1319 | let range_str = match range case SOME(r) then '<%dumpExp(r, context)%>' | ||
| 1320 | let guard_str = match guardExp case SOME(g) then ' if <%dumpExp(g, context)%>' | ||
| 1321 | '<%range_str%><%guard_str%>' | ||
| 1322 | end dumpForIteratorRanges; | ||
| 1323 | |||
| 1324 | ✗ | template dumpForIteratorName(Absyn.ForIterator iterator, Context context) | |
| 1325 | ::= | ||
| 1326 | match iterator | ||
| 1327 | case ITERATOR(__) then | ||
| 1328 | '<%name%>' | ||
| 1329 | end dumpForIteratorName; | ||
| 1330 | |||
| 1331 | ✗ | template dumpOutputsJL(list<ElementItem> elements) | |
| 1332 | ::= | ||
| 1333 | let outputStr = (listReverse(elements) |> e => dumpTypeSpecOpt(AbsynUtil.getTypeSpecFromElementItemOpt(e), functionContext) ;separator=", ") | ||
| 1334 | '<%outputStr%>' | ||
| 1335 | end dumpOutputsJL; | ||
| 1336 | |||
| 1337 | annotation(__OpenModelica_Interface="backend_tools"); | ||
| 1338 | end AbsynToJulia; | ||
| 1339 |