Example 3: Generating Python for Mobile Phones
Navigating models based on connections is just one possible way of translating models to code. To illustrate other ways generators can work here's a case that generates SmartPhone applications by producing function definitions for individual model elements. Here the underlying phone platform, Symbian/S60 and its Python framework, provides a set of APIs and expects a specific programming model for the user interface. To enable model-based generation, a specification language and generator follows the programming model and APIs. Figure 3
shows a sample design.
The modeling concepts in Figure 3
are based directly on the services and widgets that S60 phones offer for application development. Modelers describe the behavioral logic of the application mostly based on the widgets' behavior and on the actions provided by the actual product. If you are familiar with some phone applications, like phone book or calendar, you can probably understand what the application does by studying the model.
|Figure 3. Conference Application: The figure shows the design for a conference application intended to run on a Symbian/S60 phone.|
From the design in Figure 3
, the generator produces function-based code that the target device or an emulator can compile and execute. The generator itself is structured into modules, one generator module for each modeling concept. For example, one generator module takes care of lists, another handles confirmation dialogs etc. Because several concepts require generation of similar code, such as flow of control to the next concept, parts of the generator definitions are made into subroutines used in several places. The generator includes some framework code for dispatching and for multi-view management (different tabs in the pane). Here's some sample Python code generated from the design in Figure 3
01 import appuifw
02 import messaging
04 # This app provides conference registration by SMS.
33 def List3_5396():
34 # List Check Credit card Invoice
35 global Payment
36 choices3_5396 = [u"Check", u"Credit card", u"Invoice"]
37 Payment = appuifw.selection_list(choices3_5396)
38 if Payment == None:
39 return Query3_1481
41 return SendSMS3_677
85 def SendSMS3_677():
86 # Sending SMS Conference_registration
87 # Use of global variables
88 global PersonName
89 global Payment
90 string = u"Conference_registration "\
91 +unicode(str(PersonName))+", "\
93 messaging.sms_send("4912345678", string)
94 return Note3_2227
101 def Stop3_983():
102 # This applications stops here
103 return appuifw.app.set_exit
107 f = Note3_2543
108 while True:
109 f = f()
The generator starts by outputting module import
statements (lines 12) based on the services used. First, the overall application UI framework, and thenbecause the model contains SMS actions (yellow envelope symbols)the messaging module. The comment following the import
statements is simply taken from the documentation entry specified in the design. Next, the code defines each service and widget as its own function. Rather than producing functions in an arbitrary order, the generator produces functions arranged by type, for example, all list functions followed by SMS/text message functions etc.
Lines 3341 describe the code for the payment method selection that uses a list widget. After defining the function name and comment, the code declares a global Payment
variable. Line 36 shows the list values as Unicode in a local variable, and line 37 calls the List widget provided by the framework. The code handles sending SMS messages (lines 8594) in a similar way to the List widget. Line 93 calls the imported SMS module's sms_send
function. The generator takes the parameters to the function (recipient number
, message keyword
) from the model, and handles forming the right message syntax. These messages are clearly defined, always using the same pattern.
The end of each function includes code to call the next function based on user input. For sending an SMS, the generator simply follows the application flow (line 94), but for list selections, the situation is little more complex. Depending on the user's selection from the list, different alternatives can exist. While in this case the code always takes a single path forward regardless of the value chosen from the list, there is the implicit possibility of a cancel operation (pressing the Cancel or Back button). The generator automatically creates operation-cancelling code to return execution to the previous widget (lines 3839), or if a choice was made, moves on to send the SMS (lines 4041). Having the DSM implicitly handle Cancel or exception actions is just one extra way to make describing applications simpler. In other words, the modeler doesn't need to do anything in most cases, only specifying behavior that differs from the default (such as the diagonal Cancel relationship to the end state from the first menu).
In the final function, the generator creates application exit code based on the application's end state (see lines 101103). Finally, a dispatcher starts the application by calling the first function (line 107). This function, like all the others, returns the next function to call, and lines 108109 handle calling the next function after each function has finished. Handling the calls this way, rather than having each function itself call the next function, provides a kind of tail recursion to reduce stack depth when moving from one function to the next.
This case highlights an interesting benefit of DSM; the modeling language is totally independent of the generated programming language. As Symbian phones also support C++ and Java, you can change the generator without changing the designs to generate an identically behaving application in a different target language.