-
Notifications
You must be signed in to change notification settings - Fork 13
Home
Welcome to the MetaScript wiki! For now, the wiki contains a few non-trivial insights on writing meta.
- A source is the source that you are working with, containing your custom meta.
- A meta program is what your source becomes when compiled through MetaScript.
- A scope contains the compile time options that your custom meta uses.
- A transformed source is what your source becomes through executing its meta program with a specific scope.
//? if (NODE)
buffer.writeInt8(offset, value);
//? else
view.setInt8(value, offset);
This will actually work without using curly braces as long as there is just one line following, because each source line is wrapped by a dedicated write(...)
call, resulting in the following meta program:
if (NODE)
write('buffer.writeInt8(offset, value);\n');
else
write('view.setInt8(value, offset);\n');
In default notation, variables and functions are local to the file they have been declared in. So, if you intend to declare a global variable or function, just do it explicitly:
Variables:
//? var NODE = true; // Local
//? NODE = true; // Global
Functions:
//? function doit() {} // Local
//? doit = function() {} // Global
The MetaScript compiler makes sure to retain any white spaces and line breaks with one important exception: If a meta line or block, which is not a ?=
expression, is the only contents of a line, the entire line will be skipped. Let's modify the example from above to demonstrate why this is useful:
if (true) {
//? if (NODE)
buffer.writeInt8(offset, value);
//? else
view.setInt8(value, offset);
}
The result of the above will not contain any white spaces or new lines where the meta statements are, like for NODE=true
:
if (true) {
buffer.writeInt8(offset, value);
}
Which looks much cleaner.
If you explicitly require indentation, you may use either a ?=
expression, the __
variable or even call the indent(str:string, indent:string|number):string
utility manually. Example:
// This will be indented (it's a ?= expression):
//?= 'var i=0;'
// Just like this (it uses manual indentation):
//? write(indent('var j=0;\n', 4));
// Or this (it prepends __):
//? write(__+'var k=0;\n');
// But this will not:
//? write('var k=0;\n');
Results in:
// This will be indented (it's a ?= expression):
var i=0;
// Just like this (it uses manual indentation):
var j=0;
// Or this (it prepends __):
var k=0;
// But this will not:
var k=0;
When inspecting the generated meta program, you will notice that the variable __
is used quite frequently. It stores the indentation level of the last meta block processed. For example ...
//? if (NODE)
//? include("node-stuff.js");
//? else
//? include("browser-stuff.js");
... will indent the contents of the included files by ' ' (four spaces), just like before //?
, while ...
/*? if (NODE)
include("node-stuff.js");
else
include("browser-stuff.js"); */
will not, just like before /*?
. When creating custom utility functions, it's of course safe to use this variable on your own.
-
__out
Contains the so far generated output as an expanding array. -
__source
Source code of the currently processed source file. -
__program
Source code of the currently running meta program. -
__filename
File name of the currently processed source file. -
__dirname
Directory of the currently processed source file. -
__version
MetaScript version used to compile the currently running meta program.
JavaScripts surely allows a developer to do lots, if not all, of the work at runtime, switching to different fallbacks in varying environments. We all know this from making stuff work in multiple browsers and in lots of cases this is absolutely legit because there are simply no alternatives.
However, since technology like node.js came up, what we understand by different environments has changed a bit: Imagine you have a library that, for maximum performance, uses ArrayBuffers in the browser and Buffers, which are much faster than ArrayBuffers but not available in the browser, on node. Or node modules vs. polyfills and stuff like that. At worst, the result would be a heavily bloated library that implements lots of the functionality multiple times for the different APIs or at best multiple layers of wrappers around the fundamental types. Now imagine that this library is also meant to be used in the browser and that you do not want the redundant node-functionality to be downloaded every time a user visits it. Or that every microsecond counts because you are writing a realtime game. You see, it will work but is not optimal and you might consider writing some meta that produces a node and a browser version of your library from a single source tree.
This is mostly a question of style and a bit of what toolset you require at compile time. Usually, once you require more tools, using MetaScript (on node.js) will provide you with a programmer's paradise where a preprocessor will let you hanging.