Skip to content

preprocessor_proposal

Callum McGing edited this page May 17, 2022 · 10 revisions

Preprocessor proposal

Symbols

Symbols are essentially global variables available only in the preprocessor scope. The same rules applies for naming of symbols as for global variables. Values are either bool, string, double or empty.

Defining symbols

  • #define - defines a symbol
  • #undef - undefines a symbol

The base way of defining a symbol is to use #define followed by one or more whitespaces then by a symbol name composed by a single literal followed by one or more whitespaces, optionally followed by =, followed by one or more whitespaces and finally a value. A value has to be a single literal, either true, false, a double like 1, 3.14 or a string enclosed in either single or double quotes. Opening and enclosing quote has to be of the same type. 'my string', "my string". A string like 'my string" is invalid and results in a preprocessor error.

#define MY_SYMBOL = 5
#define MY_SYMBOL 5

When a symbol is defined and right hand of the definition is ommited, we treat for comparisons it as if the right hand was = true but the actual value of a symbol is empty.

#define MY_SYMBOL

Multiple definitions can be shorthanded in one line via ,. This works with both #define and #undef.

#define MY_SYMBOL = false, LOG_LEVEL = "warning", MY_VERSION = '4.0.1'
#undef MY_SYMBOL, LOG_LEVEL

Comments

All # directives can contain single line comments // which are ignored by the preprocessor interpreter. When // sequence is encountered the rest of line is ignored. The only time this does not apply is when a string literal is being parsed. #define MY_STRING = '//' is a valid usage of #define.

#define LOG_LEVEL = "warning" // this setting means something and has some known values blah blah blah... I can use #whatever here and it is ignored

Conditional compilation

  • #if
  • #elseif, #else if, #elif (all of these have the same meaning)
  • #else
  • #endif

A block *(zero or more lines of code) between #if and #endif will be compiled only if the #if's expression is truthy. Same rules apply as with normal ifs. We consider a truthy value to be true, any double greater than 0 and any string with length greater than 0.

#if "YES" // any string other than "" or '' is truthy

#endif

Comparison operators >, >=, <, <=, ==, != can be used in #if's expression, logical !, || and && operators are also supported.

#if 2 + 2 > 5 // this is illegal, will throw. We don't support arithmetical operators such as + in the preprocessor

#endif

Parentheses are supported in expressions.

#if DEBUG == (((true))) // this is a legit rhs

Parentheses around expression in #if, #elif, #elseif and #else if can be ommited but are supported.

// these two are the same
#if (DEBUG == true)
#if DEBUG

The existence of a variable can also be checked with the defined() operator. This will return true if the value is defined even if the value evaluates to false.

#if defined(VARIABLE)

Multiple branches can be added to the #if directive via #elif, #else if, #else if and #else. Alias #elif is introduced due to it's usage in C# and C. #if directive has to end with a #endif directive. If no such directive is found it results in a throw.

Errors

  • #error

To throw errors #error is used. An optional message can be included in #error as a single string (single or double quotes enclosed) literal.

#if LANGVER < 2.5
    #error "This snippet requires WattleScript at least 2.5"
#endif          

If no rhs is provided an interpreter will throw a default message with line number on which the error was raised.

Parser directives

  • #line

#line directive is used by code generators for WattleScript to translate line numbers and enable seamless debugging. There are two ways to write a #line directive:

1. #line LINE_NUMBER

LINE_NUMBER has to be an integer greater than 0 or a special literal. Known special literals are: - default - line numbering mode is set to native - anything other is an invalid special and throws

1. #line 200
2. var a = = 
3. local b = =
4. #line default
5. var c = =

// Unexpected symbol at line 200 after after "var a ="
// Unexpected symbol at line 201 after "local b ="
// Unexpected symbol at line 5 after "var c ="

2.#line LINE_NUMBER, COL_OFFSET

  • COL_OFFSET - the column offset for the #line directive to take place. The next character after COL_OFFSET characters is treated as column 1.
1. #line 2, 5
2. var a = =

// "var" in this example starts at line 2, character 6

Regions

  • #region
  • #endregion

#region directives are a feature to be used in LSP implementations as "folding ranges". Preprocessor ignores them apart from checking that each #region is enclosed with #endregion.

Predefined symbols

  • #LANGVER - a double corresponding to the WattleScript NuGet version installed on the executing system. Example values: 1.2 or 5.

We allow redefining predefined symbols. #LANGVER 10 will force the symbol to hold value 10.