14 releases
0.6.2 | Sep 22, 2021 |
---|---|
0.6.1 | Sep 22, 2021 |
0.6.0 | Aug 31, 2020 |
0.5.0 | Dec 17, 2019 |
0.1.0 | Nov 1, 2019 |
#2064 in Rust patterns
156 downloads per month
Used in 2 crates
(via web-rwkv)
28KB
605 lines
gpp
This is a simple generic C-like preprocessor for Rust. See the documentation (cargo doc --open
) for details.
lib.rs
:
gpp is a Generic PreProcessor written in Rust.
It supports:
- Simple macros, no function macros
- #include
- #define and #undef
- #ifdef, #ifndef, #elifdef, #elifndef, #else and #endif
- #exec for running commands
- #in and #endin for giving input to commands
#includes work differently from C, as they do not require (and do not work with) quotes or <>,
so #include file.txt
is the correct syntax. It does not support #if or #elif, and recursive
macros will cause the library to get stuck.
About
The hash in any command may be succeeded by optional whitespace, so for example
is valid, but
# undef Macro
is not.
#define and #undef
#define works similar to C: #define [name] [value]
, and #undef too: #undef [name]
. Be
careful though, because unlike C macro expansion is recursive: if you #define A A
and then
use A, gpp will run forever.
If #define is not given a value, then it will default to an empty string.
#include
Includes, unlike C, do not require quotes or angle brackets, so this: #include "file.txt"
or
this: #include <file.txt>
will not work; you must write #include file.txt
.
Also, unlike C the directory does not change when you #include; otherwise, gpp would change its
current directory and wouldn't be thread safe. This means that if you #include dir/file.txt
and in dir/file.txt
it says #include other_file.txt
, that would refer to other_file.txt
,
not dir/other_file.txt
.
Ifs
The #ifdef, #ifndef, #elifdef, #elifndef, #else and #endif commands work exactly as you expect. I did not add generic #if commands to gpp, as it would make it much more complex and require a lot of parsing, and most of the time these are all you need anyway.
#exec, #in and #endin
The exec command executes the given command with cmd /C
for Windows and sh -c
for
everything else, and captures the command's standard output. For example, #exec echo Hi!
will
output Hi!
. It does not capture the command's standard error, and parsing stops if the
command exits with a nonzero status.
Due to the security risk enabling #exec causes, by default exec is disabled, however you can
enable it by changing the allow_exec
flag in your context. If the input tries to #exec
when
exec is disabled, it will cause an error.
The in command is similar to exec, but all text until the endin command is passed into the program's standard input. For example,
#in sed 's/tree/three/g'
One, two, tree.
#endin
Would output One, two, three.
. Note that you shouldn't do this, just using #define tree three
would be much faster and less platform-dependent. You can also place more commands in
the in block, including other in blocks. For a useful example:
<style>
#in sassc -s
# include styles.scss
#endin
</style>
This compiles your scss file into css using Sassc and includes in the HTML every time you generate your webpage with gpp.
Literal hashes
In order to insert literal hash symbols at the start of the line, simply use two hashes.
##some text
will convert into #some text
, while #some text
will throw an error as some
is not a command.
Examples
// Create a context for preprocessing
let mut context = gpp::Context::new();
// Add a macro to that context manually (context.macros is a HashMap)
context.macros.insert("my_macro".to_owned(), "my_value".to_owned());
// Process some text using that
assert_eq!(gpp::process_str("My macro is my_macro\n", &mut context).unwrap(), "My macro is my_value\n");
// Process some multi-line text, changing the context
assert_eq!(gpp::process_str("
#define Line Row
Line One
Line Two
The Third Line", &mut context).unwrap(), "
Row One
Row Two
The Third Row
");
// The context persists
assert_eq!(context.macros.get("Line").unwrap(), "Row");
// Try some more advanced commands
assert_eq!(gpp::process_str("
Line Four
#ifdef Line
#undef Line
#endif
Line Five", &mut context).unwrap(), "
Row Four
Line Five
");
Dependencies
~125KB