Adding a New Functionality to the DotNet Translator

The process consists of the following steps:

1) Add a stub method to Pravda.cs without implementing any functionality. 2) Describe the translation of the method in CallsTranslation 3) Write a test C# program that uses this method. Place the appropriate tests to parser, translation and teskit folders.

Stub the Method into Pravda.cs

For example, when adding the static method ProgramAddress to the Info class, we can define the stub method as follows:

public static Bytes ProgramAddress() { return null; }

The returning value is irrelevant. You can return the default value for the returning type.

Method Translation in CallsTranslation

Changing the Stack During Method Execution

We need to tell the translator how the stack is changed during the method execution. For this purpose, we should add a pattern-match case to the deltaOffsetOne function, which is similar with regard to other methods.

For example, the ProgramAddress() method takes no parameters, but returns one value. This means, that the stack height is changed by +1. If the method takes two parameters and returns one value, then the stack height is changed by -1.

Method Translation to Pravda VM Opcodes

We need to add a pattern-match for the Call case with our method (which is similar with regard to other methods from Pravda.cs) in the function asmOpsOne. There, we need to implement the method using Pravda VM opcodes.

For example, for the ProgramAddress() method we have the PADDR opcode, enabling us to write the following:

case Call(MemberRefData(TypeRefData(_, "Info", "Expload.Pravda"), "ProgramAddress", _)) =>
  Right(List(Operation(Opcodes.PADDR)))

Parser and Translation Tests

At first, we need to add a C# test program to the dotnet-tests/resources/ folder.

Parser

We need to create a file with the .prs extension in dotnet/src/test/resources/parser. The file name can be chosen arbitrarily.

The file should contain preconditions which describe the dotnet compilation steps:

dotnet-compilation:
  steps:
  - target: Pravda.dll
    sources:
    - PravdaDotNet/Pravda/Pravda.cs
    optimize: true
  - target: <C# program name>.exe
    sources:
    - Pravda.dll
    - dotnet-tests/resources/<C# program name>.cs
    optimize: true
---

The next command completes the test file with the expected parsing result.

sbt dotnet/test:runMain pravda.dotnet.ParserSuite --overwrite

Translation

Create a file similarly to the one described above, but in this case the file extension should be .trs and the file should be created in the dotnet/src/test/resources/translation folder.

The next command completes the test file with the expected translation result.

sbt dotnet/test:runMain pravda.dotnet.TranslationSuite --overwrite

Adding Tests to the Testkit

We need to add the runtime test to the respective folder in the testkit.

The test file should have the .sbox extension and contain the following minimum set of the preconditions:

stack:
  [utf8.name of method from test C# program]
storage:
  utf8.init: "null"
dotnet-compilation:
  steps:
  - target: Pravda.dll
    sources:
    - PravdaDotNet/Pravda/Pravda.cs
    optimize: true
  - target: <C# program name>.exe
    sources:
    - Pravda.dll
    - dotnet-tests/resources/<C# program name>.cs
    optimize: true
---

As you can see, it contains three preconditions:

  • the method name from the test C# program, that should be put on the top of the stack
  • the program should be initialized and to do this, we put the following key-value pair to the storage: key = "utf8.init", value = "null"
  • the dotnet compilation steps