The environment in Metashell
Metashell maintains an environment, which is a piece of C++ code. When you
evaluate a metaprogram in the shell (eg. fib<3>::value
), the metaprogram is
evaluated in that environment: it can use all the declarations and definitions
from the environment and the files included from the environment.
Metashell has an initial environment. To see what it contains, start a new shell and run the following command:
> #msh environment
#msh
is a short version of #pragma metashell
. Metashell accepts both, but
#msh
is easier to use. The metashell environment
pragma displays the content
of the environment. A new shell contains the initial environment.
Extending the environment
When you define a metafunction, you add the definition of that metafunction to the environment. For example by running the following command:
> template <class T> struct add_const { typedef const T type; };
You add the definition of add_const
to the environment. After running it, you
can use the metashell environment
pragma to see that it has been added.
When you type in a command (eg. template <class T> struct add_const ...
or
add_const<T>
) Metashell has to decide if it is a command instructing the shell
to evaluate a metaprogram or it is an addition to the environment. Metashell
will try to figure it out, which category your command belongs to. If you'd like
to add something to the environment, but Metashell thinks that it is a
metaprogram to evaluate, there is a pragma you can use:
> #msh environment add template <class T> struct add_const { typedef const T type; };
This will always add your command to the environment. Similarly, if you'd like to run a metaprogram, but Metashell tries adding it to the environment, there is a pragma which you can use:
> #msh evaluate add_const<int>::type
This will always evaluate your command as a metaprogram. Note that if you need to use any of these pragmas, you have found a bug in Metashell. Please file a bug report about it.
The environment stack
It might happen, that you'd like to experiment with some definitions and then return to an earlier environment. For example you have a template class, you add some extra specialisations, try running some metaprograms and you'd like to remove the specialisations and get back to the original state.
Metashell has an environment stack which you can use. You can push the current environment on this stack by running the following command:
> #msh environment push
This command does not change the environment, but saves it in a stack. You can add new definitions, include new header files and run metaprograms in that updated environment. Once you're done and you'd like to get back to the original environment, you can run the following command:
> #msh environment pop
This will restore the environment you saved by the environment push
pragma and
remove it from the environment stack. You can add multiple environments to the
stack and get back to them later. You can always check the current size of the
environment stack by running the following command:
> #msh environment stack
This command displays how many environments have been stored on the stack.
What happens to files included to the environment?
When you use #include
to add the content of a file to the environment, the
#include
line is added to the environment, not the content of the file. Every
time the environment is re-evaluated, the content of the included file is
re-read. When is the environment re-evaluated?
It depends on multiple things.
- When you add something new to the environment, the entire environment is re-evaluated. Any changes to the included header files are picked up.
- When you run a metaprogram and you have turned precompiled header usage off, the environment is re-evaluated. If you have enabled precompiled header usage, the environment is not re-evaluated.
- You can ask Metashell to re-evaluate the environment by running the
#msh environment reload
command.
Metashell uses precompiled headers to make the shell faster. When you use metaprograms you might (eg. by using Boost.MPL) need to include large header files taking a lot of time to process. If you re-evaluate them for every command the shell responds slowly. The speed can be increased significantly by creating a precompiled header of the environment. This precompiled header is rebuilt every time there are changes to the environment.
Precompiled header usage is enabled by default (if Metashell can find the
clang++
binary on your computer). You can turn it off by using the
--no_precompiled_headers
command-line argument at startup or by running the
following command in the shell:
#msh precompiled_headers off
This command disables precompiled header usage in the current shell.