Some changes proposed for discussion
Opened this issue · 0 comments
As a base, I propose to consider macros.
Which can be used in the following ways:
- Function like macro
- User-defined attribute
- Definition keyword
Changes for strawman syntax notes:
Replace current:
constexpr void my_metaclass(T target, S source) { ... }
by:
consteval meta::tokenstream my_macro(const meta::tokenstream input) { ... }
Reason for use meta::tokenstream instead meta::type
Separate AST's implementation from the compiler
Also, implement AST's library as part of the std library. Reason for it - separate AST's implementation from the compiler.
So, we have to way to:
- use the built-in library and convert the stream of tokens to AST's form
- relying on AST's standardized library to do some optimizations
Note:
Simplest optimization example that comes to mind - we can skip transformation if have implemented AST's library as set of wrappers or if the compiler's internal representation is the same as standardized AST (which is unlikely, but possible).
A similar idea is presented in 1.3.4 Querying changes made on a local copy
Add user possibility choose the implementation with which it is convenient for them to work.
Allow creating a built-in DSL language
Also, it will allow creating a built-in DSL language. For example:
Mathematics based if
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p0893r1.html
mif( a > b > c) {
} else if( a && b){
} mif( (a + b < a) != c){
}
Backus–Naur form
It can help a project like Boost.Spirit
Also, It will be possible to implement such things as JSX
...
SQL validators
https://github.com/sfackler/rust-postgres-macros
#![feature(plugin)]
#![plugin(postgres_macros)]
fn main() {
let query = sql!("SELECT * FROM users WHERE name = $1");
let bad_query = sql!("SELECT * FORM users WEHRE name = $1");
}
Allow abandon preprocessor capabilities
...
Refuse injection or __extend
Violates the principles Be consistent and Be general
Using the AST library we should transfer tokens into AST representation. After we can work with AST like we work with vector or list. If we need to add function, we must first construct it and then put it into the class itself using the member function
Reflection should not be part of the language
https://cplusplus.github.io/reflection-ts/draft.pdf
If we can convert tokens to AST, do we need a special reflection built into the language?
In fact, we are talking about the magic type meta::tokenstream. Which say the compiler pass tokens to the compile-time environment or inject token compile unit.
Homogeneity of compile-time environment
More, more Be general.
Code written once works both in runtime and in compile time.
When we talk about the compile-time environment, we can present this as a separately compiled program instance with a modified entry point to our macro (The implementation is not fundamentally. Of course, at best, expect an interpreter/bytecode machine/JIT).
So, what do I mean by homogeneity? We don't need compiler.error(“message”, m) because we already have print or cout, we also don't need dm.source_location(), we already have meta::tokenstream it is enough to have the starting position like field. Keeping the idea. We must have the same capabilities as in runtime, for example, to be able to open files.
The latter is very important for generators such as go-swagger.
Determinism and portability
There is a significant problem and this should be recognized, therefore some parts of the language cannot be used:
- code with UB
- asm inserts
However, for large codebases, this solution can create significant problems. As a solution, the proposed attribute [[meta::allow_unsafe]].
To execute the code in the case of cross-compiling or guarantee its execution using the reference compiler, proposed attribute [[meta::set_environment(str)]] where str is a command that will be executed in the shell (this moment is badly thought out by me, but I think that this is quite important).
P.S. This is not all that I would like to write. I will add some things later.