Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 71.4% 15 / 0 / 21
Functions: -% 0 / 0 / 0
Branches: -% 0 / 0 / 0

OMCompiler/Compiler/Template/CodegenUtil.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 // This file defines util functions for templates for transforming Modelica/MetaModelica code to C like
37 // code. They are used in the code generator phase of the compiler to write
38 // target code.
39 //
40 // There are two root templates intended to be called from the code generator:
41 // translateModel and translateFunctions. These templates do not return any
42 // result but instead write the result to files. All other templates return
43 // text and are used by the root templates (most of them indirectly).
44 //
45 // To future maintainers of this file:
46 //
47 // - A line like this
48 // # var = "" /*BUFD*/
49 // declares a text buffer that you can later append text to. It can also be
50 // passed to other templates that in turn can append text to it. In the new
51 // version of Susan it should be written like this instead:
52 // let &var = buffer ""
53 //
54 // - A line like this
55 // ..., Text var /*BUFP*/, ...
56 // declares that a template takes a text buffer as input parameter. In the
57 // new version of Susan it should be written like this instead:
58 // ..., Text &var, ...
59 //
60 // - A line like this:
61 // ..., var /*BUFC*/, ...
62 // passes a text buffer to a template. In the new version of Susan it should
63 // be written like this instead:
64 // ..., &var, ...
65 //
66 // - Style guidelines:
67 //
68 // - Try (hard) to limit each row to 80 characters
69 //
70 // - Code for a template should be indented with 2 spaces
71 //
72 // - Exception to this rule is if you have only a single case, then that
73 // single case can be written using no indentation
74 //
75 // This single case can be seen as a clarification of the input to the
76 // template
77 //
78 // - Code after a case should be indented with 2 spaces if not written on the
79 // same line
80
81 package CodegenUtil
82
83 import interface SimCodeTV;
84 import ExpressionDumpTpl.*;
85
86 /* public */ template symbolName(String modelNamePrefix, String symbolName)
87 "Creates a unique name for the function"
88 ::=
89 modelNamePrefix + "_" + symbolName
90 end symbolName;
91
92 911798 template replaceDotAndUnderscore(String str)
93 "Replace _ with __ and dot in identifiers with _.
94 For quoted identifiers (those starting with a single quote) the dots are
95 part of the name itself (e.g. 'Modelica.Media.X') and must be sanitized by
96 unquoteIdentifier (-> _2E), not treated as path separators (-> _5F_5F).
97 Otherwise the generated name diverges from the record type name built by
98 AbsynUtil.pathStringUnquoteReplaceDot and the C code fails to compile. See #13009."
99 ::=
100 let str_dots = if stringEq(substring(str,1,1), "'") then str else System.stringReplace(str,".", "_")
101 let str_underscores = System.stringReplace(str_dots, "_", "__")
102 System.unquoteIdentifier(str_underscores)
103 end replaceDotAndUnderscore;
104
105 1404 template getGeneralTarget(String str)
106 ::=
107 match str
108 case "msvc10"
109 case "msvc12"
110 case "msvc13"
111 case "msvc15"
112 case "msvc19"
113 then "msvc"
114 else str
115 end getGeneralTarget;
116
117 693993 template underscorePath(Absyn.Path path)
118 "Generate paths with components separated by underscores.
119 Replaces also the . in identifiers with _.
120 The dot might happen for world.gravityAccleration"
121 ::=
122 match path
123 case QUALIFIED(__) then
124 '<%replaceDotAndUnderscore(name)%>_<%underscorePath(path)%>'
125 case IDENT(__) then
126 replaceDotAndUnderscore(name)
127 case FULLYQUALIFIED(__) then
128 underscorePath(path)
129 end underscorePath;
130
131 377012 template crefStr(ComponentRef cr)
132 "Generates the name of a variable for variable name array. Uses underscores for qualified names.
133 a._b not a.b"
134 ::=
135 match cr
136 case CREF_IDENT(__) then '<%System.unquoteIdentifier(ident)%><%subscriptsStr(subscriptLst)%>'
137 // Are these even needed? Function context should only have CREF_IDENT :)
138 case CREF_QUAL(ident = "$DER") then 'der(<%crefStr(componentRef)%>)'
139 case CREF_QUAL(ident = "$CLKPRE") then 'previous(<%crefStr(componentRef)%>)'
140 case CREF_QUAL(__) then '<%System.unquoteIdentifier(ident)%><%subscriptsStr(subscriptLst)%>._<%crefStr(componentRef)%>'
141 else "CREF_NOT_IDENT_OR_QUAL"
142 end crefStr;
143
144 2152382 template crefStrNoUnderscore(ComponentRef cr)
145 "Generates the name of a variable for variable name array.
146 However does not use underscores on qualified names.
147 a.b not a._b.
148
149 Used for generating variable names that are exported e.g. to xml files"
150 ::=
151 match cr
152 case CREF_IDENT(__) then
153 '<%ident%><%subscriptsStr(subscriptLst)%>'
154 case CREF_QUAL(ident = "$DER") then 'der(<%crefStrNoUnderscore(componentRef)%>)'
155 case CREF_QUAL(ident = "$CLKPRE") then 'previous(<%crefStrNoUnderscore(componentRef)%>)'
156 case CREF_QUAL(__) then '<%ident%><%subscriptsStr(subscriptLst)%>.<%crefStrNoUnderscore(componentRef)%>'
157 else "CREF_NOT_IDENT_OR_QUAL"
158 end crefStrNoUnderscore;
159
160 627900 template subscriptsStr(list<DAE.Subscript> subscripts)
161 "Generares subscript part of the name."
162 ::=
163 if subscripts then
164 '[<%subscripts |> s => subscriptStr(s) ;separator=","%>]'
165 end subscriptsStr;
166
167 ✗ template crefStrMatlabSafe(ComponentRef cr)
168 "Generates the name of a variable for variable name array. Used for linearization
169 to generate matlab safe variable names."
170 ::=
171 match cr
172 case CREF_IDENT(__) then '<%ident%><%subscriptsStrMatlabSafe(subscriptLst)%>'
173 case CREF_QUAL(ident = "$DER") then 'der_<%crefStrMatlabSafe(componentRef)%>'
174 case CREF_QUAL(ident = "$CLKPRE") then 'pre_<%crefStrMatlabSafe(componentRef)%>'
175 case CREF_QUAL(__) then '<%ident%><%subscriptsStrMatlabSafe(subscriptLst)%>_<%crefStrMatlabSafe(componentRef)%>'
176 else "CREF_NOT_IDENT_OR_QUAL"
177 end crefStrMatlabSafe;
178
179 ✗ template subscriptsStrMatlabSafe(list<DAE.Subscript> subscripts)
180 "Generares subscript part of the name for matlab safe variable names."
181 ::=
182 if subscripts then
183 '(<%subscripts |> s => subscriptStr(s) ;separator=","%>)'
184 end subscriptsStrMatlabSafe;
185
186 711975 template subscriptStr(DAE.Subscript subscript)
187 "Generates a single subscript.
188 Only works for constant integer and cref indicies."
189
190 ::=
191 match subscript
192 case INDEX(exp=ICONST(integer=i)) then i
193 case INDEX(exp=BCONST(bool=i)) then i
194 case INDEX(exp=ENUM_LITERAL(name=n)) then dotPath(n)
195 case INDEX(exp=CREF()) then printExpStr(exp)
196 case SLICE(exp=ICONST(integer=i)) then i
197 case INDEX(__)
198 case SLICE(__) then 'UNKNOWN_SUBSCRIPT /* <%escapeCComments(printExpStr(exp))%> */'
199 case WHOLEDIM(__) then "WHOLEDIM"
200 case WHOLE_NONEXP(__) then "WHOLE_NONEXP"
201 else "UNKNOWN_SUBSCRIPT"
202 end subscriptStr;
203
204 /*********************** Comments ************************/
205
206 1464753 template escapeCComments(String stringWithCComments)
207 "escape the C comments inside a string, replaces them with /* */->(* *)"
208 ::= '<%System.stringReplace(System.stringReplace(stringWithCComments, "/*", "(*"), "*/", "*)")%>'
209 end escapeCComments;
210
211 23364 template crefCComment(SimVar v, String vName)
212 "write the C comment for a cref, if it is not to be obfuscated"
213 ::=
214 match v
215 case SIMVAR(isProtected = true) then
216 if stringEq(getConfigString(OBFUSCATE), "none")
217 then '<%escapeCComments(vName)%>'
218 else 'OBFUSCATED'
219 case SIMVAR(__) then
220 if not stringEq(getConfigString(OBFUSCATE), "full")
221 then '<%escapeCComments(vName)%>'
222 else 'OBFUSCATED'
223 end crefCComment;
224
225 800052 template crefCCommentWithVariability(SimVar v)
226 "write the C comment for a cref with variability"
227 ::=
228 match v
229 case SIMVAR(isProtected = true) then
230 if stringEq(getConfigString(OBFUSCATE), "none")
231 then ' /* <%escapeCComments(crefStrNoUnderscore(name))%> <%variabilityString(varKind)%> */'
232 case SIMVAR(__) then
233 if not stringEq(getConfigString(OBFUSCATE), "full")
234 then ' /* <%escapeCComments(crefStrNoUnderscore(name))%> <%variabilityString(varKind)%> */'
235 end crefCCommentWithVariability;
236
237 /*********************************************************/
238
239 240 template escapeSingleQuoteIdent(String ident)
240 "Escape single quotes from quoted identifiers."
241 ::=
242 // TODO: How to replace "'" with "\'" but not "\'" with "\\'"?
243 '<%System.stringReplace(System.stringReplace(ident, "\\'", "\\\\'"), "'", "\\'")%>'
244 end escapeSingleQuoteIdent;
245
246 ✗ template initDefaultValXml(DAE.Type type_)
247 ::=
248 match type_
249 case T_INTEGER(__) then '0'
250 case T_REAL(__) then '0.0'
251 case T_BOOL(__) then 'false'
252 case T_STRING(__) then ''
253 case T_ENUMERATION(__) then '0'
254 else error(sourceInfo(), 'initial value of unknown type: <%unparseType(type_)%>')
255 end initDefaultValXml;
256
257 9859 template initValXml(Exp exp, String stringQuotes)
258 ::=
259 match exp
260 case ICONST(__) then integer
261 case RCONST(__) then real
262 case SCONST(__) then '<%stringQuotes%><%Util.escapeModelicaStringToXmlString(string)%><%stringQuotes%>'
263 case BCONST(__) then bool
264 case ARRAY(__) then '<%array |> elem => initValXml(elem, stringQuotes) ;separator=" "%>'
265 case REDUCTION(__) then if Expression.isSimpleLiteralValue(expr, true) then '<%initValXml(expr, stringQuotes)%>' else ''
266 case ENUM_LITERAL(__) then '<%index%>'
267 else error(sourceInfo(), 'initial value of unknown type: <%dumpExp(exp,"\"")%>')
268 end initValXml;
269
270 /*********************************************************************
271 *********************************************************************
272 * Common XML Functions
273 *********************************************************************
274 *********************************************************************/
275
276 7919 template getVariablity(BackendDAE.VarKind varKind)
277 "Returns the variablity Attribute of ScalarVariable."
278 ::=
279 match varKind
280 case DISCRETE(__) then "discrete"
281 case PARAM(__) then "parameter"
282 case CONST(__) then "constant"
283 else "continuous"
284 end getVariablity;
285
286 336730 template variabilityString(BackendDAE.VarKind varKind)
287 ::=
288 match varKind
289 case VARIABLE() then "variable"
290 case STATE(derName=NONE()) then 'STATE(<%index%>)'
291 case STATE(derName=SOME(dcr)) then 'STATE(<%index%>,<%crefStrNoUnderscore(dcr)%>)'
292 case STATE_DER() then "STATE_DER"
293 case DUMMY_DER() then "DUMMY_DER"
294 case DUMMY_STATE() then "DUMMY_STATE"
295 case CLOCKED_STATE() then "CLOCKED_STATE"
296 case DISCRETE() then "DISCRETE"
297 case PARAM() then "PARAM"
298 case CONST() then "CONST"
299 case EXTOBJ() then 'EXTOBJ: <%dotPath(fullClassName)%>'
300 case JAC_VAR() then "JACOBIAN_VAR"
301 case JAC_TMP_VAR() then "JACOBIAN_TMP_VAR"
302 case SEED_VAR() then "SEED_VAR"
303 case OPT_CONSTR() then "OPT_CONSTR"
304 case OPT_FCONSTR() then "OPT_FCONSTR"
305 case OPT_INPUT_WITH_DER() then "OPT_INPUT_WITH_DER"
306 case OPT_INPUT_DER() then "OPT_INPUT_DER"
307 case OPT_TGRID() then "OPT_TGRID"
308 case OPT_LOOP_INPUT() then "OPT_LOOP_INPUT"
309 case ALG_STATE() then "ALG_STATE"
310 case DAE_RESIDUAL_VAR() then "DAE_RESIDUAL_VAR"
311 case DAE_AUX_VAR() then "DAE_AUX_VAR"
312 case LOOP_ITERATION() then "LOOP_ITERATION"
313 case LOOP_SOLVED() then "LOOP_SOLVED"
314 else "#UNKNOWN_VARKIND"
315 end match
316 end variabilityString;
317
318 ✗ template getAliasVar(AliasVariable aliasvar)
319 "Returns the alias Attribute of ScalarVariable."
320 ::=
321 match aliasvar
322 case NOALIAS(__) then '"noAlias"'
323 case ALIAS(__) then '"alias" aliasVariable="<%crefStrNoUnderscore(varName)%>"'
324 case NEGATEDALIAS(__) then '"negatedAlias" aliasVariable="<%crefStrNoUnderscore(varName)%>"'
325 else '"noAlias"'
326 end getAliasVar;
327
328
329 /*********************************************************************
330 *********************************************************************
331 * Paths
332 *********************************************************************
333 *********************************************************************/
334
335 55705 template dotPath(Absyn.Path path)
336 "Generates paths with components separated by dots."
337 ::=
338 match path
339 case QUALIFIED(__) then '<%name%>.<%dotPath(path)%>'
340 case IDENT(__) then name
341 case FULLYQUALIFIED(__) then dotPath(path)
342 end dotPath;
343
344
345 /*********************************************************************
346 *********************************************************************
347 * Error
348 *********************************************************************
349 *********************************************************************/
350
351 ✗ template error(SourceInfo srcInfo, String errMessage)
352 "Example source template error reporting template to be used together with the sourceInfo() magic function.
353 Usage: error(sourceInfo(), <<message>>) "
354 ::=
355 let() = Tpl.addSourceTemplateError(errMessage, srcInfo)
356 <<
357
358 #error "<% Error.infoStr(srcInfo) %> <% errMessage %>"<%\n%>
359 >>
360 end error;
361
362 //for completeness; although the error() template above is preferable
363 ✗ template errorMsg(String errMessage)
364 "Example template error reporting template
365 that is reporting only the error message without the usage of source infotmation."
366 ::=
367 let() = Tpl.addTemplateError(errMessage)
368 <<
369
370 #error "<% errMessage %>"<%\n%>
371 >>
372 end errorMsg;
373
374 /* public */ template extFunctionName(String name, String language) "used in Compiler/Template/CodegenFMU.tpl"
375 ::=
376 match language
377 case "BUILTIN"
378 case "C" then '<%name%>'
379 case "FORTRAN 77" then '<%name%>_'
380 else error(sourceInfo(), 'Unsupported external language: <%language%>')
381 end extFunctionName;
382
383 annotation(__OpenModelica_Interface="codegen_util");
384 end CodegenUtil;
385
386 // vim: filetype=susan sw=2 sts=2
387