Code Snippets

Table of Contents

Overview

Actifsource supports a special editor, the so-called Code Snippet editor, which allows the user to insert Actifsource resources as variables or functions into snippets of source code. Such a snippet of code is essentially a list of statements written in C-, where C- is a subset of the programming language ANSI C. A more precise definition of C- will be given below. Actifsource then provides the possibility to generate code in an arbitrary target language from these code snippets. This is achieved by parsing the input code according to the grammar of C- and applying either built-in or user-provided templates to the resulting parse tree. This parse tree is actually a model composed of temporary (i.e. non-persistent) resources. The following example shows a code snippet here the underlined identifiers are resources used as variables and functions:

image324 image324

Defining Code Snippet Relations

First, we will show how to add a code snippet relation to a class and define all the necessary properties of this relation. Such a relation enables the code snippet editor on instances of this class and allows a user to add code written in the chosen input language to the resource. Most of the examples and screenshots in the following are taken from the Code Snippet tutorial available at http://www.actifsource.com/tutorials/index.html. This tutorial is based on the following meta-model for statemachines and shows how to add code snippets for conditions on transitions and for actions taken when a condition is executed.

image325 image325

To add code snippets to resources of type MyClass, you have to edit MyClass in the resource editor, add a new property and choose the type StructuredCodeSnippetRelation for the relation in the Type Selection dialog:

image326 image326

In the resulting property, you have to create the following statements: subjectObjectCardinality, objectCardinality and name as for Own- or Association (see Section 4.3).

Additionally, we define the CodeSnippetRelationAspect as shown below with the class

ch.actifsource.codesnippet.metamodel.aspect.impl.StructuredCodeSnippetRelationAspect.

image327 image327

Language

Next, we choose an input language for the code snippet.

image328 image328

The input language is used to check the input code syntactically and to highlight keywords of the language. Furthermore, the input language defines which parser will be applied to the input code when generating output code from the code snippet. See Section 10.3 for a description of the available input languages.

Tokens

Finally, we need to define which resources will be available as functions and variables in the code snippet editor. This is done by creating one or more token statements referring to a RelationTokenProvider. The RelationTokenProvider allows the user to define a selector (cf. Section 8.3.12) which defines a list of resources. Additionally, it allows you to choose a tokenType which is either

  • ch.actifsource.codesnippet.metamodel.TokenType.Variable for variables or
  • ch.actifsource.codesnippet.metamodel.TokenType.Function for functions.

image329 image329

For variables you can define sub-tokens. The definition of sub-tokens instructs the Content Assist to propose all resources defined by the selector of the sub-token when you insert a '.' after a token. This means that sub-tokens can be used to insert resources as identifiers of fields in structs where the token corresponds to the struct and the sub-token to the field (for details see Section 0 below).

Input Languages

At the moment, the following languages are available: C-, CMinusCondition and Text.

C-

The language C- is a (proper) subset of the language ANSI C. It has the following restrictions:

  1. C- supports no declarations (of variables, functions or types)

  2. C- does not support the use of pointers and addresses

  3. C- does not support type casts

  4. C- does not support conditional statements (Expression ? Expression : Expression). However, they can easily be replaced by equivalent if-statements.

  5. The comma operators is not supported, i.e., expressions such as

    • X = 2, z = 42
    • Foo(x,(y=2,y)) are not valid.
  6. Postfix and prefix increment and decrement operators (++,--) are not supported.

C- supports access to fields of structs. As identifiers for fields either variables or arbitrary identifiers are valid. The Content Assist provides proposals for fields of structs if the variable definitions are created accordingly (see Section 10.4.1 ).

C- knows the following list of keywords: break, else, switch, return, continue, for, default, do, if, while, until, case.

Furthermore, the language knows the following operators:

  • Infix-Operators { ||,  &&|^&==!=<><=, >=<<>>, +-*,  /, %}
  • Prefix-Operators { !, ~, +, -}
  • Assignment-Operators {=, *=, /= , %=, +=, -= , <<= , >>= , &=, ^= , |=}

CminusCondition

A code snippet with CMinusCondition allows the user to input a conditional expression as in ANSI C (e.g. a relational or equality expression) while the same restrictions apply as for C- (details see Section 10.3.1). Such an expression can then be used for example as the condition in an if-statement.

Text

Text allows the user to insert arbitrary text with resources added as either variables or functions. This language should only be used if C- is too restrictive and validation of the input code is not required. The input code is syntactically not validated[^1] and the resulting parse tree is very simple:

image330 image330

Code Snippet Editor

The code snippet editor is available in the resource editor for any property of type StructuredCodeSnippetRelation. The editor supports multi-line input. It highlights keywords and comments according to the language property of the StructureCodeSnippetRelation. You can inspect the definition of the input language by CTRL+Left-Click on the chosen language:

image331 image331

This opens the chosen language in the resource editor and allows you to browse the properties such as keywords and style of comments of the language:

image332 image332

Content Assist

By using CTRL+Space in the code snippet editor you can as usual call the Content Assist. The Content Assist will show you all available resources to insert as functions and variables. The set of available resources is defined by the property token on the corresponding StructuredCodeSnippetRelation (see Section10.2). Inserted resources are underlined with blue color.

  • Structures The StructuredCodeSnippetRelation supports the definition of complex and nested data types such as structs by defining a set of subtokens for a token. After inserting an instance of a token into the code snippet editor followed by a '.' (struct field access in C-), the Content Assist will propose the list of all resources defined by the selectors of its sub-tokens.

Consider for example the following meta-model:

image333 image333

Furthermore, we consider a StructuredCodeSnippetRelation on class A with the following definition of tokens:

image334 image334

We can now create a resource a1 of type A and insert code into the code snippet editor. When calling the Content Assist after inserting b1 it proposes the list c1, c2 (available through the Selector B.c) and d1 (available through the Selector B.d). See first screenshot below.

Info

Note that it is also syntactically correct to insert arbitrary strings as identifiers for fields of structs. After inserting one or more such identifiers followed by a '.', the Content Assist will again propose the list of root elements (tokens) independently of possible resources before the string (see second screenshot below).

It is not possible to define structures recursively. Thus, you have to explicitly define the whole structure to the desired (finite) depth if it is self-referential.

image335 image335

image336 image336

Validation and Errors

The syntax of the input code in the code snippet editor is continuously validated. Syntax errors are shown by underlining the errors in the code and adding an error description to the Model Inconsistencies view:

image337 image337

Code Generation

In this section, we will show how to generate code in an arbitrary target language from code snippets. As explained in the introduction of this chapter, the input code of a code snippet is parsed by a parser that depends on the chosen input language (e.g. C- or Text). From the resulting parse tree, Actifsource generates a model that is composed of temporary resources. The meta-model for parse trees of the language C- is available at http://www.actifsource.com/manuals/index.html. The parse tree for unvalidated input (Text) can be found in Section 10.3.3.

To generate output files from these temporary models, we can apply code templates or template functions to these temporary resources, i.e., the temporary resources behave in exactly the same way as persistent resources except that they are not shown in the resource browser (Project Explorer) and are deleted when the session ends (e.g. the project or the workspace is closed). To use the content of code snippets in templates, you can either use the built-in TemplateFunctions (see Section 10.5.1) or write your own templates or template functions by modifying the built-in templates or writing them from scratch. The behavior of the built-in template functions can be customized by overwriting the way names of variables and functions are created (see Section Overwrite Variable and Function Names (Name Provider) below).

Built-in Template Functions

Actifsource provides the following built-in template functions which are defined on resources of type ch.actifsource.codesnippet.metamodel.element.CodeSnippet:

  • codeSnippetToST: generates Structured Text from a CodeSnippet with input language CMinus or CMinusCondition.
  • codeSnippetToC: generates C code from a CodeSnippet with input language CMinus or CMinusCondition.
  • codeSnippetToText: generates code from a CodeSnippet with input language Text (unvalidated code).
  • codeSnippetToFormattedC: generates formatted C code (HTML) from a CodeSnippet with input language CMinus or CMinusCondition (the actual code is the p)
  • codeSnippetToVHDL: generates VHDL code from a generates C code from a CodeSnippet with input language CMinus or CMinusCondition

For all the above template functions, the names of variables and functions in the output code are generated by calling the function simpleName@BuiltIn on the corresponding resource.

Info

Note that the above template functions which are written for input languages CMinus and CMinusCondition can also be applied to Text. The output is the same as when calling the function codeSnippetToText in this case.

Overwrite Variable and Function Names (Name Provider)

Generating the names of variables and functions by calling simpleName@BuiltIn, is in practice not always sufficient to generate code that meets all the requirements (the requirements on the naming could depend on naming conventions of the target language or names of variables could depend on the context in which the corresponding resource is used). For these cases, Actifsource provides more flexible template functions which takes a Literal of type ch.actifsource.codesnippet.metamodel.parsetree.template.NameProvider as an additional parameter:

  • codeSnippetToSTwithNameProvider

  • codeSnippetToCwithNameProvider

  • codeSnippetToText

  • codeSnippetToFormattedC

  • codeSnippetToVHDL

Apart from the generation of function and variable names, these templates have exactly the same behavior as the corresponding template functions from the section above.

The additional parameter to this functions can be used to store additional context information necessary to generate the names and to overwrite the functions used to generate the names, namely variableName@TokenToName and functionName@TokenToName. These two functions take a parameter of type Resource (the resource corresponding to the variable resp. function) and generate the name by calling NameProvider.variableName@TokenToName resp. NameProvider.functionName@TokenToName:

image338 image338

image339 image339

The Code Snippet tutorial available at http://www.actifsource.com/tutorials/index.html show how to implement a NameProvider by guiding you step-by-step through an example.

Implement a custom NameProvider

In general, one can implement and use a NameProvider as follows:

  1. Write a LiteralAspect (e.g. MyNameProviderLiteralAspect) in Java which implements ch.actifsource.core.model.aspects.impl.IGenericLiteralAspect<MyNameProviderLiteralAspect>. image340 image340

  2. Create your own resource of type Literal (e.g. MyNameProvider) which extends ch.actifsource.codesnippet.metamodel.parsetree.template.NameProvider: image341 image341

  3. Create a Java interface (e.g. IMyNameProvider) which provides the members needed to manage and store the context information needed by the NameProvider. image342 image342

  4. Create a FunctionSpace (e.g. MyNameFunctions) which extends TokenToName with a FunctionContext for the newly created Literal type (e.g. MyNameProvider). Create the two functions variableName and functionName with exactly the same signature as corresponding functions in the TokenToName.

    image343 image343

    image344 image344

  5. Write a JavaFunctions (e.g. createMyNameProvider) that generates an instance of the newly created Java interface (e.g. IMyNameProvider).

    image345 image345

  6. In the template where the function to<Language>withNameProvider is used, call the newly created JavaFunction (createMyNameProvider) and call to<Language>withNameProvider with the output of the JavaFunction.

image346 image346

Info

Note that the TemplateFunctions presented in Section 10.5.1 generate the names by internally calling the name functions variableName and functionName on ch.actifsource.codesnippet.metamodel.parsetree.template.NameProvider (the default NameProvider). Thus, overwriting these functions in a FunctionSpace that extends TokenToName for the type NameProvider (see example below) also changes the behavior of this TemplateFunctions without NameProvider (e.g. toC@CodeSnippetToCode). This can, in particular, change the behavior of already existing templates and template functions. Therefore, this approach should normally be avoided and a customized NameProvider implemented instead.

image346 image346

Display Code Snippets in Diagrams

Since the parse trees created from the input code of a code snippet are temporary resources, they are only visible for the code generator. To use the content of code snippets in diagrams, Actifsource provides template functions which allow you to display the code in diagrams:

  • displayCodeSnippet
  • displayCodeSnippetSingleLine

These TemplateFunctions show the unprocessed code as it is entered by the user in the code snippet editor. Both functions are defined on resources of type ch.actifsource.codesnippet.metamodel.element.CodeSnippet. An example application of these functions can be found in the Installing Actifsource](/tutorials/\20_enterprise/60_code-snippet) .