Skip to content

Migrating to v2

Trin Wasinger edited this page Oct 24, 2024 · 11 revisions

This article describes upcoming changes

Preprocessor

Older versions of MTSC used a C like preprocessor; however, new versions provide one more like Rust's procedural macros. This fixes several quirks*, reduces the likelihood of future bugs, and is over all more powerful and flexible.

* e.g. procedural macros do not expand in backtick strings unlike prior macros

Procedural Macros

At the most abstract level, MTSC's procedural macros are simply an identifier followed by two non-null assertions (foo!!) that act as a trigger for syntax transforms. Usually proc macros will be used in one of three ways:

  • Values - This is the simplest type of procedural macro. It simply replaces the macro with some value. For example, file!! becomes a string holding the current file name.
  • Functions - Functional proc macros act on the AST of their arguments and replace themselves with some expression. For example, strc!!(1 + 1) becomes the string '1 + 1' and include!!('example.ts') injects the contents of the file example.ts.
  • Annotations
/*
 * Many prior preprocessor directives are now proc macro functions. 
 */
///#include "file.ts"
include!!('file.ts');

///#include <file.ts>
include!!('<file.ts>')

///#embed 'file.bin'
embed!!('file.bin')

///#error Error Text
error!!('Error Text')

///#warning Warning Text
warning!!('Warning Text')

/*
 * _Pragma and __pragma have also been replaced by a proc macro.
 */
///#pragma ...
_Pragma("...")
__pragma(...)
pragma!!(...)

///#pragma once
pragma!!(once)

///#pragma region
pragma!!(region)

///#pragma endregion
pragma!!(endregion)

/*
 * Instead of if, elif, and else directives, use compile-time expressions inside of plain if statements.
 * As a special case to cexpr, when evaluating to a falsey value in an if condition, that branch is removed, and if evaluating to truthy, then the branch replaces the statement. 
 */
///#if EXPR
A()
///#elif EXPR
B()
///#else
C()
///#endif

if(cexpr!!(EXPR)) {
    A()
} else if(cexpr!!(EXPR)) {
    B()
} else {
    C()
}

/*
 * The __TIME__ and __DATE__ macros can also be replaced with compile-time expressions.
 * Note that the format of __DATE__ below is slightly different.
 */
console.log(__TIME__)
console.log(cexpr!!(new Date().toTimeString().split(' ')[0]))

console.log(__DATE__)
console.log(cexpr!!(new Date().toDateString().slice(4)))

/*
 * __FILE__ and __LINE__ are also proc macros
 */
console.log(`${__FILE__}:__LINE__`)
console.log(`${file!!}:${line!!});

define/undef

Removed Features

The following features have been removed since they are unneeded with proc macros or were artifacts of C:

  • ///#pragma mtsc eval(arg) - no longer required since directives are now proc macros and macros can call other macros
  • ///#include_next
  • __has_include()
  • ///#ifdef, ///#ifndef
  • __NEWLINE__
  • C Digraphs

Unimplemented and Planned Features

The following features are currently missing but will be added back later:

  • __BASE_FILE__
  • __INCLUDE_LEVEL__
  • __MAIN__
  • __MTSC_VERSION__
  • defined()
  • Command line macros like -DDEBUG

The following features may be readded if found to be needed:

  • ///#pragma mtsc line(arg)
  • ///#line

The following features will be added soon:

  • namespaced proc macros (foo.bar.baz!!)
  • global transforms
  • ability to undefine macros

New Features

  • env!!(name)
  • strc!!(expr)
  • cexpr!!(expr)