summaryrefslogtreecommitdiff
path: root/src/expand/mod.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/expand/mod.cpp')
-rw-r--r--src/expand/mod.cpp222
1 files changed, 198 insertions, 24 deletions
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp
index 527fa0d3..fe7507fb 100644
--- a/src/expand/mod.cpp
+++ b/src/expand/mod.cpp
@@ -7,6 +7,7 @@
#include <map>
#include "macro_rules.hpp"
#include "../parse/common.hpp" // For reparse from macros
+#include <ast/expr.hpp>
::std::map< ::std::string, ::std::unique_ptr<ExpandDecorator> > g_decorators;
::std::map< ::std::string, ::std::unique_ptr<ExpandProcMacro> > g_macros;
@@ -18,7 +19,16 @@ void Register_Synext_Macro(::std::string name, ::std::unique_ptr<ExpandProcMacro
g_macros[name] = mv$(handler);
}
-void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item)
+namespace {
+ AttrStage stage_pre(bool is_early) {
+ return (is_early ? AttrStage::EarlyPre : AttrStage::LatePre);
+ }
+ AttrStage stage_post(bool is_early) {
+ return (is_early ? AttrStage::EarlyPost : AttrStage::LatePost);
+ }
+}
+
+void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::std::function<void(const ExpandDecorator& d,const ::AST::MetaItem& a)> f)
{
for( auto& a : attrs.m_items )
{
@@ -26,21 +36,27 @@ void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate&
if( d.first == a.name() ) {
DEBUG("#[" << d.first << "] " << (int)d.second->stage() << "-" << (int)stage);
if( d.second->stage() == stage ) {
- d.second->handle(a, crate, path, mod, item);
+ f(*d.second, a);
}
}
}
}
}
+void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item)
+{
+ Expand_Attrs(attrs, stage, [&](const auto& d, const auto& a){ d.handle(a, crate, path, mod, item); });
+}
-::std::unique_ptr<TokenStream> Expand_Macro(bool is_early, LList<const AST::Module*> modstack, ::AST::Module& mod, ::AST::MacroInvocation& mi)
+::std::unique_ptr<TokenStream> Expand_Macro(
+ bool is_early, LList<const AST::Module*> modstack, ::AST::Module& mod,
+ Span mi_span, const ::std::string& name, const ::std::string& input_ident, const TokenTree& input_tt
+ )
{
for( const auto& m : g_macros )
{
- if( mi.name() == m.first && m.second->expand_early() == is_early )
+ if( name == m.first && m.second->expand_early() == is_early )
{
- auto e = m.second->expand(mi.input_ident(), mi.input_tt(), mod);
- mi.clear();
+ auto e = m.second->expand(input_ident, input_tt, mod);
return e;
}
}
@@ -53,26 +69,24 @@ void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate&
for( const auto& mr : mac_mod.macros() )
{
//DEBUG("- " << mr.name);
- if( mr.name == mi.name() )
+ if( mr.name == name )
{
- if( mi.input_ident() != "" )
- ; // TODO: ERROR - macro_rules! macros can't take an ident
+ if( input_ident != "" )
+ ERROR(mi_span, E0000, "macro_rules! macros can't take an ident");
- auto e = Macro_Invoke(mr.name.c_str(), mr.data, mi.input_tt(), mod);
- mi.clear();
+ auto e = Macro_Invoke(name.c_str(), mr.data, input_tt, mod);
return e;
}
}
for( const auto& mri : mac_mod.macro_imports_res() )
{
//DEBUG("- " << mri.name);
- if( mri.name == mi.name() )
+ if( mri.name == name )
{
- if( mi.input_ident() != "" )
- ; // TODO: ERROR - macro_rules! macros can't take an ident
+ if( input_ident != "" )
+ ERROR(mi_span, E0000, "macro_rules! macros can't take an ident");
- auto e = Macro_Invoke(mi.name().c_str(), *mri.data, mi.input_tt(), mod);
- mi.clear();
+ auto e = Macro_Invoke(name.c_str(), *mri.data, input_tt, mod);
return e;
}
}
@@ -80,13 +94,169 @@ void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate&
if( ! is_early ) {
// Error - Unknown macro name
- ERROR(mi.span(), E0000, "Unknown macro '" << mi.name() << "'");
+ ERROR(mi_span, E0000, "Unknown macro '" << name << "'");
}
// Leave valid and return an empty expression
return ::std::unique_ptr<TokenStream>();
}
+void Expand_Expr(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Path item_path, AST::Expr& node)
+{
+ struct CExpandExpr:
+ public ::AST::NodeVisitor
+ {
+ bool is_early;
+ LList<const AST::Module*> modstack;
+ ::std::unique_ptr<::AST::ExprNode> replacement;
+
+ CExpandExpr(bool is_early, LList<const AST::Module*> ms):
+ is_early(is_early),
+ modstack(ms)
+ {
+ }
+
+ void visit(::std::unique_ptr<AST::ExprNode>& cnode) {
+ if(cnode.get())
+ Expand_Attrs(cnode->attrs(), stage_pre(is_early), [&](const auto& d, const auto& a){ d.handle(a, *cnode); });
+ if(cnode.get())
+ {
+ cnode->visit(*this);
+ if( this->replacement.get() ) {
+ cnode = mv$(this->replacement);
+ }
+ }
+
+ if(cnode.get())
+ Expand_Attrs(cnode->attrs(), stage_post(is_early), [&](const auto& d, const auto& a){ d.handle(a, *cnode); });
+ }
+ void visit_nodelete(const ::AST::ExprNode& parent, ::std::unique_ptr<AST::ExprNode>& cnode) {
+ if( cnode.get() != nullptr )
+ {
+ this->visit(cnode);
+ if(cnode.get() == nullptr)
+ ERROR(parent.get_pos(), E0000, "#[cfg] not allowed in this position");
+ }
+ }
+ void visit_vector(::std::vector< ::std::unique_ptr<AST::ExprNode> >& cnodes) {
+ for( auto& child : cnodes ) {
+ this->visit(child);
+ }
+ // Delete null children
+ for( auto it = cnodes.begin(); it != cnodes.end(); ) {
+ if( it->get() == nullptr ) {
+ it = cnodes.erase( it );
+ }
+ else {
+ ++ it;
+ }
+ }
+ }
+
+ void visit(::AST::ExprNode_Macro& node) override {
+ auto ttl = Expand_Macro(
+ false, modstack, *(::AST::Module*)(modstack.m_item),
+ Span(node.get_pos()),
+ node.m_name, node.m_ident, node.m_tokens
+ );
+ // TODO: Reparse as expression / item
+ // TODO: Then call visit on it again
+ BUG(node.get_pos(), "TODO: Expand expression macros");
+ }
+
+ void visit(::AST::ExprNode_Block& node) override {
+ this->visit_vector(node.m_nodes);
+ }
+ void visit(::AST::ExprNode_Flow& node) override {
+ this->visit_nodelete(node, node.m_value);
+ }
+ void visit(::AST::ExprNode_LetBinding& node) override {
+ // TODO: Pattern and type
+ this->visit_nodelete(node, node.m_value);
+ }
+ void visit(::AST::ExprNode_Assign& node) override {
+ this->visit_nodelete(node, node.m_slot);
+ this->visit_nodelete(node, node.m_value);
+ }
+ void visit(::AST::ExprNode_CallPath& node) override {
+ // TODO: path?
+ this->visit_vector(node.m_args);
+ }
+ void visit(::AST::ExprNode_CallMethod& node) override {
+ this->visit_nodelete(node, node.m_val);
+ this->visit_vector(node.m_args);
+ }
+ void visit(::AST::ExprNode_CallObject& node) override {
+ this->visit_nodelete(node, node.m_val);
+ this->visit_vector(node.m_args);
+ }
+ void visit(::AST::ExprNode_Loop& node) override {
+ this->visit_nodelete(node, node.m_cond);
+ this->visit_nodelete(node, node.m_code);
+ }
+ void visit(::AST::ExprNode_Match& node) override {
+ this->visit_nodelete(node, node.m_val);
+ // TODO: Arms
+ }
+ void visit(::AST::ExprNode_If& node) override {
+ this->visit_nodelete(node, node.m_cond);
+ this->visit_nodelete(node, node.m_true);
+ this->visit_nodelete(node, node.m_false); // TODO: Can the false branch be `#[cfg]`d off?
+ }
+ void visit(::AST::ExprNode_IfLet& node) override {
+ // TODO: Pattern
+ this->visit_nodelete(node, node.m_value);
+ this->visit_nodelete(node, node.m_true);
+ this->visit_nodelete(node, node.m_false); // TODO: Can the false branch be `#[cfg]`d off?
+ }
+ void visit(::AST::ExprNode_Integer& node) override { }
+ void visit(::AST::ExprNode_Float& node) override { }
+ void visit(::AST::ExprNode_Bool& node) override { }
+ void visit(::AST::ExprNode_String& node) override { }
+ void visit(::AST::ExprNode_Closure& node) override {
+ // TODO: Arg patterns and types
+ // TODO: Return type
+ this->visit_nodelete(node, node.m_code);
+ }
+ void visit(::AST::ExprNode_StructLiteral& node) override {
+ this->visit_nodelete(node, node.m_base_value);
+ // TODO: Values (with #[cfg] support)
+ }
+ void visit(::AST::ExprNode_Array& node) override {
+ this->visit_nodelete(node, node.m_size);
+ this->visit_vector(node.m_values);
+ }
+ void visit(::AST::ExprNode_Tuple& node) override {
+ this->visit_vector(node.m_values);
+ }
+ void visit(::AST::ExprNode_NamedValue& node) override { }
+ void visit(::AST::ExprNode_Field& node) override {
+ this->visit_nodelete(node, node.m_obj);
+ }
+ void visit(::AST::ExprNode_Index& node) override {
+ this->visit_nodelete(node, node.m_obj);
+ this->visit_nodelete(node, node.m_idx);
+ }
+ void visit(::AST::ExprNode_Deref& node) override {
+ this->visit_nodelete(node, node.m_value);
+ }
+ void visit(::AST::ExprNode_Cast& node) override {
+ this->visit_nodelete(node, node.m_value);
+ // TODO: Type
+ }
+ void visit(::AST::ExprNode_BinOp& node) override {
+ this->visit_nodelete(node, node.m_left);
+ this->visit_nodelete(node, node.m_right);
+ }
+ void visit(::AST::ExprNode_UniOp& node) override {
+ this->visit_nodelete(node, node.m_value);
+ }
+ };
+
+ auto visitor = CExpandExpr(is_early, modstack);
+ node.visit_nodes(visitor);
+}
+
void Expand_Mod(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Path modpath, ::AST::Module& mod)
{
TRACE_FUNCTION_F("is_early = " << is_early << ", modpath = " << modpath);
@@ -108,10 +278,11 @@ void Expand_Mod(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> mo
// Move out of the module to avoid invalidation if a new macro invocation is added
auto mi_owned = mv$(mi);
- auto ttl = Expand_Macro(is_early, modstack, mod, mi_owned);
-
- if( mi_owned.name() != "" )
+ auto ttl = Expand_Macro(is_early, modstack, mod, mi_owned.span(), mi_owned.name(), mi_owned.input_ident(), mi_owned.input_tt());
+
+ if( ! ttl.get() )
{
+ // - Return ownership to the list
mod.macro_invs()[i] = mv$(mi_owned);
}
else
@@ -119,6 +290,7 @@ void Expand_Mod(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> mo
// Re-parse tt
assert(ttl.get());
Parse_ModRoot_Items(*ttl, mod, false, "-");
+ // - Any new macro invocations ends up at the end of the list and handled
}
}
}
@@ -130,7 +302,7 @@ void Expand_Mod(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> mo
DEBUG("- " << i.name << " :: " << i.data.attrs);
::AST::Path path = modpath + i.name;
- Expand_Attrs(i.data.attrs, (is_early ? AttrStage::EarlyPre : AttrStage::LatePre), crate, path, mod, i.data);
+ Expand_Attrs(i.data.attrs, stage_pre(is_early), crate, path, mod, i.data);
TU_MATCH(::AST::Item, (i.data), (e),
(None,
@@ -158,14 +330,16 @@ void Expand_Mod(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> mo
),
(Function,
- // TODO: Recurse into function code (and types)
+ // TODO: Recurse into argument patterns + types
+ Expand_Expr(is_early, crate, modstack, path, e.e.code());
),
(Static,
- // TODO: Recurse into static values
+ // Recurse into static values
+ Expand_Expr(is_early, crate, modstack, path, e.e.value());
)
)
- Expand_Attrs(i.data.attrs, (is_early ? AttrStage::EarlyPost : AttrStage::LatePost), crate, path, mod, i.data);
+ Expand_Attrs(i.data.attrs, stage_post(is_early), crate, path, mod, i.data);
}
DEBUG("Impls");