1import collections
2import warnings
3
4from sympy.external import import_module
5
6autolevparser = import_module('sympy.parsing.autolev._antlr.autolevparser',
7                              import_kwargs={'fromlist': ['AutolevParser']})
8autolevlexer = import_module('sympy.parsing.autolev._antlr.autolevlexer',
9                             import_kwargs={'fromlist': ['AutolevLexer']})
10autolevlistener = import_module('sympy.parsing.autolev._antlr.autolevlistener',
11                                import_kwargs={'fromlist': ['AutolevListener']})
12
13AutolevParser = getattr(autolevparser, 'AutolevParser', None)
14AutolevLexer = getattr(autolevlexer, 'AutolevLexer', None)
15AutolevListener = getattr(autolevlistener, 'AutolevListener', None)
16
17
18def strfunc(z):
19    if z == 0:
20        return ""
21    elif z == 1:
22        return "_d"
23    else:
24        return "_" + "d" * z
25
26def declare_phy_entities(self, ctx, phy_type, i, j=None):
27    if phy_type in ("frame", "newtonian"):
28        declare_frames(self, ctx, i, j)
29    elif phy_type == "particle":
30        declare_particles(self, ctx, i, j)
31    elif phy_type == "point":
32        declare_points(self, ctx, i, j)
33    elif phy_type == "bodies":
34        declare_bodies(self, ctx, i, j)
35
36def declare_frames(self, ctx, i, j=None):
37    if "{" in ctx.getText():
38        if j:
39            name1 = ctx.ID().getText().lower() + str(i) + str(j)
40        else:
41            name1 = ctx.ID().getText().lower() + str(i)
42    else:
43        name1 = ctx.ID().getText().lower()
44    name2 = "frame_" + name1
45    if self.getValue(ctx.parentCtx.varType()) == "newtonian":
46        self.newtonian = name2
47
48    self.symbol_table2.update({name1: name2})
49
50    self.symbol_table.update({name1 + "1>": name2 + ".x"})
51    self.symbol_table.update({name1 + "2>": name2 + ".y"})
52    self.symbol_table.update({name1 + "3>": name2 + ".z"})
53
54    self.type2.update({name1: "frame"})
55    self.write(name2 + " = " + "_me.ReferenceFrame('" + name1 + "')\n")
56
57def declare_points(self, ctx, i, j=None):
58    if "{" in ctx.getText():
59        if j:
60            name1 = ctx.ID().getText().lower() + str(i) + str(j)
61        else:
62            name1 = ctx.ID().getText().lower() + str(i)
63    else:
64        name1 = ctx.ID().getText().lower()
65
66    name2 = "point_" + name1
67
68    self.symbol_table2.update({name1: name2})
69    self.type2.update({name1: "point"})
70    self.write(name2 + " = " + "_me.Point('" + name1 + "')\n")
71
72def declare_particles(self, ctx, i, j=None):
73    if "{" in ctx.getText():
74        if j:
75            name1 = ctx.ID().getText().lower() + str(i) + str(j)
76        else:
77            name1 = ctx.ID().getText().lower() + str(i)
78    else:
79        name1 = ctx.ID().getText().lower()
80
81    name2 = "particle_" + name1
82
83    self.symbol_table2.update({name1: name2})
84    self.type2.update({name1: "particle"})
85    self.bodies.update({name1: name2})
86    self.write(name2 + " = " + "_me.Particle('" + name1 + "', " + "_me.Point('" +
87                name1 + "_pt" + "'), " + "_sm.Symbol('m'))\n")
88
89def declare_bodies(self, ctx, i, j=None):
90    if "{" in ctx.getText():
91        if j:
92            name1 = ctx.ID().getText().lower() + str(i) + str(j)
93        else:
94            name1 = ctx.ID().getText().lower() + str(i)
95    else:
96        name1 = ctx.ID().getText().lower()
97
98    name2 = "body_" + name1
99    self.bodies.update({name1: name2})
100    masscenter = name2 + "_cm"
101    refFrame = name2 + "_f"
102
103    self.symbol_table2.update({name1: name2})
104    self.symbol_table2.update({name1 + "o": masscenter})
105    self.symbol_table.update({name1 + "1>": refFrame+".x"})
106    self.symbol_table.update({name1 + "2>": refFrame+".y"})
107    self.symbol_table.update({name1 + "3>": refFrame+".z"})
108
109    self.type2.update({name1: "bodies"})
110    self.type2.update({name1+"o": "point"})
111
112    self.write(masscenter + " = " + "_me.Point('" + name1 + "_cm" + "')\n")
113    if self.newtonian:
114        self.write(masscenter + ".set_vel(" + self.newtonian + ", " + "0)\n")
115    self.write(refFrame + " = " + "_me.ReferenceFrame('" + name1 + "_f" + "')\n")
116    # We set a dummy mass and inertia here.
117    # They will be reset using the setters later in the code anyway.
118    self.write(name2 + " = " + "_me.RigidBody('" + name1 + "', " + masscenter + ", " +
119                refFrame + ", " + "_sm.symbols('m'), (_me.outer(" + refFrame +
120                ".x," + refFrame + ".x)," + masscenter + "))\n")
121
122def inertia_func(self, v1, v2, l, frame):
123
124    if self.type2[v1] == "particle":
125        l.append("_me.inertia_of_point_mass(" + self.bodies[v1] + ".mass, " + self.bodies[v1] +
126                 ".point.pos_from(" + self.symbol_table2[v2] + "), " + frame + ")")
127
128    elif self.type2[v1] == "bodies":
129        # Inertia has been defined about center of mass.
130        if self.inertia_point[v1] == v1 + "o":
131            # Asking point is cm as well
132            if v2 == self.inertia_point[v1]:
133                l.append(self.symbol_table2[v1] + ".inertia[0]")
134
135            # Asking point is not cm
136            else:
137                l.append(self.bodies[v1] + ".inertia[0]" + " + " +
138                         "_me.inertia_of_point_mass(" + self.bodies[v1] +
139                         ".mass, " + self.bodies[v1] + ".masscenter" +
140                         ".pos_from(" + self.symbol_table2[v2] +
141                         "), " + frame + ")")
142
143        # Inertia has been defined about another point
144        else:
145            # Asking point is the defined point
146            if v2 == self.inertia_point[v1]:
147                l.append(self.symbol_table2[v1] + ".inertia[0]")
148            # Asking point is cm
149            elif v2 == v1 + "o":
150                l.append(self.bodies[v1] + ".inertia[0]" + " - " +
151                         "_me.inertia_of_point_mass(" + self.bodies[v1] +
152                         ".mass, " + self.bodies[v1] + ".masscenter" +
153                         ".pos_from(" + self.symbol_table2[self.inertia_point[v1]] +
154                         "), " + frame + ")")
155            # Asking point is some other point
156            else:
157                l.append(self.bodies[v1] + ".inertia[0]" + " - " +
158                         "_me.inertia_of_point_mass(" + self.bodies[v1] +
159                         ".mass, " + self.bodies[v1] + ".masscenter" +
160                         ".pos_from(" + self.symbol_table2[self.inertia_point[v1]] +
161                         "), " + frame + ")" + " + " +
162                         "_me.inertia_of_point_mass(" + self.bodies[v1] +
163                         ".mass, " + self.bodies[v1] + ".masscenter" +
164                         ".pos_from(" + self.symbol_table2[v2] +
165                         "), " + frame + ")")
166
167
168def processConstants(self, ctx):
169    # Process constant declarations of the type: Constants F = 3, g = 9.81
170    name = ctx.ID().getText().lower()
171    if "=" in ctx.getText():
172        self.symbol_table.update({name: name})
173        # self.inputs.update({self.symbol_table[name]: self.getValue(ctx.getChild(2))})
174        self.write(self.symbol_table[name] + " = " + "_sm.S(" + self.getValue(ctx.getChild(2)) + ")\n")
175        self.type.update({name: "constants"})
176        return
177
178    # Constants declarations of the type: Constants A, B
179    else:
180        if "{" not in ctx.getText():
181            self.symbol_table[name] = name
182            self.type[name] = "constants"
183
184    # Process constant declarations of the type: Constants C+, D-
185    if ctx.getChildCount() == 2:
186        # This is set for declaring nonpositive=True and nonnegative=True
187        if ctx.getChild(1).getText() == "+":
188            self.sign[name] = "+"
189        elif ctx.getChild(1).getText() == "-":
190            self.sign[name] = "-"
191    else:
192        if "{" not in ctx.getText():
193            self.sign[name] = "o"
194
195    # Process constant declarations of the type: Constants K{4}, a{1:2, 1:2}, b{1:2}
196    if "{" in ctx.getText():
197        if ":" in ctx.getText():
198            num1 = int(ctx.INT(0).getText())
199            num2 = int(ctx.INT(1).getText()) + 1
200        else:
201            num1 = 1
202            num2 = int(ctx.INT(0).getText()) + 1
203
204        if ":" in ctx.getText():
205            if "," in ctx.getText():
206                num3 = int(ctx.INT(2).getText())
207                num4 = int(ctx.INT(3).getText()) + 1
208                for i in range(num1, num2):
209                    for j in range(num3, num4):
210                        self.symbol_table[name + str(i) + str(j)] = name + str(i) + str(j)
211                        self.type[name + str(i) + str(j)] = "constants"
212                        self.var_list.append(name + str(i) + str(j))
213                        self.sign[name + str(i) + str(j)] = "o"
214            else:
215                for i in range(num1, num2):
216                    self.symbol_table[name + str(i)] = name + str(i)
217                    self.type[name + str(i)] = "constants"
218                    self.var_list.append(name + str(i))
219                    self.sign[name + str(i)] = "o"
220
221        elif "," in ctx.getText():
222            for i in range(1, int(ctx.INT(0).getText()) + 1):
223                for j in range(1, int(ctx.INT(1).getText()) + 1):
224                    self.symbol_table[name] = name + str(i) + str(j)
225                    self.type[name + str(i) + str(j)] = "constants"
226                    self.var_list.append(name + str(i) + str(j))
227                    self.sign[name + str(i) + str(j)] = "o"
228
229        else:
230            for i in range(num1, num2):
231                self.symbol_table[name + str(i)] = name + str(i)
232                self.type[name + str(i)] = "constants"
233                self.var_list.append(name + str(i))
234                self.sign[name + str(i)] = "o"
235
236    if "{" not in ctx.getText():
237        self.var_list.append(name)
238
239
240def writeConstants(self, ctx):
241    l1 = list(filter(lambda x: self.sign[x] == "o", self.var_list))
242    l2 = list(filter(lambda x: self.sign[x] == "+", self.var_list))
243    l3 = list(filter(lambda x: self.sign[x] == "-", self.var_list))
244    try:
245        if self.settings["complex"] == "on":
246            real = ", real=True"
247        elif self.settings["complex"] == "off":
248            real = ""
249    except Exception:
250        real = ", real=True"
251
252    if l1:
253        a = ", ".join(l1) + " = " + "_sm.symbols(" + "'" +\
254            " ".join(l1) + "'" + real + ")\n"
255        self.write(a)
256    if l2:
257        a = ", ".join(l2) + " = " + "_sm.symbols(" + "'" +\
258            " ".join(l2) + "'" + real + ", nonnegative=True)\n"
259        self.write(a)
260    if l3:
261        a = ", ".join(l3) + " = " + "_sm.symbols(" + "'" + \
262            " ".join(l3) + "'" + real + ", nonpositive=True)\n"
263        self.write(a)
264    self.var_list = []
265
266
267def processVariables(self, ctx):
268    # Specified F = x*N1> + y*N2>
269    name = ctx.ID().getText().lower()
270    if "=" in ctx.getText():
271        text = name + "'"*(ctx.getChildCount()-3)
272        self.write(text + " = " + self.getValue(ctx.expr()) + "\n")
273        return
274
275    # Process variables of the type: Variables qA, qB
276    if ctx.getChildCount() == 1:
277        self.symbol_table[name] = name
278        if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"):
279            self.type.update({name: self.getValue(ctx.parentCtx.getChild(0))})
280
281        self.var_list.append(name)
282        self.sign[name] = 0
283
284    # Process variables of the type: Variables x', y''
285    elif "'" in ctx.getText() and "{" not in ctx.getText():
286        if ctx.getText().count("'") > self.maxDegree:
287            self.maxDegree = ctx.getText().count("'")
288        for i in range(ctx.getChildCount()):
289            self.sign[name + strfunc(i)] = i
290            self.symbol_table[name + "'"*i] = name + strfunc(i)
291            if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"):
292                self.type.update({name + "'"*i: self.getValue(ctx.parentCtx.getChild(0))})
293            self.var_list.append(name + strfunc(i))
294
295    elif "{" in ctx.getText():
296        # Process variables of the type: Variales x{3}, y{2}
297
298        if "'" in ctx.getText():
299            dash_count = ctx.getText().count("'")
300            if dash_count > self.maxDegree:
301                self.maxDegree = dash_count
302
303        if ":" in ctx.getText():
304            # Variables C{1:2, 1:2}
305            if "," in ctx.getText():
306                num1 = int(ctx.INT(0).getText())
307                num2 = int(ctx.INT(1).getText()) + 1
308                num3 = int(ctx.INT(2).getText())
309                num4 = int(ctx.INT(3).getText()) + 1
310            # Variables C{1:2}
311            else:
312                num1 = int(ctx.INT(0).getText())
313                num2 = int(ctx.INT(1).getText()) + 1
314
315        # Variables C{1,3}
316        elif "," in ctx.getText():
317            num1 = 1
318            num2 = int(ctx.INT(0).getText()) + 1
319            num3 = 1
320            num4 = int(ctx.INT(1).getText()) + 1
321        else:
322            num1 = 1
323            num2 = int(ctx.INT(0).getText()) + 1
324
325        for i in range(num1, num2):
326            try:
327                for j in range(num3, num4):
328                    try:
329                        for z in range(dash_count+1):
330                            self.symbol_table.update({name + str(i) + str(j) + "'"*z: name + str(i) + str(j) + strfunc(z)})
331                            if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"):
332                                self.type.update({name + str(i) + str(j) +  "'"*z: self.getValue(ctx.parentCtx.getChild(0))})
333                            self.var_list.append(name + str(i) + str(j) + strfunc(z))
334                            self.sign.update({name + str(i) + str(j) + strfunc(z): z})
335                            if dash_count > self.maxDegree:
336                                self.maxDegree = dash_count
337                    except Exception:
338                        self.symbol_table.update({name + str(i) + str(j): name + str(i) + str(j)})
339                        if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"):
340                            self.type.update({name + str(i) + str(j): self.getValue(ctx.parentCtx.getChild(0))})
341                        self.var_list.append(name + str(i) + str(j))
342                        self.sign.update({name + str(i) + str(j): 0})
343            except Exception:
344                try:
345                    for z in range(dash_count+1):
346                        self.symbol_table.update({name + str(i) + "'"*z: name + str(i) + strfunc(z)})
347                        if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"):
348                            self.type.update({name + str(i) +  "'"*z: self.getValue(ctx.parentCtx.getChild(0))})
349                        self.var_list.append(name + str(i) + strfunc(z))
350                        self.sign.update({name + str(i) + strfunc(z): z})
351                        if dash_count > self.maxDegree:
352                            self.maxDegree = dash_count
353                except Exception:
354                    self.symbol_table.update({name + str(i): name + str(i)})
355                    if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"):
356                        self.type.update({name + str(i): self.getValue(ctx.parentCtx.getChild(0))})
357                    self.var_list.append(name + str(i))
358                    self.sign.update({name + str(i): 0})
359
360def writeVariables(self, ctx):
361    #print(self.sign)
362    #print(self.symbol_table)
363    if self.var_list:
364        for i in range(self.maxDegree+1):
365            if i == 0:
366                j = ""
367                t = ""
368            else:
369                j = str(i)
370                t = ", "
371            l = []
372            for k in list(filter(lambda x: self.sign[x] == i, self.var_list)):
373                if i == 0:
374                    l.append(k)
375                if i == 1:
376                    l.append(k[:-1])
377                if i > 1:
378                    l.append(k[:-2])
379            a = ", ".join(list(filter(lambda x: self.sign[x] == i, self.var_list))) + " = " +\
380                "_me.dynamicsymbols(" + "'" + " ".join(l) + "'" + t + j + ")\n"
381            l = []
382            self.write(a)
383        self.maxDegree = 0
384    self.var_list = []
385
386def processImaginary(self, ctx):
387    name = ctx.ID().getText().lower()
388    self.symbol_table[name] = name
389    self.type[name] = "imaginary"
390    self.var_list.append(name)
391
392
393def writeImaginary(self, ctx):
394    a = ", ".join(self.var_list) + " = " + "_sm.symbols(" + "'" + \
395        " ".join(self.var_list) + "')\n"
396    b = ", ".join(self.var_list) + " = " + "_sm.I\n"
397    self.write(a)
398    self.write(b)
399    self.var_list = []
400
401if AutolevListener:
402    class MyListener(AutolevListener):  # type: ignore
403        def __init__(self, include_numeric=False):
404            # Stores data in tree nodes(tree annotation). Especially useful for expr reconstruction.
405            self.tree_property = {}
406
407            # Stores the declared variables, constants etc as they are declared in Autolev and SymPy
408            # {"<Autolev symbol>": "<SymPy symbol>"}.
409            self.symbol_table = collections.OrderedDict()
410
411            # Similar to symbol_table. Used for storing Physical entities like Frames, Points,
412            # Particles, Bodies etc
413            self.symbol_table2 = collections.OrderedDict()
414
415            # Used to store nonpositive, nonnegative etc for constants and number of "'"s (order of diff)
416            # in variables.
417            self.sign = {}
418
419            # Simple list used as a store to pass around variables between the 'process' and 'write'
420            # methods.
421            self.var_list = []
422
423            # Stores the type of a declared variable (constants, variables, specifieds etc)
424            self.type = collections.OrderedDict()
425
426            # Similar to self.type. Used for storing the type of Physical entities like Frames, Points,
427            # Particles, Bodies etc
428            self.type2 = collections.OrderedDict()
429
430            # These lists are used to distinguish matrix, numeric and vector expressions.
431            self.matrix_expr = []
432            self.numeric_expr = []
433            self.vector_expr = []
434            self.fr_expr = []
435
436            self.output_code = []
437
438            # Stores the variables and their rhs for substituting upon the Autolev command EXPLICIT.
439            self.explicit = collections.OrderedDict()
440
441            # Write code to import common dependencies.
442            self.output_code.append("import sympy.physics.mechanics as _me\n")
443            self.output_code.append("import sympy as _sm\n")
444            self.output_code.append("import math as m\n")
445            self.output_code.append("import numpy as _np\n")
446            self.output_code.append("\n")
447
448            # Just a store for the max degree variable in a line.
449            self.maxDegree = 0
450
451            # Stores the input parameters which are then used for codegen and numerical analysis.
452            self.inputs = collections.OrderedDict()
453            # Stores the variables which appear in Output Autolev commands.
454            self.outputs = []
455            # Stores the settings specified by the user. Ex: Complex on/off, Degrees on/off
456            self.settings = {}
457            # Boolean which changes the behaviour of some expression reconstruction
458            # when parsing Input Autolev commands.
459            self.in_inputs = False
460            self.in_outputs = False
461
462            # Stores for the physical entities.
463            self.newtonian = None
464            self.bodies = collections.OrderedDict()
465            self.constants = []
466            self.forces = collections.OrderedDict()
467            self.q_ind = []
468            self.q_dep = []
469            self.u_ind = []
470            self.u_dep = []
471            self.kd_eqs = []
472            self.dependent_variables = []
473            self.kd_equivalents = collections.OrderedDict()
474            self.kd_equivalents2 = collections.OrderedDict()
475            self.kd_eqs_supplied = None
476            self.kane_type = "no_args"
477            self.inertia_point = collections.OrderedDict()
478            self.kane_parsed = False
479            self.t = False
480
481            # PyDy ode code will be included only if this flag is set to True.
482            self.include_numeric = include_numeric
483
484        def write(self, string):
485            self.output_code.append(string)
486
487        def getValue(self, node):
488            return self.tree_property[node]
489
490        def setValue(self, node, value):
491            self.tree_property[node] = value
492
493        def getSymbolTable(self):
494            return self.symbol_table
495
496        def getType(self):
497            return self.type
498
499        def exitVarDecl(self, ctx):
500            # This event method handles variable declarations. The parse tree node varDecl contains
501            # one or more varDecl2 nodes. Eg varDecl for 'Constants a{1:2, 1:2}, b{1:2}' has two varDecl2
502            # nodes(one for a{1:2, 1:2} and one for b{1:2}).
503
504            # Variable declarations are processed and stored in the event method exitVarDecl2.
505            # This stored information is used to write the final SymPy output code in the exitVarDecl event method.
506
507            # determine the type of declaration
508            if self.getValue(ctx.varType()) == "constant":
509                writeConstants(self, ctx)
510            elif self.getValue(ctx.varType()) in\
511            ("variable", "motionvariable", "motionvariable'", "specified"):
512                writeVariables(self, ctx)
513            elif self.getValue(ctx.varType()) == "imaginary":
514                writeImaginary(self, ctx)
515
516        def exitVarType(self, ctx):
517            # Annotate the varType tree node with the type of the variable declaration.
518            name = ctx.getChild(0).getText().lower()
519            if name[-1] == "s" and name != "bodies":
520                self.setValue(ctx, name[:-1])
521            else:
522                self.setValue(ctx, name)
523
524        def exitVarDecl2(self, ctx):
525            # Variable declarations are processed and stored in the event method exitVarDecl2.
526            # This stored information is used to write the final SymPy output code in the exitVarDecl event method.
527            # This is the case for constants, variables, specifieds etc.
528
529            # This isn't the case for all types of declarations though. For instance
530            # Frames A, B, C, N cannot be defined on one line in SymPy. So we do not append A, B, C, N
531            # to a var_list or use exitVarDecl. exitVarDecl2 directly writes out to the file.
532
533            # determine the type of declaration
534            if self.getValue(ctx.parentCtx.varType()) == "constant":
535                processConstants(self, ctx)
536
537            elif self.getValue(ctx.parentCtx.varType()) in \
538            ("variable", "motionvariable", "motionvariable'", "specified"):
539                processVariables(self, ctx)
540
541            elif self.getValue(ctx.parentCtx.varType()) == "imaginary":
542                processImaginary(self, ctx)
543
544            elif self.getValue(ctx.parentCtx.varType()) in ("frame", "newtonian", "point", "particle", "bodies"):
545                if "{" in ctx.getText():
546                    if ":" in ctx.getText() and "," not in ctx.getText():
547                        num1 = int(ctx.INT(0).getText())
548                        num2 = int(ctx.INT(1).getText()) + 1
549                    elif ":" not in ctx.getText() and "," in ctx.getText():
550                        num1 = 1
551                        num2 = int(ctx.INT(0).getText()) + 1
552                        num3 = 1
553                        num4 = int(ctx.INT(1).getText()) + 1
554                    elif ":" in ctx.getText() and "," in ctx.getText():
555                        num1 = int(ctx.INT(0).getText())
556                        num2 = int(ctx.INT(1).getText()) + 1
557                        num3 = int(ctx.INT(2).getText())
558                        num4 = int(ctx.INT(3).getText()) + 1
559                    else:
560                        num1 = 1
561                        num2 = int(ctx.INT(0).getText()) + 1
562                else:
563                    num1 = 1
564                    num2 = 2
565                for i in range(num1, num2):
566                    try:
567                        for j in range(num3, num4):
568                            declare_phy_entities(self, ctx, self.getValue(ctx.parentCtx.varType()), i, j)
569                    except Exception:
570                       declare_phy_entities(self, ctx, self.getValue(ctx.parentCtx.varType()), i)
571        # ================== Subrules of parser rule expr (Start) ====================== #
572
573        def exitId(self, ctx):
574            # Tree annotation for ID which is a labeled subrule of the parser rule expr.
575            # A_C
576            python_keywords = ["and", "as", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except",\
577            "exec", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "not", "or", "pass", "print",\
578            "raise", "return", "try", "while", "with", "yield"]
579
580            if ctx.ID().getText().lower() in python_keywords:
581                warnings.warn("Python keywords must not be used as identifiers. Please refer to the list of keywords at https://docs.python.org/2.5/ref/keywords.html",
582                SyntaxWarning)
583
584            if "_" in ctx.ID().getText() and ctx.ID().getText().count('_') == 1:
585                e1, e2 = ctx.ID().getText().lower().split('_')
586                try:
587                    if self.type2[e1] == "frame":
588                        e1 = self.symbol_table2[e1]
589                    elif self.type2[e1] == "bodies":
590                        e1 = self.symbol_table2[e1] + "_f"
591                    if self.type2[e2] == "frame":
592                        e2 = self.symbol_table2[e2]
593                    elif self.type2[e2] == "bodies":
594                        e2 = self.symbol_table2[e2] + "_f"
595
596                    self.setValue(ctx, e1 + ".dcm(" + e2 + ")")
597                except Exception:
598                    self.setValue(ctx, ctx.ID().getText().lower())
599            else:
600                # Reserved constant Pi
601                if ctx.ID().getText().lower() == "pi":
602                    self.setValue(ctx, "_sm.pi")
603                    self.numeric_expr.append(ctx)
604
605                # Reserved variable T (for time)
606                elif ctx.ID().getText().lower() == "t":
607                    self.setValue(ctx, "_me.dynamicsymbols._t")
608                    if not self.in_inputs and not self.in_outputs:
609                        self.t = True
610
611                else:
612                    idText = ctx.ID().getText().lower() + "'"*(ctx.getChildCount() - 1)
613                    if idText in self.type.keys() and self.type[idText] == "matrix":
614                        self.matrix_expr.append(ctx)
615                    if self.in_inputs:
616                        try:
617                            self.setValue(ctx, self.symbol_table[idText])
618                        except Exception:
619                            self.setValue(ctx, idText.lower())
620                    else:
621                        try:
622                            self.setValue(ctx, self.symbol_table[idText])
623                        except Exception:
624                            pass
625
626        def exitInt(self, ctx):
627            # Tree annotation for int which is a labeled subrule of the parser rule expr.
628            int_text = ctx.INT().getText()
629            self.setValue(ctx, int_text)
630            self.numeric_expr.append(ctx)
631
632        def exitFloat(self, ctx):
633            # Tree annotation for float which is a labeled subrule of the parser rule expr.
634            floatText = ctx.FLOAT().getText()
635            self.setValue(ctx, floatText)
636            self.numeric_expr.append(ctx)
637
638        def exitAddSub(self, ctx):
639            # Tree annotation for AddSub which is a labeled subrule of the parser rule expr.
640            # The subrule is expr = expr (+|-) expr
641            if ctx.expr(0) in self.matrix_expr or ctx.expr(1) in self.matrix_expr:
642                self.matrix_expr.append(ctx)
643            if ctx.expr(0) in self.vector_expr or ctx.expr(1) in self.vector_expr:
644                self.vector_expr.append(ctx)
645            if ctx.expr(0) in self.numeric_expr and ctx.expr(1) in self.numeric_expr:
646                self.numeric_expr.append(ctx)
647            self.setValue(ctx, self.getValue(ctx.expr(0)) + ctx.getChild(1).getText() +
648                          self.getValue(ctx.expr(1)))
649
650        def exitMulDiv(self, ctx):
651            # Tree annotation for MulDiv which is a labeled subrule of the parser rule expr.
652            # The subrule is expr = expr (*|/) expr
653            try:
654                if ctx.expr(0) in self.vector_expr and ctx.expr(1) in self.vector_expr:
655                    self.setValue(ctx, "_me.outer(" + self.getValue(ctx.expr(0)) + ", " +
656                                  self.getValue(ctx.expr(1)) + ")")
657                else:
658                    if ctx.expr(0) in self.matrix_expr or ctx.expr(1) in self.matrix_expr:
659                        self.matrix_expr.append(ctx)
660                    if ctx.expr(0) in self.vector_expr or ctx.expr(1) in self.vector_expr:
661                        self.vector_expr.append(ctx)
662                    if ctx.expr(0) in self.numeric_expr and ctx.expr(1) in self.numeric_expr:
663                        self.numeric_expr.append(ctx)
664                    self.setValue(ctx, self.getValue(ctx.expr(0)) + ctx.getChild(1).getText() +
665                                  self.getValue(ctx.expr(1)))
666            except Exception:
667                pass
668
669        def exitNegativeOne(self, ctx):
670            # Tree annotation for negativeOne which is a labeled subrule of the parser rule expr.
671            self.setValue(ctx, "-1*" + self.getValue(ctx.getChild(1)))
672            if ctx.getChild(1) in self.matrix_expr:
673                self.matrix_expr.append(ctx)
674            if ctx.getChild(1) in self.numeric_expr:
675                self.numeric_expr.append(ctx)
676
677        def exitParens(self, ctx):
678            # Tree annotation for parens which is a labeled subrule of the parser rule expr.
679            # The subrule is expr = '(' expr ')'
680            if ctx.expr() in self.matrix_expr:
681                self.matrix_expr.append(ctx)
682            if ctx.expr() in self.vector_expr:
683                self.vector_expr.append(ctx)
684            if ctx.expr() in self.numeric_expr:
685                self.numeric_expr.append(ctx)
686            self.setValue(ctx, "(" + self.getValue(ctx.expr()) + ")")
687
688        def exitExponent(self, ctx):
689            # Tree annotation for Exponent which is a labeled subrule of the parser rule expr.
690            # The subrule is expr = expr ^ expr
691            if ctx.expr(0) in self.matrix_expr or ctx.expr(1) in self.matrix_expr:
692                self.matrix_expr.append(ctx)
693            if ctx.expr(0) in self.vector_expr or ctx.expr(1) in self.vector_expr:
694                self.vector_expr.append(ctx)
695            if ctx.expr(0) in self.numeric_expr and ctx.expr(1) in self.numeric_expr:
696                self.numeric_expr.append(ctx)
697            self.setValue(ctx, self.getValue(ctx.expr(0)) + "**" + self.getValue(ctx.expr(1)))
698
699        def exitExp(self, ctx):
700            s = ctx.EXP().getText()[ctx.EXP().getText().index('E')+1:]
701            if "-" in s:
702                s = s[0] + s[1:].lstrip("0")
703            else:
704                s = s.lstrip("0")
705            self.setValue(ctx, ctx.EXP().getText()[:ctx.EXP().getText().index('E')] +
706                          "*10**(" + s + ")")
707
708        def exitFunction(self, ctx):
709            # Tree annotation for function which is a labeled subrule of the parser rule expr.
710
711            # The difference between this and FunctionCall is that this is used for non standalone functions
712            # appearing in expressions and assignments.
713            # Eg:
714            # When we come across a standalone function say Expand(E, n:m) then it is categorized as FunctionCall
715            # which is a parser rule in itself under rule stat. exitFunctionCall() takes care of it and writes to the file.
716            #
717            # On the other hand, while we come across E_diff = D(E, y), we annotate the tree node
718            # of the function D(E, y) with the SymPy equivalent in exitFunction().
719            # In this case it is the method exitAssignment() that writes the code to the file and not exitFunction().
720
721            ch = ctx.getChild(0)
722            func_name = ch.getChild(0).getText().lower()
723
724            # Expand(y, n:m) *
725            if func_name == "expand":
726                expr = self.getValue(ch.expr(0))
727                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
728                    self.matrix_expr.append(ctx)
729                    # _sm.Matrix([i.expand() for i in z]).reshape(z.shape[0], z.shape[1])
730                    self.setValue(ctx, "_sm.Matrix([i.expand() for i in " + expr + "])" +
731                                  ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])")
732                else:
733                    self.setValue(ctx, "(" + expr + ")" + "." + "expand()")
734
735            # Factor(y, x) *
736            elif func_name == "factor":
737                expr = self.getValue(ch.expr(0))
738                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
739                    self.matrix_expr.append(ctx)
740                    self.setValue(ctx, "_sm.Matrix([_sm.factor(i, " + self.getValue(ch.expr(1)) + ") for i in " +
741                                  expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])")
742                else:
743                    self.setValue(ctx, "_sm.factor(" + "(" + expr + ")" +
744                                  ", " + self.getValue(ch.expr(1)) + ")")
745
746            # D(y, x)
747            elif func_name == "d":
748                expr = self.getValue(ch.expr(0))
749                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
750                    self.matrix_expr.append(ctx)
751                    self.setValue(ctx, "_sm.Matrix([i.diff(" + self.getValue(ch.expr(1)) + ") for i in " +
752                                  expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])")
753                else:
754                    if ch.getChildCount() == 8:
755                        frame = self.symbol_table2[ch.expr(2).getText().lower()]
756                        self.setValue(ctx, "(" + expr + ")" + "." + "diff(" + self.getValue(ch.expr(1)) +
757                                      ", " + frame + ")")
758                    else:
759                        self.setValue(ctx, "(" + expr + ")" + "." + "diff(" +
760                                      self.getValue(ch.expr(1)) + ")")
761
762            # Dt(y)
763            elif func_name == "dt":
764                expr = self.getValue(ch.expr(0))
765                if ch.expr(0) in self.vector_expr:
766                    text = "dt("
767                else:
768                    text = "diff(_sm.Symbol('t')"
769                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
770                    self.matrix_expr.append(ctx)
771                    self.setValue(ctx, "_sm.Matrix([i." + text +
772                                  ") for i in " + expr + "])" +
773                                  ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])")
774                else:
775                    if ch.getChildCount() == 6:
776                        frame = self.symbol_table2[ch.expr(1).getText().lower()]
777                        self.setValue(ctx, "(" + expr + ")" + "." + "dt(" +
778                                      frame + ")")
779                    else:
780                        self.setValue(ctx, "(" + expr + ")" + "." + text + ")")
781
782            # Explicit(EXPRESS(IMPLICIT>,C))
783            elif func_name == "explicit":
784                if ch.expr(0) in self.vector_expr:
785                    self.vector_expr.append(ctx)
786                expr = self.getValue(ch.expr(0))
787                if self.explicit.keys():
788                    explicit_list = []
789                    for i in self.explicit.keys():
790                        explicit_list.append(i + ":" + self.explicit[i])
791                    self.setValue(ctx, "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "})")
792                else:
793                    self.setValue(ctx, expr)
794
795            # Taylor(y, 0:2, w=a, x=0)
796            # TODO: Currently only works with symbols. Make it work for dynamicsymbols.
797            elif func_name == "taylor":
798                exp = self.getValue(ch.expr(0))
799                order = self.getValue(ch.expr(1).expr(1))
800                x = (ch.getChildCount()-6)//2
801                l = []
802                for i in range(x):
803                    index = 2 + i
804                    child = ch.expr(index)
805                    l.append(".series(" + self.getValue(child.getChild(0)) +
806                             ", " + self.getValue(child.getChild(2)) +
807                             ", " + order + ").removeO()")
808                self.setValue(ctx, "(" + exp + ")" + "".join(l))
809
810            # Evaluate(y, a=x, b=2)
811            elif func_name == "evaluate":
812                expr = self.getValue(ch.expr(0))
813                l = []
814                x = (ch.getChildCount()-4)//2
815                for i in range(x):
816                    index = 1 + i
817                    child = ch.expr(index)
818                    l.append(self.getValue(child.getChild(0)) + ":" +
819                             self.getValue(child.getChild(2)))
820
821                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
822                    self.matrix_expr.append(ctx)
823                    self.setValue(ctx, "_sm.Matrix([i.subs({" + ",".join(l) + "}) for i in " +
824                                  expr + "])" +
825                                  ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])")
826                else:
827                    if self.explicit:
828                        explicit_list = []
829                        for i in self.explicit.keys():
830                            explicit_list.append(i + ":" + self.explicit[i])
831                        self.setValue(ctx, "(" + expr + ")" + ".subs({" + ",".join(explicit_list) +
832                                      "}).subs({" + ",".join(l) + "})")
833                    else:
834                        self.setValue(ctx, "(" + expr + ")" + ".subs({" + ",".join(l) + "})")
835
836            # Polynomial([a, b, c], x)
837            elif func_name == "polynomial":
838                self.setValue(ctx, "_sm.Poly(" + self.getValue(ch.expr(0)) + ", " +
839                              self.getValue(ch.expr(1)) + ")")
840
841            # Roots(Poly, x, 2)
842            # Roots([1; 2; 3; 4])
843            elif func_name == "roots":
844                self.matrix_expr.append(ctx)
845                expr = self.getValue(ch.expr(0))
846                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
847                    self.setValue(ctx, "[i.evalf() for i in " + "_sm.solve(" +
848                                  "_sm.Poly(" + expr + ", " + "x),x)]")
849                else:
850                    self.setValue(ctx, "[i.evalf() for i in " + "_sm.solve(" +
851                                  expr + ", " + self.getValue(ch.expr(1)) + ")]")
852
853            # Transpose(A), Inv(A)
854            elif func_name in ("transpose", "inv", "inverse"):
855                self.matrix_expr.append(ctx)
856                if func_name == "transpose":
857                    e = ".T"
858                elif func_name in ("inv", "inverse"):
859                    e = "**(-1)"
860                self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + e)
861
862            # Eig(A)
863            elif func_name == "eig":
864                # "_sm.Matrix([i.evalf() for i in " +
865                self.setValue(ctx, "_sm.Matrix([i.evalf() for i in (" +
866                              self.getValue(ch.expr(0)) + ").eigenvals().keys()])")
867
868            # Diagmat(n, m, x)
869            # Diagmat(3, 1)
870            elif func_name == "diagmat":
871                self.matrix_expr.append(ctx)
872                if ch.getChildCount() == 6:
873                    l = []
874                    for i in range(int(self.getValue(ch.expr(0)))):
875                        l.append(self.getValue(ch.expr(1)) + ",")
876
877                    self.setValue(ctx, "_sm.diag(" + ("".join(l))[:-1] + ")")
878
879                elif ch.getChildCount() == 8:
880                    # _sm.Matrix([x if i==j else 0 for i in range(n) for j in range(m)]).reshape(n, m)
881                    n = self.getValue(ch.expr(0))
882                    m = self.getValue(ch.expr(1))
883                    x = self.getValue(ch.expr(2))
884                    self.setValue(ctx, "_sm.Matrix([" + x + " if i==j else 0 for i in range(" +
885                                  n + ") for j in range(" + m + ")]).reshape(" + n + ", " + m + ")")
886
887            # Cols(A)
888            # Cols(A, 1)
889            # Cols(A, 1, 2:4, 3)
890            elif func_name in ("cols", "rows"):
891                self.matrix_expr.append(ctx)
892                if func_name == "cols":
893                    e1 = ".cols"
894                    e2 = ".T."
895                else:
896                    e1 = ".rows"
897                    e2 = "."
898                if ch.getChildCount() == 4:
899                    self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + e1)
900                elif ch.getChildCount() == 6:
901                    self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" +
902                                  e1[:-1] + "(" + str(int(self.getValue(ch.expr(1))) - 1) + ")")
903                else:
904                    l = []
905                    for i in range(4, ch.getChildCount()):
906                        try:
907                            if ch.getChild(i).getChildCount() > 1 and ch.getChild(i).getChild(1).getText() == ":":
908                                for j in range(int(ch.getChild(i).getChild(0).getText()),
909                                int(ch.getChild(i).getChild(2).getText())+1):
910                                    l.append("(" + self.getValue(ch.getChild(2)) + ")" + e2 +
911                                             "row(" + str(j-1) + ")")
912                            else:
913                                l.append("(" + self.getValue(ch.getChild(2)) + ")" + e2 +
914                                         "row(" + str(int(ch.getChild(i).getText())-1) + ")")
915                        except Exception:
916                            pass
917                    self.setValue(ctx, "_sm.Matrix([" + ",".join(l) + "])")
918
919            # Det(A) Trace(A)
920            elif func_name in ["det", "trace"]:
921                self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + "." +
922                              func_name + "()")
923
924            # Element(A, 2, 3)
925            elif func_name == "element":
926                self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + "[" +
927                              str(int(self.getValue(ch.expr(1)))-1) + "," +
928                              str(int(self.getValue(ch.expr(2)))-1) + "]")
929
930            elif func_name in \
931            ["cos", "sin", "tan", "cosh", "sinh", "tanh", "acos", "asin", "atan",
932            "log", "exp", "sqrt", "factorial", "floor", "sign"]:
933                self.setValue(ctx, "_sm." + func_name + "(" + self.getValue(ch.expr(0)) + ")")
934
935            elif func_name == "ceil":
936                self.setValue(ctx, "_sm.ceiling" + "(" + self.getValue(ch.expr(0)) + ")")
937
938            elif func_name == "sqr":
939                self.setValue(ctx, "(" + self.getValue(ch.expr(0)) +
940                              ")" + "**2")
941
942            elif func_name == "log10":
943                self.setValue(ctx, "_sm.log" +
944                              "(" + self.getValue(ch.expr(0)) + ", 10)")
945
946            elif func_name == "atan2":
947                self.setValue(ctx, "_sm.atan2" + "(" + self.getValue(ch.expr(0)) + ", " +
948                              self.getValue(ch.expr(1)) + ")")
949
950            elif func_name in ["int", "round"]:
951                self.setValue(ctx, func_name +
952                              "(" + self.getValue(ch.expr(0)) + ")")
953
954            elif func_name == "abs":
955                self.setValue(ctx, "_sm.Abs(" + self.getValue(ch.expr(0)) + ")")
956
957            elif func_name in ["max", "min"]:
958                # max(x, y, z)
959                l = []
960                for i in range(1, ch.getChildCount()):
961                    if ch.getChild(i) in self.tree_property.keys():
962                        l.append(self.getValue(ch.getChild(i)))
963                    elif ch.getChild(i).getText() in [",", "(", ")"]:
964                        l.append(ch.getChild(i).getText())
965                self.setValue(ctx, "_sm." + ch.getChild(0).getText().capitalize() + "".join(l))
966
967            # Coef(y, x)
968            elif func_name == "coef":
969                #A41_A53=COEF([RHS(U4);RHS(U5)],[U1,U2,U3])
970                if ch.expr(0) in self.matrix_expr and ch.expr(1) in self.matrix_expr:
971                    icount = jcount = 0
972                    for i in range(ch.expr(0).getChild(0).getChildCount()):
973                        try:
974                            ch.expr(0).getChild(0).getChild(i).getRuleIndex()
975                            icount+=1
976                        except Exception:
977                            pass
978                    for j in range(ch.expr(1).getChild(0).getChildCount()):
979                        try:
980                            ch.expr(1).getChild(0).getChild(j).getRuleIndex()
981                            jcount+=1
982                        except Exception:
983                            pass
984                    l = []
985                    for i in range(icount):
986                        for j in range(jcount):
987                            # a41_a53[i,j] = u4.expand().coeff(u1)
988                            l.append(self.getValue(ch.expr(0).getChild(0).expr(i)) + ".expand().coeff("
989                                     + self.getValue(ch.expr(1).getChild(0).expr(j)) + ")")
990                    self.setValue(ctx, "_sm.Matrix([" + ", ".join(l) + "]).reshape(" + str(icount) + ", " + str(jcount) + ")")
991                else:
992                    self.setValue(ctx, "(" + self.getValue(ch.expr(0)) +
993                                  ")" + ".expand().coeff(" + self.getValue(ch.expr(1)) + ")")
994
995            # Exclude(y, x) Include(y, x)
996            elif func_name in ("exclude", "include"):
997                if func_name == "exclude":
998                    e = "0"
999                else:
1000                    e = "1"
1001                expr = self.getValue(ch.expr(0))
1002                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
1003                    self.matrix_expr.append(ctx)
1004                    self.setValue(ctx, "_sm.Matrix([i.collect(" + self.getValue(ch.expr(1)) + "])" +
1005                                  ".coeff(" + self.getValue(ch.expr(1)) + "," + e + ")" + "for i in " + expr + ")" +
1006                                  ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])")
1007                else:
1008                    self.setValue(ctx, "(" + expr +
1009                                  ")" + ".collect(" + self.getValue(ch.expr(1)) + ")" +
1010                                  ".coeff(" + self.getValue(ch.expr(1)) + "," + e + ")")
1011
1012            # RHS(y)
1013            elif func_name == "rhs":
1014                self.setValue(ctx, self.explicit[self.getValue(ch.expr(0))])
1015
1016            # Arrange(y, n, x) *
1017            elif func_name == "arrange":
1018                expr = self.getValue(ch.expr(0))
1019                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
1020                    self.matrix_expr.append(ctx)
1021                    self.setValue(ctx, "_sm.Matrix([i.collect(" + self.getValue(ch.expr(2)) +
1022                                  ")" + "for i in " + expr + "])"+
1023                                  ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])")
1024                else:
1025                    self.setValue(ctx, "(" + expr +
1026                                  ")" + ".collect(" + self.getValue(ch.expr(2)) + ")")
1027
1028            # Replace(y, sin(x)=3)
1029            elif func_name == "replace":
1030                l = []
1031                for i in range(1, ch.getChildCount()):
1032                    try:
1033                        if ch.getChild(i).getChild(1).getText() == "=":
1034                            l.append(self.getValue(ch.getChild(i).getChild(0)) +
1035                                     ":" + self.getValue(ch.getChild(i).getChild(2)))
1036                    except Exception:
1037                        pass
1038                expr = self.getValue(ch.expr(0))
1039                if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
1040                    self.matrix_expr.append(ctx)
1041                    self.setValue(ctx, "_sm.Matrix([i.subs({" + ",".join(l) + "}) for i in " +
1042                                  expr + "])" +
1043                                  ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])")
1044                else:
1045                    self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" +
1046                                  ".subs({" + ",".join(l) + "})")
1047
1048            # Dot(Loop>, N1>)
1049            elif func_name == "dot":
1050                l = []
1051                num = (ch.expr(1).getChild(0).getChildCount()-1)//2
1052                if ch.expr(1) in self.matrix_expr:
1053                    for i in range(num):
1054                        l.append("_me.dot(" + self.getValue(ch.expr(0)) + ", " + self.getValue(ch.expr(1).getChild(0).expr(i)) + ")")
1055                    self.setValue(ctx, "_sm.Matrix([" + ",".join(l) + "]).reshape(" + str(num) + ", " + "1)")
1056                else:
1057                    self.setValue(ctx, "_me.dot(" + self.getValue(ch.expr(0)) + ", " + self.getValue(ch.expr(1)) + ")")
1058            # Cross(w_A_N>, P_NA_AB>)
1059            elif func_name == "cross":
1060                self.vector_expr.append(ctx)
1061                self.setValue(ctx, "_me.cross(" + self.getValue(ch.expr(0)) + ", " + self.getValue(ch.expr(1)) + ")")
1062
1063            # Mag(P_O_Q>)
1064            elif func_name == "mag":
1065                self.setValue(ctx, self.getValue(ch.expr(0)) + "." + "magnitude()")
1066
1067            # MATRIX(A, I_R>>)
1068            elif func_name == "matrix":
1069                if self.type2[ch.expr(0).getText().lower()] == "frame":
1070                    text = ""
1071                elif self.type2[ch.expr(0).getText().lower()] == "bodies":
1072                    text = "_f"
1073                self.setValue(ctx, "(" + self.getValue(ch.expr(1)) + ")" + ".to_matrix(" +
1074                              self.symbol_table2[ch.expr(0).getText().lower()] + text + ")")
1075
1076            # VECTOR(A, ROWS(EIGVECS,1))
1077            elif func_name == "vector":
1078                if self.type2[ch.expr(0).getText().lower()] == "frame":
1079                    text = ""
1080                elif self.type2[ch.expr(0).getText().lower()] == "bodies":
1081                    text = "_f"
1082                v = self.getValue(ch.expr(1))
1083                f = self.symbol_table2[ch.expr(0).getText().lower()] + text
1084                self.setValue(ctx, v + "[0]*" + f + ".x +" + v + "[1]*" + f + ".y +" +
1085                              v + "[2]*" + f + ".z")
1086
1087            # Express(A2>, B)
1088            # Here I am dealing with all the Inertia commands as I expect the users to use Inertia
1089            # commands only with Express because SymPy needs the Reference frame to be specified unlike Autolev.
1090            elif func_name == "express":
1091                self.vector_expr.append(ctx)
1092                if self.type2[ch.expr(1).getText().lower()] == "frame":
1093                    frame = self.symbol_table2[ch.expr(1).getText().lower()]
1094                else:
1095                    frame = self.symbol_table2[ch.expr(1).getText().lower()] + "_f"
1096                if ch.expr(0).getText().lower() == "1>>":
1097                    self.setValue(ctx, "_me.inertia(" + frame + ", 1, 1, 1)")
1098
1099                elif '_' in ch.expr(0).getText().lower() and ch.expr(0).getText().lower().count('_') == 2\
1100                and ch.expr(0).getText().lower()[0] == "i" and ch.expr(0).getText().lower()[-2:] == ">>":
1101                    v1 = ch.expr(0).getText().lower()[:-2].split('_')[1]
1102                    v2 = ch.expr(0).getText().lower()[:-2].split('_')[2]
1103                    l = []
1104                    inertia_func(self, v1, v2, l, frame)
1105                    self.setValue(ctx, " + ".join(l))
1106
1107                elif ch.expr(0).getChild(0).getChild(0).getText().lower() == "inertia":
1108                    if ch.expr(0).getChild(0).getChildCount() == 4:
1109                        l = []
1110                        v2 = ch.expr(0).getChild(0).ID(0).getText().lower()
1111                        for v1 in self.bodies:
1112                            inertia_func(self, v1, v2, l, frame)
1113                        self.setValue(ctx, " + ".join(l))
1114
1115                    else:
1116                        l = []
1117                        l2 = []
1118                        v2 = ch.expr(0).getChild(0).ID(0).getText().lower()
1119                        for i in range(1, (ch.expr(0).getChild(0).getChildCount()-2)//2):
1120                            l2.append(ch.expr(0).getChild(0).ID(i).getText().lower())
1121                        for v1 in l2:
1122                            inertia_func(self, v1, v2, l, frame)
1123                        self.setValue(ctx, " + ".join(l))
1124
1125                else:
1126                    self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + ".express(" +
1127                                  self.symbol_table2[ch.expr(1).getText().lower()] + ")")
1128            # CM(P)
1129            elif func_name == "cm":
1130                if self.type2[ch.expr(0).getText().lower()] == "point":
1131                    text = ""
1132                else:
1133                    text = ".point"
1134                if ch.getChildCount() == 4:
1135                    self.setValue(ctx, "_me.functions.center_of_mass(" + self.symbol_table2[ch.expr(0).getText().lower()] +
1136                                  text + "," + ", ".join(self.bodies.values()) + ")")
1137                else:
1138                    bodies = []
1139                    for i in range(1, (ch.getChildCount()-1)//2):
1140                        bodies.append(self.symbol_table2[ch.expr(i).getText().lower()])
1141                    self.setValue(ctx, "_me.functions.center_of_mass(" + self.symbol_table2[ch.expr(0).getText().lower()] +
1142                                  text + "," + ", ".join(bodies) + ")")
1143
1144            # PARTIALS(V_P1_E>,U1)
1145            elif func_name == "partials":
1146                speeds = []
1147                for i in range(1, (ch.getChildCount()-1)//2):
1148                    if self.kd_equivalents2:
1149                        speeds.append(self.kd_equivalents2[self.symbol_table[ch.expr(i).getText().lower()]])
1150                    else:
1151                        speeds.append(self.symbol_table[ch.expr(i).getText().lower()])
1152                v1, v2, v3 = ch.expr(0).getText().lower().replace(">","").split('_')
1153                if self.type2[v2] == "point":
1154                    point = self.symbol_table2[v2]
1155                elif self.type2[v2] == "particle":
1156                    point = self.symbol_table2[v2] + ".point"
1157                frame = self.symbol_table2[v3]
1158                self.setValue(ctx, point + ".partial_velocity(" + frame + ", " + ",".join(speeds) + ")")
1159
1160            # UnitVec(A1>+A2>+A3>)
1161            elif func_name == "unitvec":
1162                self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + ".normalize()")
1163
1164            # Units(deg, rad)
1165            elif func_name == "units":
1166                if ch.expr(0).getText().lower() == "deg" and ch.expr(1).getText().lower() == "rad":
1167                    factor = 0.0174533
1168                elif ch.expr(0).getText().lower() == "rad" and ch.expr(1).getText().lower() == "deg":
1169                    factor = 57.2958
1170                self.setValue(ctx, str(factor))
1171            # Mass(A)
1172            elif func_name == "mass":
1173                l = []
1174                try:
1175                    ch.ID(0).getText().lower()
1176                    for i in range((ch.getChildCount()-1)//2):
1177                        l.append(self.symbol_table2[ch.ID(i).getText().lower()] + ".mass")
1178                    self.setValue(ctx, "+".join(l))
1179                except Exception:
1180                    for i in self.bodies.keys():
1181                        l.append(self.bodies[i] + ".mass")
1182                    self.setValue(ctx, "+".join(l))
1183
1184            # Fr() FrStar()
1185            # _me.KanesMethod(n, q_ind, u_ind, kd, velocity_constraints).kanes_equations(pl, fl)[0]
1186            elif func_name in ["fr", "frstar"]:
1187                if not self.kane_parsed:
1188                    if self.kd_eqs:
1189                        for i in self.kd_eqs:
1190                            self.q_ind.append(self.symbol_table[i.strip().split('-')[0].replace("'","")])
1191                            self.u_ind.append(self.symbol_table[i.strip().split('-')[1].replace("'","")])
1192
1193                    for i in range(len(self.kd_eqs)):
1194                        self.kd_eqs[i] = self.symbol_table[self.kd_eqs[i].strip().split('-')[0]] + " - " +\
1195                                         self.symbol_table[self.kd_eqs[i].strip().split('-')[1]]
1196
1197                    # Do all of this if kd_eqs are not specified
1198                    if not self.kd_eqs:
1199                        self.kd_eqs_supplied = False
1200                        self.matrix_expr.append(ctx)
1201                        for i in self.type.keys():
1202                            if self.type[i] == "motionvariable":
1203                                if self.sign[self.symbol_table[i.lower()]] == 0:
1204                                    self.q_ind.append(self.symbol_table[i.lower()])
1205                                elif self.sign[self.symbol_table[i.lower()]] == 1:
1206                                    name = "u_" + self.symbol_table[i.lower()]
1207                                    self.symbol_table.update({name: name})
1208                                    self.write(name + " = " + "_me.dynamicsymbols('" + name + "')\n")
1209                                    if self.symbol_table[i.lower()] not in self.dependent_variables:
1210                                        self.u_ind.append(name)
1211                                        self.kd_equivalents.update({name: self.symbol_table[i.lower()]})
1212                                    else:
1213                                        self.u_dep.append(name)
1214                                        self.kd_equivalents.update({name: self.symbol_table[i.lower()]})
1215
1216                        for i in self.kd_equivalents.keys():
1217                            self.kd_eqs.append(self.kd_equivalents[i] + "-" + i)
1218
1219                    if not self.u_ind and not self.kd_eqs:
1220                        self.u_ind = self.q_ind.copy()
1221                        self.q_ind = []
1222
1223                # deal with velocity constraints
1224                if self.dependent_variables:
1225                    for i in self.dependent_variables:
1226                        self.u_dep.append(i)
1227                        if i in self.u_ind:
1228                            self.u_ind.remove(i)
1229
1230
1231                self.u_dep[:] = [i for i in self.u_dep if i not in self.kd_equivalents.values()]
1232
1233                force_list = []
1234                for i in self.forces.keys():
1235                    force_list.append("(" + i + "," + self.forces[i] + ")")
1236                if self.u_dep:
1237                    u_dep_text = ", u_dependent=[" + ", ".join(self.u_dep) + "]"
1238                else:
1239                    u_dep_text = ""
1240                if self.dependent_variables:
1241                    velocity_constraints_text = ", velocity_constraints = velocity_constraints"
1242                else:
1243                    velocity_constraints_text = ""
1244                if ctx.parentCtx not in self.fr_expr:
1245                    self.write("kd_eqs = [" + ", ".join(self.kd_eqs) + "]\n")
1246                    self.write("forceList = " + "[" + ", ".join(force_list) + "]\n")
1247                    self.write("kane = _me.KanesMethod(" + self.newtonian + ", " + "q_ind=[" +
1248                            ",".join(self.q_ind) + "], " + "u_ind=[" +
1249                            ", ".join(self.u_ind) + "]" + u_dep_text + ", " +
1250                            "kd_eqs = kd_eqs" + velocity_constraints_text + ")\n")
1251                    self.write("fr, frstar = kane." + "kanes_equations([" +
1252                                ", ".join(self.bodies.values()) + "], forceList)\n")
1253                    self.fr_expr.append(ctx.parentCtx)
1254                self.kane_parsed = True
1255                self.setValue(ctx, func_name)
1256
1257        def exitMatrices(self, ctx):
1258            # Tree annotation for Matrices which is a labeled subrule of the parser rule expr.
1259
1260            # MO = [a, b; c, d]
1261            # we generate _sm.Matrix([a, b, c, d]).reshape(2, 2)
1262            # The reshape values are determined by counting the "," and ";" in the Autolev matrix
1263
1264            # Eg:
1265            # [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12]
1266            # semicolon_count = 3 and rows = 3+1 = 4
1267            # comma_count = 8 and cols = 8/rows + 1 = 8/4 + 1 = 3
1268
1269            # TODO** Parse block matrices
1270            self.matrix_expr.append(ctx)
1271            l = []
1272            semicolon_count = 0
1273            comma_count = 0
1274            for i in range(ctx.matrix().getChildCount()):
1275                child = ctx.matrix().getChild(i)
1276                if child == AutolevParser.ExprContext:
1277                    l.append(self.getValue(child))
1278                elif child.getText() == ";":
1279                    semicolon_count += 1
1280                    l.append(",")
1281                elif child.getText() == ",":
1282                    comma_count += 1
1283                    l.append(",")
1284                else:
1285                    try:
1286                        try:
1287                            l.append(self.getValue(child))
1288                        except Exception:
1289                            l.append(self.symbol_table[child.getText().lower()])
1290                    except Exception:
1291                        l.append(child.getText().lower())
1292            num_of_rows = semicolon_count + 1
1293            num_of_cols = (comma_count//num_of_rows) + 1
1294
1295            self.setValue(ctx, "_sm.Matrix(" + "".join(l) + ")" + ".reshape(" +
1296                          str(num_of_rows) + ", " + str(num_of_cols) + ")")
1297
1298        def exitVectorOrDyadic(self, ctx):
1299            self.vector_expr.append(ctx)
1300            ch = ctx.vec()
1301
1302            if ch.getChild(0).getText() == "0>":
1303                self.setValue(ctx, "0")
1304
1305            elif ch.getChild(0).getText() == "1>>":
1306                self.setValue(ctx, "1>>")
1307
1308            elif "_" in ch.ID().getText() and ch.ID().getText().count('_') == 2:
1309                vec_text = ch.getText().lower()
1310                v1, v2, v3 = ch.ID().getText().lower().split('_')
1311
1312                if v1 == "p":
1313                    if self.type2[v2] == "point":
1314                        e2 = self.symbol_table2[v2]
1315                    elif self.type2[v2] == "particle":
1316                        e2 = self.symbol_table2[v2] + ".point"
1317                    if self.type2[v3] == "point":
1318                        e3 = self.symbol_table2[v3]
1319                    elif self.type2[v3] == "particle":
1320                        e3 = self.symbol_table2[v3] + ".point"
1321                    get_vec = e3 + ".pos_from(" + e2 + ")"
1322                    self.setValue(ctx, get_vec)
1323
1324                elif v1 in ("w", "alf"):
1325                    if v1 == "w":
1326                        text = ".ang_vel_in("
1327                    elif v1 == "alf":
1328                        text = ".ang_acc_in("
1329                    if self.type2[v2] == "bodies":
1330                        e2 = self.symbol_table2[v2] + "_f"
1331                    elif self.type2[v2] == "frame":
1332                        e2 = self.symbol_table2[v2]
1333                    if self.type2[v3] == "bodies":
1334                        e3 = self.symbol_table2[v3] + "_f"
1335                    elif self.type2[v3] == "frame":
1336                        e3 = self.symbol_table2[v3]
1337                    get_vec = e2 + text + e3 + ")"
1338                    self.setValue(ctx, get_vec)
1339
1340                elif v1 in ("v", "a"):
1341                    if v1 == "v":
1342                        text = ".vel("
1343                    elif v1 == "a":
1344                        text = ".acc("
1345                    if self.type2[v2] == "point":
1346                        e2 = self.symbol_table2[v2]
1347                    elif self.type2[v2] == "particle":
1348                        e2 = self.symbol_table2[v2] + ".point"
1349                    get_vec = e2 + text + self.symbol_table2[v3] + ")"
1350                    self.setValue(ctx, get_vec)
1351
1352                else:
1353                    self.setValue(ctx, vec_text.replace(">", ""))
1354
1355            else:
1356                vec_text = ch.getText().lower()
1357                name = self.symbol_table[vec_text]
1358                self.setValue(ctx, name)
1359
1360        def exitIndexing(self, ctx):
1361            if ctx.getChildCount() == 4:
1362                try:
1363                    int_text = str(int(self.getValue(ctx.getChild(2))) - 1)
1364                except Exception:
1365                    int_text = self.getValue(ctx.getChild(2)) + " - 1"
1366                self.setValue(ctx, ctx.ID().getText().lower() + "[" + int_text + "]")
1367            elif ctx.getChildCount() == 6:
1368                try:
1369                    int_text1 = str(int(self.getValue(ctx.getChild(2))) - 1)
1370                except Exception:
1371                    int_text1 = self.getValue(ctx.getChild(2)) + " - 1"
1372                try:
1373                    int_text2 = str(int(self.getValue(ctx.getChild(4))) - 1)
1374                except Exception:
1375                    int_text2 = self.getValue(ctx.getChild(2)) + " - 1"
1376                self.setValue(ctx, ctx.ID().getText().lower() + "[" + int_text1 + ", " + int_text2 + "]")
1377
1378
1379        # ================== Subrules of parser rule expr (End) ====================== #
1380
1381        def exitRegularAssign(self, ctx):
1382            # Handle assignments of type ID = expr
1383            if ctx.equals().getText() in ["=", "+=", "-=", "*=", "/="]:
1384                equals = ctx.equals().getText()
1385            elif ctx.equals().getText() == ":=":
1386                equals = " = "
1387            elif ctx.equals().getText() == "^=":
1388                equals = "**="
1389
1390            try:
1391                a = ctx.ID().getText().lower() + "'"*ctx.diff().getText().count("'")
1392            except Exception:
1393                a = ctx.ID().getText().lower()
1394
1395            if a in self.type.keys() and self.type[a] in ("motionvariable", "motionvariable'") and\
1396            self.type[ctx.expr().getText().lower()] in ("motionvariable", "motionvariable'"):
1397                b = ctx.expr().getText().lower()
1398                if "'" in b and "'" not in a:
1399                    a, b = b, a
1400                if not self.kane_parsed:
1401                    self.kd_eqs.append(a + "-" + b)
1402                    self.kd_equivalents.update({self.symbol_table[a]:
1403                                                self.symbol_table[b]})
1404                    self.kd_equivalents2.update({self.symbol_table[b]:
1405                                                    self.symbol_table[a]})
1406
1407            if a in self.symbol_table.keys() and a in self.type.keys() and self.type[a] in ("variable", "motionvariable"):
1408                self.explicit.update({self.symbol_table[a]: self.getValue(ctx.expr())})
1409
1410            else:
1411                if ctx.expr() in self.matrix_expr:
1412                    self.type.update({a: "matrix"})
1413
1414                try:
1415                    b = self.symbol_table[a]
1416                except KeyError:
1417                    self.symbol_table[a] = a
1418
1419                if "_" in a and a.count("_") == 1:
1420                    e1, e2 = a.split('_')
1421                    if e1 in self.type2.keys() and self.type2[e1] in ("frame", "bodies")\
1422                    and e2 in self.type2.keys() and self.type2[e2] in ("frame", "bodies"):
1423                        if self.type2[e1] == "bodies":
1424                            t1 = "_f"
1425                        else:
1426                            t1 = ""
1427                        if self.type2[e2] == "bodies":
1428                            t2 = "_f"
1429                        else:
1430                            t2 = ""
1431
1432                        self.write(self.symbol_table2[e2] + t2 + ".orient(" + self.symbol_table2[e1] +
1433                                   t1 + ", 'DCM', " + self.getValue(ctx.expr()) + ")\n")
1434                    else:
1435                        self.write(self.symbol_table[a] + " " + equals + " " +
1436                                    self.getValue(ctx.expr()) + "\n")
1437                else:
1438                    self.write(self.symbol_table[a] + " " + equals + " " +
1439                                self.getValue(ctx.expr()) + "\n")
1440
1441        def exitIndexAssign(self, ctx):
1442            # Handle assignments of type ID[index] = expr
1443                if ctx.equals().getText() in ["=", "+=", "-=", "*=", "/="]:
1444                    equals = ctx.equals().getText()
1445                elif ctx.equals().getText() == ":=":
1446                    equals = " = "
1447                elif ctx.equals().getText() == "^=":
1448                    equals = "**="
1449
1450                text = ctx.ID().getText().lower()
1451                self.type.update({text: "matrix"})
1452                # Handle assignments of type ID[2] = expr
1453                if ctx.index().getChildCount() == 1:
1454                    if ctx.index().getChild(0).getText() == "1":
1455                        self.type.update({text: "matrix"})
1456                        self.symbol_table.update({text: text})
1457                        self.write(text + " = " + "_sm.Matrix([[0]])\n")
1458                        self.write(text + "[0] = " + self.getValue(ctx.expr()) + "\n")
1459                    else:
1460                        # m = m.row_insert(m.shape[0], _sm.Matrix([[0]]))
1461                        self.write(text + " = " + text +
1462                                   ".row_insert(" + text + ".shape[0]" + ", " + "_sm.Matrix([[0]])" + ")\n")
1463                        self.write(text + "[" + text + ".shape[0]-1" + "] = " + self.getValue(ctx.expr()) + "\n")
1464
1465                # Handle assignments of type ID[2, 2] = expr
1466                elif ctx.index().getChildCount() == 3:
1467                    l = []
1468                    try:
1469                        l.append(str(int(self.getValue(ctx.index().getChild(0)))-1))
1470                    except Exception:
1471                        l.append(self.getValue(ctx.index().getChild(0)) + "-1")
1472                    l.append(",")
1473                    try:
1474                        l.append(str(int(self.getValue(ctx.index().getChild(2)))-1))
1475                    except Exception:
1476                        l.append(self.getValue(ctx.index().getChild(2)) + "-1")
1477                    self.write(self.symbol_table[ctx.ID().getText().lower()] +
1478                               "[" + "".join(l) + "]" + " " + equals + " " + self.getValue(ctx.expr()) + "\n")
1479
1480        def exitVecAssign(self, ctx):
1481            # Handle assignments of the type vec = expr
1482            ch = ctx.vec()
1483            vec_text = ch.getText().lower()
1484
1485            if "_" in ch.ID().getText():
1486                num = ch.ID().getText().count('_')
1487
1488                if num == 2:
1489                    v1, v2, v3 = ch.ID().getText().lower().split('_')
1490
1491                    if v1 == "p":
1492                        if self.type2[v2] == "point":
1493                            e2 = self.symbol_table2[v2]
1494                        elif self.type2[v2] == "particle":
1495                            e2 = self.symbol_table2[v2] + ".point"
1496                        if self.type2[v3] == "point":
1497                            e3 = self.symbol_table2[v3]
1498                        elif self.type2[v3] == "particle":
1499                            e3 = self.symbol_table2[v3] + ".point"
1500                        # ab.set_pos(na, la*a.x)
1501                        self.write(e3 + ".set_pos(" + e2 + ", " + self.getValue(ctx.expr()) + ")\n")
1502
1503                    elif v1 in ("w", "alf"):
1504                        if v1 == "w":
1505                            text = ".set_ang_vel("
1506                        elif v1 == "alf":
1507                            text = ".set_ang_acc("
1508                        # a.set_ang_vel(n, qad*a.z)
1509                        if self.type2[v2] == "bodies":
1510                            e2 = self.symbol_table2[v2] + "_f"
1511                        else:
1512                            e2 = self.symbol_table2[v2]
1513                        if self.type2[v3] == "bodies":
1514                            e3 = self.symbol_table2[v3] + "_f"
1515                        else:
1516                            e3 = self.symbol_table2[v3]
1517                        self.write(e2 + text + e3 + ", " + self.getValue(ctx.expr()) + ")\n")
1518
1519                    elif v1 in ("v", "a"):
1520                        if v1 == "v":
1521                            text = ".set_vel("
1522                        elif v1 == "a":
1523                            text = ".set_acc("
1524                        if self.type2[v2] == "point":
1525                            e2 = self.symbol_table2[v2]
1526                        elif self.type2[v2] == "particle":
1527                            e2 = self.symbol_table2[v2] + ".point"
1528                        self.write(e2 + text + self.symbol_table2[v3] +
1529                                   ", " + self.getValue(ctx.expr()) + ")\n")
1530                    elif v1 == "i":
1531                        if v2 in self.type2.keys() and self.type2[v2] == "bodies":
1532                            self.write(self.symbol_table2[v2] + ".inertia = (" + self.getValue(ctx.expr()) +
1533                            ", " + self.symbol_table2[v3] + ")\n")
1534                            self.inertia_point.update({v2: v3})
1535                        elif v2 in self.type2.keys() and self.type2[v2] == "particle":
1536                            self.write(ch.ID().getText().lower() + " = " + self.getValue(ctx.expr()) + "\n")
1537                        else:
1538                            self.write(ch.ID().getText().lower() + " = " + self.getValue(ctx.expr()) + "\n")
1539                    else:
1540                        self.write(ch.ID().getText().lower() + " = " + self.getValue(ctx.expr()) + "\n")
1541
1542                elif num == 1:
1543                    v1, v2 = ch.ID().getText().lower().split('_')
1544
1545                    if v1 in ("force", "torque"):
1546                        if self.type2[v2] in ("point", "frame"):
1547                            e2 = self.symbol_table2[v2]
1548                        elif self.type2[v2] == "particle":
1549                            e2 = self.symbol_table2[v2] + ".point"
1550                        self.symbol_table.update({vec_text: ch.ID().getText().lower()})
1551
1552                        if e2 in self.forces.keys():
1553                            self.forces[e2] = self.forces[e2] + " + " + self.getValue(ctx.expr())
1554                        else:
1555                            self.forces.update({e2: self.getValue(ctx.expr())})
1556                        self.write(ch.ID().getText().lower() + " = " + self.forces[e2] + "\n")
1557
1558                    else:
1559                        name = ch.ID().getText().lower()
1560                        self.symbol_table.update({vec_text: name})
1561                        self.write(ch.ID().getText().lower() + " = " + self.getValue(ctx.expr()) + "\n")
1562                else:
1563                    name = ch.ID().getText().lower()
1564                    self.symbol_table.update({vec_text: name})
1565                    self.write(name + " " + ctx.getChild(1).getText() + " " + self.getValue(ctx.expr()) + "\n")
1566            else:
1567                name = ch.ID().getText().lower()
1568                self.symbol_table.update({vec_text: name})
1569                self.write(name + " " + ctx.getChild(1).getText() + " " + self.getValue(ctx.expr()) + "\n")
1570
1571        def enterInputs2(self, ctx):
1572            self.in_inputs = True
1573
1574        # Inputs
1575        def exitInputs2(self, ctx):
1576            # Stores numerical values given by the input command which
1577            # are used for codegen and numerical analysis.
1578            if ctx.getChildCount() == 3:
1579                try:
1580                    self.inputs.update({self.symbol_table[ctx.id_diff().getText().lower()]: self.getValue(ctx.expr(0))})
1581                except Exception:
1582                    self.inputs.update({ctx.id_diff().getText().lower(): self.getValue(ctx.expr(0))})
1583            elif ctx.getChildCount() == 4:
1584                try:
1585                    self.inputs.update({self.symbol_table[ctx.id_diff().getText().lower()]:
1586                    (self.getValue(ctx.expr(0)), self.getValue(ctx.expr(1)))})
1587                except Exception:
1588                    self.inputs.update({ctx.id_diff().getText().lower():
1589                    (self.getValue(ctx.expr(0)), self.getValue(ctx.expr(1)))})
1590
1591            self.in_inputs = False
1592
1593        def enterOutputs(self, ctx):
1594            self.in_outputs = True
1595        def exitOutputs(self, ctx):
1596            self.in_outputs = False
1597
1598        def exitOutputs2(self, ctx):
1599            try:
1600                if "[" in ctx.expr(1).getText():
1601                    self.outputs.append(self.symbol_table[ctx.expr(0).getText().lower()] +
1602                                        ctx.expr(1).getText().lower())
1603                else:
1604                    self.outputs.append(self.symbol_table[ctx.expr(0).getText().lower()])
1605
1606            except Exception:
1607                pass
1608
1609        # Code commands
1610        def exitCodegen(self, ctx):
1611            # Handles the CODE() command ie the solvers and the codgen part.
1612            # Uses linsolve for the algebraic solvers and nsolve for non linear solvers.
1613
1614            if ctx.functionCall().getChild(0).getText().lower() == "algebraic":
1615                matrix_name = self.getValue(ctx.functionCall().expr(0))
1616                e = []
1617                d = []
1618                for i in range(1, (ctx.functionCall().getChildCount()-2)//2):
1619                    a = self.getValue(ctx.functionCall().expr(i))
1620                    e.append(a)
1621
1622                for i in self.inputs.keys():
1623                    d.append(i + ":" + self.inputs[i])
1624                self.write(matrix_name + "_list" + " = " + "[]\n")
1625                self.write("for i in " + matrix_name + ":  " + matrix_name +
1626                           "_list" + ".append(i.subs({" + ", ".join(d) + "}))\n")
1627                self.write("print(_sm.linsolve(" + matrix_name + "_list" + ", " + ",".join(e) + "))\n")
1628
1629            elif ctx.functionCall().getChild(0).getText().lower() == "nonlinear":
1630                e = []
1631                d = []
1632                guess = []
1633                for i in range(1, (ctx.functionCall().getChildCount()-2)//2):
1634                    a = self.getValue(ctx.functionCall().expr(i))
1635                    e.append(a)
1636                #print(self.inputs)
1637                for i in self.inputs.keys():
1638                    if i in self.symbol_table.keys():
1639                        if type(self.inputs[i]) is tuple:
1640                            j, z = self.inputs[i]
1641                        else:
1642                            j = self.inputs[i]
1643                            z = ""
1644                        if i not in e:
1645                            if z == "deg":
1646                                d.append(i + ":" + "_np.deg2rad(" + j + ")")
1647                            else:
1648                                d.append(i + ":" + j)
1649                        else:
1650                            if z == "deg":
1651                                guess.append("_np.deg2rad(" + j + ")")
1652                            else:
1653                                guess.append(j)
1654
1655                self.write("matrix_list" + " = " + "[]\n")
1656                self.write("for i in " + self.getValue(ctx.functionCall().expr(0)) + ":")
1657                self.write("matrix_list" + ".append(i.subs({" + ", ".join(d) + "}))\n")
1658                self.write("print(_sm.nsolve(matrix_list," + "(" + ",".join(e) + ")" +
1659                           ",(" + ",".join(guess) + ")" + "))\n")
1660
1661            elif ctx.functionCall().getChild(0).getText().lower() in ["ode", "dynamics"] and self.include_numeric:
1662                if self.kane_type == "no_args":
1663                    for i in self.symbol_table.keys():
1664                        try:
1665                            if self.type[i] == "constants" or self.type[self.symbol_table[i]] == "constants":
1666                                self.constants.append(self.symbol_table[i])
1667                        except Exception:
1668                            pass
1669                    q_add_u = self.q_ind + self.q_dep + self.u_ind + self.u_dep
1670                    x0 = []
1671                    for i in q_add_u:
1672                        try:
1673                            if i in self.inputs.keys():
1674                                if type(self.inputs[i]) is tuple:
1675                                    if self.inputs[i][1] == "deg":
1676                                        x0.append(i + ":" + "_np.deg2rad(" + self.inputs[i][0] + ")")
1677                                    else:
1678                                        x0.append(i + ":" + self.inputs[i][0])
1679                                else:
1680                                    x0.append(i + ":" + self.inputs[i])
1681                            elif self.kd_equivalents[i] in self.inputs.keys():
1682                                if type(self.inputs[self.kd_equivalents[i]]) is tuple:
1683                                    x0.append(i + ":" + self.inputs[self.kd_equivalents[i]][0])
1684                                else:
1685                                    x0.append(i + ":" + self.inputs[self.kd_equivalents[i]])
1686                        except Exception:
1687                            pass
1688
1689                    # numerical constants
1690                    numerical_constants = []
1691                    for i in self.constants:
1692                        if i in self.inputs.keys():
1693                            if type(self.inputs[i]) is tuple:
1694                                numerical_constants.append(self.inputs[i][0])
1695                            else:
1696                                numerical_constants.append(self.inputs[i])
1697
1698                    # t = linspace
1699                    t_final = self.inputs["tfinal"]
1700                    integ_stp = self.inputs["integstp"]
1701
1702                    self.write("from pydy.system import System\n")
1703                    const_list = []
1704                    if numerical_constants:
1705                        for i in range(len(self.constants)):
1706                            const_list.append(self.constants[i] + ":" + numerical_constants[i])
1707                    specifieds = []
1708                    if self.t:
1709                        specifieds.append("_me.dynamicsymbols('t')" + ":" + "lambda x, t: t")
1710
1711                    for i in self.inputs:
1712                        if i in self.symbol_table.keys() and self.symbol_table[i] not in\
1713                        self.constants + self.q_ind + self.q_dep + self.u_ind + self.u_dep:
1714                            specifieds.append(self.symbol_table[i] + ":" + self.inputs[i])
1715
1716                    self.write("sys = System(kane, constants = {" + ", ".join(const_list) + "},\n" +
1717                               "specifieds={" + ", ".join(specifieds) + "},\n" +
1718                               "initial_conditions={" + ", ".join(x0) + "},\n" +
1719                               "times = _np.linspace(0.0, " + str(t_final) + ", " + str(t_final) +
1720                               "/" + str(integ_stp) + "))\n\ny=sys.integrate()\n")
1721
1722                    # For outputs other than qs and us.
1723                    other_outputs = []
1724                    for i in self.outputs:
1725                        if i not in q_add_u:
1726                            if "[" in i:
1727                                other_outputs.append((i[:-3] + i[-2], i[:-3] + "[" + str(int(i[-2])-1) + "]"))
1728                            else:
1729                                other_outputs.append((i, i))
1730
1731                    for i in other_outputs:
1732                        self.write(i[0] + "_out" + " = " + "[]\n")
1733                    if other_outputs:
1734                        self.write("for i in y:\n")
1735                        self.write("    q_u_dict = dict(zip(sys.coordinates+sys.speeds, i))\n")
1736                        for i in other_outputs:
1737                            self.write(" "*4 + i[0] + "_out" + ".append(" + i[1] + ".subs(q_u_dict)" +
1738                                    ".subs(sys.constants).evalf())\n")
1739
1740        # Standalone function calls (used for dual functions)
1741        def exitFunctionCall(self, ctx):
1742            # Basically deals with standalone function calls ie functions which are not a part of
1743            # expressions and assignments. Autolev Dual functions can both appear in standalone
1744            # function calls and also on the right hand side as part of expr or assignment.
1745
1746            # Dual functions are indicated by a * in the comments below
1747
1748            # Checks if the function is a statement on its own
1749            if ctx.parentCtx.getRuleIndex() == AutolevParser.RULE_stat:
1750                func_name = ctx.getChild(0).getText().lower()
1751                # Expand(E, n:m) *
1752                if func_name == "expand":
1753                    # If the first argument is a pre declared variable.
1754                    expr = self.getValue(ctx.expr(0))
1755                    symbol = self.symbol_table[ctx.expr(0).getText().lower()]
1756                    if ctx.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
1757                        self.write(symbol + " = " + "_sm.Matrix([i.expand() for i in " + expr + "])" +
1758                                   ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])\n")
1759                    else:
1760                        self.write(symbol + " = " + symbol + "." + "expand()\n")
1761
1762                # Factor(E, x) *
1763                elif func_name == "factor":
1764                    expr = self.getValue(ctx.expr(0))
1765                    symbol = self.symbol_table[ctx.expr(0).getText().lower()]
1766                    if ctx.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
1767                        self.write(symbol + " = " + "_sm.Matrix([_sm.factor(i," + self.getValue(ctx.expr(1)) +
1768                                   ") for i in " + expr + "])" +
1769                                   ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])\n")
1770                    else:
1771                        self.write(expr + " = " + "_sm.factor(" + expr + ", " +
1772                                   self.getValue(ctx.expr(1)) + ")\n")
1773
1774                # Solve(Zero, x, y)
1775                elif func_name == "solve":
1776                    l = []
1777                    l2 = []
1778                    num = 0
1779                    for i in range(1, ctx.getChildCount()):
1780                        if ctx.getChild(i).getText() == ",":
1781                            num+=1
1782                        try:
1783                            l.append(self.getValue(ctx.getChild(i)))
1784                        except Exception:
1785                            l.append(ctx.getChild(i).getText())
1786
1787                        if i != 2:
1788                            try:
1789                                l2.append(self.getValue(ctx.getChild(i)))
1790                            except Exception:
1791                                pass
1792
1793                    for i in l2:
1794                        self.explicit.update({i: "_sm.solve" + "".join(l) + "[" + i + "]"})
1795
1796                    self.write("print(_sm.solve" + "".join(l) + ")\n")
1797
1798                # Arrange(y, n, x) *
1799                elif func_name == "arrange":
1800                    expr = self.getValue(ctx.expr(0))
1801                    symbol = self.symbol_table[ctx.expr(0).getText().lower()]
1802
1803                    if ctx.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"):
1804                        self.write(symbol + " = " + "_sm.Matrix([i.collect(" + self.getValue(ctx.expr(2)) +
1805                                   ")" + "for i in " + expr + "])" +
1806                                   ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])\n")
1807                    else:
1808                        self.write(self.getValue(ctx.expr(0)) + ".collect(" +
1809                                   self.getValue(ctx.expr(2)) + ")\n")
1810
1811                # Eig(M, EigenValue, EigenVec)
1812                elif func_name == "eig":
1813                    self.symbol_table.update({ctx.expr(1).getText().lower(): ctx.expr(1).getText().lower()})
1814                    self.symbol_table.update({ctx.expr(2).getText().lower(): ctx.expr(2).getText().lower()})
1815                    # _sm.Matrix([i.evalf() for i in (i_s_so).eigenvals().keys()])
1816                    self.write(ctx.expr(1).getText().lower() + " = " +
1817                               "_sm.Matrix([i.evalf() for i in " +
1818                               "(" + self.getValue(ctx.expr(0)) + ")" + ".eigenvals().keys()])\n")
1819                    # _sm.Matrix([i[2][0].evalf() for i in (i_s_o).eigenvects()]).reshape(i_s_o.shape[0], i_s_o.shape[1])
1820                    self.write(ctx.expr(2).getText().lower() + " = " +
1821                               "_sm.Matrix([i[2][0].evalf() for i in " + "(" + self.getValue(ctx.expr(0)) + ")" +
1822                               ".eigenvects()]).reshape(" + self.getValue(ctx.expr(0)) + ".shape[0], " +
1823                               self.getValue(ctx.expr(0)) + ".shape[1])\n")
1824
1825                # Simprot(N, A, 3, qA)
1826                elif func_name == "simprot":
1827                    # A.orient(N, 'Axis', qA, N.z)
1828                    if self.type2[ctx.expr(0).getText().lower()] == "frame":
1829                        frame1 = self.symbol_table2[ctx.expr(0).getText().lower()]
1830                    elif self.type2[ctx.expr(0).getText().lower()] == "bodies":
1831                        frame1 = self.symbol_table2[ctx.expr(0).getText().lower()] + "_f"
1832                    if self.type2[ctx.expr(1).getText().lower()] == "frame":
1833                        frame2 = self.symbol_table2[ctx.expr(1).getText().lower()]
1834                    elif self.type2[ctx.expr(1).getText().lower()] == "bodies":
1835                        frame2 = self.symbol_table2[ctx.expr(1).getText().lower()] + "_f"
1836                    e2 = ""
1837                    if ctx.expr(2).getText()[0] == "-":
1838                        e2 = "-1*"
1839                    if ctx.expr(2).getText() in ("1", "-1"):
1840                        e = frame1 + ".x"
1841                    elif ctx.expr(2).getText() in ("2", "-2"):
1842                        e = frame1 + ".y"
1843                    elif ctx.expr(2).getText() in ("3", "-3"):
1844                        e = frame1 + ".z"
1845                    else:
1846                        e = self.getValue(ctx.expr(2))
1847                        e2 = ""
1848
1849                    if "degrees" in self.settings.keys() and self.settings["degrees"] == "off":
1850                        value = self.getValue(ctx.expr(3))
1851                    else:
1852                        if ctx.expr(3) in self.numeric_expr:
1853                            value = "_np.deg2rad(" + self.getValue(ctx.expr(3)) + ")"
1854                        else:
1855                            value = self.getValue(ctx.expr(3))
1856                    self.write(frame2 + ".orient(" + frame1 +
1857                               ", " + "'Axis'" + ", " + "[" + value +
1858                               ", " + e2 + e + "]" + ")\n")
1859
1860                # Express(A2>, B) *
1861                elif func_name == "express":
1862                    if self.type2[ctx.expr(1).getText().lower()] == "bodies":
1863                        f = "_f"
1864                    else:
1865                        f = ""
1866
1867                    if '_' in ctx.expr(0).getText().lower() and ctx.expr(0).getText().count('_') == 2:
1868                        vec = ctx.expr(0).getText().lower().replace(">", "").split('_')
1869                        v1 = self.symbol_table2[vec[1]]
1870                        v2 = self.symbol_table2[vec[2]]
1871                        if vec[0] == "p":
1872                            self.write(v2 + ".set_pos(" + v1 + ", " + "(" + self.getValue(ctx.expr(0)) +
1873                                    ")" + ".express(" + self.symbol_table2[ctx.expr(1).getText().lower()] + f + "))\n")
1874                        elif vec[0] == "v":
1875                            self.write(v1 + ".set_vel(" + v2 + ", " + "(" + self.getValue(ctx.expr(0)) +
1876                                    ")" + ".express(" + self.symbol_table2[ctx.expr(1).getText().lower()] + f + "))\n")
1877                        elif vec[0] == "a":
1878                            self.write(v1 + ".set_acc(" + v2 + ", " + "(" + self.getValue(ctx.expr(0)) +
1879                                    ")" + ".express(" + self.symbol_table2[ctx.expr(1).getText().lower()] + f + "))\n")
1880                        else:
1881                            self.write(self.getValue(ctx.expr(0)) + " = " + "(" + self.getValue(ctx.expr(0)) + ")" + ".express(" +
1882                                        self.symbol_table2[ctx.expr(1).getText().lower()] + f + ")\n")
1883                    else:
1884                        self.write(self.getValue(ctx.expr(0)) + " = " + "(" + self.getValue(ctx.expr(0)) + ")" + ".express(" +
1885                                    self.symbol_table2[ctx.expr(1).getText().lower()] + f + ")\n")
1886
1887                # Angvel(A, B)
1888                elif func_name == "angvel":
1889                    self.write("print(" + self.symbol_table2[ctx.expr(1).getText().lower()] +
1890                               ".ang_vel_in(" + self.symbol_table2[ctx.expr(0).getText().lower()] + "))\n")
1891
1892                # v2pts(N, A, O, P)
1893                elif func_name in ("v2pts", "a2pts", "v2pt", "a1pt"):
1894                    if func_name == "v2pts":
1895                        text = ".v2pt_theory("
1896                    elif func_name == "a2pts":
1897                        text = ".a2pt_theory("
1898                    elif func_name == "v1pt":
1899                        text = ".v1pt_theory("
1900                    elif func_name == "a1pt":
1901                        text = ".a1pt_theory("
1902                    if self.type2[ctx.expr(1).getText().lower()] == "frame":
1903                        frame = self.symbol_table2[ctx.expr(1).getText().lower()]
1904                    elif self.type2[ctx.expr(1).getText().lower()] == "bodies":
1905                        frame = self.symbol_table2[ctx.expr(1).getText().lower()] + "_f"
1906                    expr_list = []
1907                    for i in range(2, 4):
1908                        if self.type2[ctx.expr(i).getText().lower()] == "point":
1909                            expr_list.append(self.symbol_table2[ctx.expr(i).getText().lower()])
1910                        elif self.type2[ctx.expr(i).getText().lower()] == "particle":
1911                            expr_list.append(self.symbol_table2[ctx.expr(i).getText().lower()] + ".point")
1912
1913                    self.write(expr_list[1] + text + expr_list[0] +
1914                               "," + self.symbol_table2[ctx.expr(0).getText().lower()] + "," +
1915                               frame + ")\n")
1916
1917                # Gravity(g*N1>)
1918                elif func_name == "gravity":
1919                    for i in self.bodies.keys():
1920                        if self.type2[i] == "bodies":
1921                            e = self.symbol_table2[i] + ".masscenter"
1922                        elif self.type2[i] == "particle":
1923                            e = self.symbol_table2[i] + ".point"
1924                        if e in self.forces.keys():
1925                            self.forces[e] = self.forces[e] + self.symbol_table2[i] +\
1926                                             ".mass*(" + self.getValue(ctx.expr(0)) + ")"
1927                        else:
1928                            self.forces.update({e: self.symbol_table2[i] +
1929                                               ".mass*(" + self.getValue(ctx.expr(0)) + ")"})
1930                        self.write("force_" + i + " = " + self.forces[e] + "\n")
1931
1932                # Explicit(EXPRESS(IMPLICIT>,C))
1933                elif func_name == "explicit":
1934                    if ctx.expr(0) in self.vector_expr:
1935                        self.vector_expr.append(ctx)
1936                    expr = self.getValue(ctx.expr(0))
1937                    if self.explicit.keys():
1938                        explicit_list = []
1939                        for i in self.explicit.keys():
1940                            explicit_list.append(i + ":" + self.explicit[i])
1941                        if '_' in ctx.expr(0).getText().lower() and ctx.expr(0).getText().count('_') == 2:
1942                            vec = ctx.expr(0).getText().lower().replace(">", "").split('_')
1943                            v1 = self.symbol_table2[vec[1]]
1944                            v2 = self.symbol_table2[vec[2]]
1945                            if vec[0] == "p":
1946                                self.write(v2 + ".set_pos(" + v1 + ", " + "(" + expr +
1947                                        ")" + ".subs({" + ", ".join(explicit_list) + "}))\n")
1948                            elif vec[0] == "v":
1949                                self.write(v2 + ".set_vel(" + v1 + ", " + "(" + expr +
1950                                        ")" + ".subs({" + ", ".join(explicit_list) + "}))\n")
1951                            elif vec[0] == "a":
1952                                self.write(v2 + ".set_acc(" + v1 + ", " + "(" + expr +
1953                                        ")" + ".subs({" + ", ".join(explicit_list) + "}))\n")
1954                            else:
1955                                self.write(expr + " = " + "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "})\n")
1956                        else:
1957                            self.write(expr + " = " + "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "})\n")
1958
1959                # Force(O/Q, -k*Stretch*Uvec>)
1960                elif func_name in ("force", "torque"):
1961
1962                    if "/" in ctx.expr(0).getText().lower():
1963                        p1 = ctx.expr(0).getText().lower().split('/')[0]
1964                        p2 = ctx.expr(0).getText().lower().split('/')[1]
1965                        if self.type2[p1] in ("point", "frame"):
1966                            pt1 = self.symbol_table2[p1]
1967                        elif self.type2[p1] == "particle":
1968                            pt1 = self.symbol_table2[p1] + ".point"
1969                        if self.type2[p2] in ("point", "frame"):
1970                            pt2 = self.symbol_table2[p2]
1971                        elif self.type2[p2] == "particle":
1972                            pt2 = self.symbol_table2[p2] + ".point"
1973                        if pt1 in self.forces.keys():
1974                            self.forces[pt1] = self.forces[pt1] + " + -1*("+self.getValue(ctx.expr(1)) + ")"
1975                            self.write("force_" + p1 + " = " + self.forces[pt1] + "\n")
1976                        else:
1977                            self.forces.update({pt1: "-1*("+self.getValue(ctx.expr(1)) + ")"})
1978                            self.write("force_" + p1 + " = " + self.forces[pt1] + "\n")
1979                        if pt2 in self.forces.keys():
1980                            self.forces[pt2] = self.forces[pt2] + "+ " + self.getValue(ctx.expr(1))
1981                            self.write("force_" + p2 + " = " + self.forces[pt2] + "\n")
1982                        else:
1983                            self.forces.update({pt2: self.getValue(ctx.expr(1))})
1984                            self.write("force_" + p2 + " = " + self.forces[pt2] + "\n")
1985
1986                    elif ctx.expr(0).getChildCount() == 1:
1987                        p1 = ctx.expr(0).getText().lower()
1988                        if self.type2[p1] in ("point", "frame"):
1989                            pt1 = self.symbol_table2[p1]
1990                        elif self.type2[p1] == "particle":
1991                            pt1 = self.symbol_table2[p1] + ".point"
1992                        if pt1 in self.forces.keys():
1993                            self.forces[pt1] = self.forces[pt1] + "+ -1*(" + self.getValue(ctx.expr(1)) + ")"
1994                        else:
1995                            self.forces.update({pt1: "-1*(" + self.getValue(ctx.expr(1)) + ")"})
1996
1997                # Constrain(Dependent[qB])
1998                elif func_name == "constrain":
1999                    if ctx.getChild(2).getChild(0).getText().lower() == "dependent":
2000                        self.write("velocity_constraints = [i for i in dependent]\n")
2001                    x = (ctx.expr(0).getChildCount()-2)//2
2002                    for i in range(x):
2003                        self.dependent_variables.append(self.getValue(ctx.expr(0).expr(i)))
2004
2005                # Kane()
2006                elif func_name == "kane":
2007                    if ctx.getChildCount() == 3:
2008                        self.kane_type = "no_args"
2009
2010        # Settings
2011        def exitSettings(self, ctx):
2012            # Stores settings like Complex on/off, Degrees on/off etc in self.settings.
2013            try:
2014                self.settings.update({ctx.getChild(0).getText().lower():
2015                                     ctx.getChild(1).getText().lower()})
2016            except Exception:
2017                pass
2018
2019        def exitMassDecl2(self, ctx):
2020            # Used for declaring the masses of particles and rigidbodies.
2021            particle = self.symbol_table2[ctx.getChild(0).getText().lower()]
2022            if ctx.getText().count("=") == 2:
2023                if ctx.expr().expr(1) in self.numeric_expr:
2024                    e = "_sm.S(" + self.getValue(ctx.expr().expr(1)) + ")"
2025                else:
2026                    e = self.getValue(ctx.expr().expr(1))
2027                self.symbol_table.update({ctx.expr().expr(0).getText().lower(): ctx.expr().expr(0).getText().lower()})
2028                self.write(ctx.expr().expr(0).getText().lower() + " = " + e + "\n")
2029                mass = ctx.expr().expr(0).getText().lower()
2030            else:
2031                try:
2032                    if ctx.expr() in self.numeric_expr:
2033                        mass = "_sm.S(" + self.getValue(ctx.expr()) + ")"
2034                    else:
2035                        mass = self.getValue(ctx.expr())
2036                except Exception:
2037                    a_text = ctx.expr().getText().lower()
2038                    self.symbol_table.update({a_text: a_text})
2039                    self.type.update({a_text: "constants"})
2040                    self.write(a_text + " = " + "_sm.symbols('" + a_text + "')\n")
2041                    mass = a_text
2042
2043            self.write(particle + ".mass = " + mass + "\n")
2044
2045        def exitInertiaDecl(self, ctx):
2046            inertia_list = []
2047            try:
2048                ctx.ID(1).getText()
2049                num = 5
2050            except Exception:
2051                num = 2
2052            for i in range((ctx.getChildCount()-num)//2):
2053                try:
2054                    if ctx.expr(i) in self.numeric_expr:
2055                        inertia_list.append("_sm.S(" + self.getValue(ctx.expr(i)) + ")")
2056                    else:
2057                        inertia_list.append(self.getValue(ctx.expr(i)))
2058                except Exception:
2059                    a_text = ctx.expr(i).getText().lower()
2060                    self.symbol_table.update({a_text: a_text})
2061                    self.type.update({a_text: "constants"})
2062                    self.write(a_text + " = " + "_sm.symbols('" + a_text + "')\n")
2063                    inertia_list.append(a_text)
2064
2065            if len(inertia_list) < 6:
2066                for i in range(6-len(inertia_list)):
2067                    inertia_list.append("0")
2068            # body_a.inertia = (_me.inertia(body_a, I1, I2, I3, 0, 0, 0), body_a_cm)
2069            try:
2070                frame = self.symbol_table2[ctx.ID(1).getText().lower()]
2071                point = self.symbol_table2[ctx.ID(0).getText().lower().split('_')[1]]
2072                body = self.symbol_table2[ctx.ID(0).getText().lower().split('_')[0]]
2073                self.inertia_point.update({ctx.ID(0).getText().lower().split('_')[0]
2074                                          : ctx.ID(0).getText().lower().split('_')[1]})
2075                self.write(body + ".inertia" + " = " + "(_me.inertia(" + frame + ", " +
2076                           ", ".join(inertia_list) + "), " + point + ")\n")
2077
2078            except Exception:
2079                body_name = self.symbol_table2[ctx.ID(0).getText().lower()]
2080                body_name_cm = body_name + "_cm"
2081                self.inertia_point.update({ctx.ID(0).getText().lower(): ctx.ID(0).getText().lower() + "o"})
2082                self.write(body_name + ".inertia" + " = " + "(_me.inertia(" + body_name + "_f" + ", " +
2083                           ", ".join(inertia_list) + "), " + body_name_cm + ")\n")
2084