Skip to content

Translates source for the SplashKit SDK into other languages

License

Notifications You must be signed in to change notification settings

splashkit/splashkit-translator

Repository files navigation

SplashKit Translator

Translates the SplashKit C++ source into another language.

Contents

Running

Docker

This project can be setup on any platform through the use of Docker containers. A docker file can be found in the root of the repository, information on how to get setup and running with can be found in Docker_README.md

Dependencies

Ensure you have HeaderDoc installed:

  • Under macOS, you will need to have Xcode with Developer Tools installed.
  • Under Ubuntu, you can download HeaderDoc at Apple's OpenSource Developer Tools here.

Install dependencies using bundle:

bundle install

Then run using translate.

Known Issues

  • macOS Bundle Install error

    If you get the following error when running bundle install:

    can't find gem bundler (>= 0.a) with executable bundle (Gem::GemNotFoundException)

    You need to use a Ruby Version Manager to install Ruby 2.7.5, rather than using the default version of Ruby that comes with macOS.

Validating

To validate a single file or files, supply the --validate or -v switch and the --input or -i switch with the header file you wish to validate:

./translate --validate --input /path/to/splashkit/coresdk/src/coresdk/audio.h

This will only validate input that it can be correctly parsed, but will not generate any translated code.

Alternatively, you can validate all header files by supplying just the SplashKit coresdk/src/coresdk directory instead:

./translate -v -i /path/to/splashkit/coresdk/src/coresdk

Converting

To convert, follow the same as the above, removing the --validate/-v switch and supplying the translated language you would like to generate using a comma-separated list under the --generate or -g switch and specifying the output directory using the --output or -o switch:

./translate -i /path/to/splashkit -o ~/Desktop/translated -g YAML,SKLIBC,CPP

If no output directory is used, then it will default to an out/translated directory inside the input directory specified.

To see a full list of each translator available, use the --help switch.

SplashKit Documentation Guidelines

SplashKit uses HeaderDoc to parse documentation. A guide on HeaderDoc can be found here.

Ensure that snake_case is consistently used throughout documentation.

Header File Docblocks

A header file should begin with a docblock consisting of:

  1. @header [name] - The name of the 'module' of functions and types defined in the header. E.g., audio.h would be listed as Audio.
  2. @author [name] - One or many author names who have contributed to the header and/or implementation
  3. @brief [description] - A brief, one sentence description of what functionality is added in this 'module'.
  4. A longer description of the functionality. The description accepts Markdown.
  5. @attribute group [group] - Groups the contents of the file under a specific group name. Refer to group for more.

Example, audio.h:

/**
 * @header Audio
 * @author Andrew Cain
 * @brief SplashKit Audio allows you to load and play music and sound effects.
 *
 * The SplashKit's audio library allows you to easily load and play music and
 * sound effects within your programs. To get started with audio the first
 * thing you need to do is load a sound effect or music file. You can do this
 * by calling the `load_sound_effect(string name)` function to the
 * `load_music(string name)` function.
 *
 * @attribute static audio
 */

Any attributes set in a header file docblock will apply those attributes to all docblocks inside that file. In the example above, all docblocks will have @attribute static audio added to them unless @attribute static is already listed in a docblock.

Function Docblocks

A function docblock should consist of at least a basic description of the functionality provided by the function in Markdown. Where applicable, it also must have:

  • @param [name] [description] - The name and description of a parameter. These should be listed in order of the function's signature. All parameters must be listed and be consistent with the correct name(s) in the signature.
  • @returns [description] - A basic description of what is returned from the function. Any non-void function must have an @returns.
  • @brief [description] - A brief, one sentence description of what functionality is added in this function.

Each of the above should be separated with a newline and grouped together where applicable.

Example, load_sound_effect:

/**
 * @brief Loads and returns a sound effect.
 *
 * The supplied `filename` is used to locate the sound effect to load. The
 * supplied `name` indicates the name to use to refer to this `sound_effect`.
 * The `sound_effect` can then be retrieved by passing this `name` to
 * the `sound_effect_named` function.
 *
 * @param name      The name used to refer to the sound effect.
 * @param filename  The filename used to locate the sound effect to use.
 *
 * @returns A new `sound_effect` with the initialised values provided.
 */
sound_effect load_sound_effect(string name, string filename);

Enum Docblocks

An enum docblock must define every one of its constants using the @constant tag. For example:

/**
 * Defines each of the five weekdays
 *
 * @constant Monday     The day where you want to go sleep
 * @constant Tuesday    The day where you start to get stuff done
 * @constant Wednesday  The day where you realise you're only midway through
 * @constant Thursday   The day where you can smell Friday coming
 * @constant Friday     The day where you party hard
 */
enum weekdays {
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday
};

Struct Docblocks

A struct docblock must define each of its field members using a @param tag. For example:

/**
 * Defines basic details for a person
 *
 * @param name    The name of the person
 * @param age     The age of the person
 * @param friend  The person's bestest friend in the whole world
 */
struct person {
  string name,
  int age,
  person *friend
};

Typedef Docblocks

A function docblock should consist of at least a basic description of the functionality provided by the function in Markdown.

Attributes

Attributes provide options to the language translator. They are applicable to functions and typedef docblocks. Attributes are declared as thus:

/**
 * @attribute [key] [value]
 */

Here is a list of all accepted attribute keys:

class

Usage in typedefs

When added to a typedef, the type will be declared as a class:

/**
 * ...
 *
 * @attribute class sound_effect
 */
typedef struct _sound_data *sound_effect;

Note that typedef aliases to pointers must be declared with a class attribute.

Usage in functions

Associates the sound_effect type to an object-oriented-translated SplashKit class instance.

When added to a function, the type will be associated to a class. You must pair this with method, constructor, destructor, getter, or setter attribute (see below) to define how the function will be associated to under that class.

/**
 * ...
 *
 * @attribute class  audio
 * @attribute method close
 */
void close_audio();

This will convert the above to an equivalent OO method:

Audio.Close()

static

Indicates the module or class name to which a global method or function is applied. Can be associated to a method name to create a static method on a class or global function on a method, or a static getter or setter.

Refer to method for more.

method

Associates a function to a class. Requires the class or static attribute to be set. The name specified by method will be the method name that will be used as the method on the class. See the above example.

When method is used with the class attribute, an instance method will be generated on the class whose name is specified by class.

When method is used with the static attribute, a static method will be generated on the class whose name is specified by static.

constructor

Associates a function as the constructor to a class.

Requires the class attribute to be set in order to construct an instance of that class.

To mark a constructor, simply set the value as true:

/**
 * ...
 *
 * @attribute class       sound_effect
 * @attribute constructor true
 */
sound_effect load_sound_effect(string name, string filename);

This will convert the above to an equivalent OO constructor:

SoundEffect(string name, string filename)

If defining a constructor, then you cannot violate this attribute with a destructor attribute in the same HeaderDoc block.

Unless static is specified, then a destructor function cannot also act as a instance getter, setter or method.

destructor

Same as constructor, but for a destructor.

Requires the class attribute to be set in order to destruct an instance of that class.

Similarly, to destruct a particular instance, the instance object will be passed into the parameter specified by a self attribute. Thus self must be set on destructors.

For example:

/**
 * ...
 *
 * @attribute class       sound_effect
 * @attribute self        effect
 * @attribute destructor  true
 */
void delete_sound_effect(sound_effect effect);

This would call the delete_sound_effect on the instance, where the instance is the effect parameter:

delete someSoundEffectInstance;

If defining a destructor, then you cannot violate this attribute with a constructor attribute in the same HeaderDoc block.

Unless static is specified, then a destructor function cannot also act as an instance getter, setter or method.

self

Specifies the name of the parameter which should act as this or self on the function call.

When the function is converted to a method for an object-oriented language, the instance calling the method will be passed into parameter specified by self.

To know which type the self parameter would be, list the class of that parameter and make sure it matches the name of the parameter indicated by self.

For example:

/**
 * ...
 *
 * @attribute class   sound_effect
 * @attribute method  play
 * @attribute self    effect
 */
void play_sound_effect(sound_effect effect, int times, float volume);

When translated into OO:

someSoundEffectInstance.play(3, 10.0f)

will call

play_sound_effect(someSoundEffectInstance, 3, 10.0f)

When using a self attribute, you must ensure that the parameter named by self has a type which matches the class attribute value. For example, the following will cause an error since times is an int, which does not match the class attribute value of type sound_effect:

/**
 * ...
 *
 * @attribute class   sound_effect    <-------------------------------
 * @attribute method  play                                             \
 * @attribute self    times           <--- times is an int, not a sound_effect!!
 */
void play_sound_effect(sound_effect effect, int times, float volume);

suffix

For translated languages that do not support overloaded function names, the name specified by suffix name will be used as a suffix appended to the global and instance name of the function.

If class is specified, then the method name appended with suffix must be unique within that class.

If static is specified, then function name appended with suffix must be unique within that static namespace.

If neither are specified, then function name appended with suffix must be unique globally.

For example:

/**
 * ...
 *
 * @attribute static  audio
 * @attribute class   sound_effect
 * @attribute method  play
 * @attribute suffix  with_loops_and_volume
 * @attribute self    effect
 */
void play_sound_effect(sound_effect effect, int times, float volume);

will be translated into Python as:

some_sound_effect_instance.play_with_loops_and_volume(3, 10.0)
play_sound_effect_with_loops_and_volume(effect, 3, 10.0)

whereas in C# it would look like:

someSoundEffectInstance.play(3, 10.0f)
Audio.PlaySoundEffect(effect, 3, 10.0f)

getter

Creates a getter method to the class or static module specified. Requires either:

  • class and self to make an instance getter on the an instance whose class is specified by class, or
  • static to make a static getter on the class specified static.

Must be set on a function that:

  • has exactly zero or one parameters, depending on if you are using class or static, and
  • is non-void.

If you are writing a static getter, then there must be no parameters.

If you are writing a class setter, then you will need exactly one parameter, that being the parameter which will be used as self. You must not specify that the function also a method (unless static is also supplied) or a constructor or destructor.

For example, the following:

/**
 * ...
 *
 * @attribute static  audio
 * @attribute getter  is_open
 */
bool audio_is_open();

/**
 * ...
 *
 * @attribute class   query_result
 * @attribute self    effect
 * @attribyte getter  is_empty
 */
bool query_result_empty(query_result result);

generates usage for the following in C#:

if (Audio.IsOpen) { ... }
if (myDatabase.queryResult.IsEmpty) { ... };

setter

Creates a setter method on the class instance of static module. Requires either:

  • class and self to make an instance setter on the an instance whose class is specified by class, or
  • static to make a static setter on the class specified static.

Must be set on a function that has exactly one or two parameters, which depends on if you are using class or static.

If you are writing a static setter, then you will need exactly one parameter, being the second must the value that is to be set.

If you are writing a class setter, then you will need exactly two parameters, where:

  1. the first must be the parameter which will be used as self, and
  2. the second must the value that is to be set.

You must not specify that this is also a method (unless static is also supplied) or a constructor or destructor.

For example, the following:

/**
 * ...
 *
 * @attribute static  audio
 * @attribute setter  is_open
 */
void audio_status(bool open);

/**
 * ...
 *
 * @attribute class   database
 * @attribute self    db
 * @attribyte setter  last_query
 */
void database_set_query_result(database db, query_result result);

generates usage for the following in C#:

Audio.IsOpen = false;
myDatabase.LastQuery = myQueryResult;

group

Applicable only to header file HeaderDoc blocks. The value associated to group means that this particular header file is grouped under the group specified by this attribute. Related header files may be applicable to just the one, e.g.:

  • audio.h,
  • sound_effect.h, and
  • music.h

could all be grouped under the Audio group.

note

Use this to add an arbitrary note to any HeaderDoc block.

It is important to place the contents of your note on a new line.

Unknown attribute issue

Not placing your content of your note over two lines will cause issues. Refer to the example below:

/**
 * @attribute note This is a really cool function
 *   that goes over two lines woohoo!
 */
int my_func();

The above will cause the following parser issue:

Unknown attribute keys are present: `note This is a really cool function`.

To fix this, you change the example to:

/**
 * @attribute note
 *   This is a really cool function
 *   that goes over two lines woohoo!
 */
int my_func();

Unfortunately, multi-line markdown parsing will not work, such as lists, code blocks and multiple paragraphs.

Summary of Parser Rules

If any of these basic rules are violated, then the parser will throw a fatal error and stop parsing along with its respective parser rule (PR) number for reference to this list.

  1. Attributes marked with self, destructor constructor must have a class attribute specified.

  2. Attributes marked with method, getter or setter must be marked with either:

    (i) class to make it an instance method, instance getter or instance setter on instance of that class, or

    (ii) static to make it a static method, static getter or static setter on a class or module indicated by static.

  3. There can never be both constructor and destructor attributes marked together in the same HeaderDoc block.

  4. If you do not supply static, then you cannot have a constructor or destructor with a getter or setter in the same block. This would imply that there is an instance getter or instance setter along with a constructor or destructor of that instance by the one function.

  5. You cannot supply constructor or destructor and method unless static is also supplied. This will make a static method on the class or module specified by static but a destructor/constructor on the class indicated by class.

  6. Same as above, except for getters and setters.

  7. A self attribute should always have a value that matches the name of a parameter in the function.

  8. When self is specified, then the parameter name it specifies should have the same type as the class specified.

  9. A getter should always return something, and must not return void unless it is void*.

  10. When class is specified with a getter, there should always be one parameter (the parameter for self).

  11. When class is specified with a setter, there should always be two parameters:

    (i) the parameter for self, and

    (ii) the value to set.

  12. When static is specified with a getter, there should always be no parameters.

  13. When static is specified with a setter, there should always be one parameter. That is, the value to set.

  14. When suffix is used, the name must be unique to the global namespace.

  15. When suffix is used with a class and method, the name must be unique to the class namespace.

  16. When a class is used on a type alias, then the type alias must be an alias to a pointer.

About

Translates source for the SplashKit SDK into other languages

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published