summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-05-22 22:39:26 +0800
committerJohn Hodge <tpg@mutabah.net>2016-05-22 22:39:26 +0800
commit1f9a4180a3b54f85f37919ba4ca709f8e8250bb6 (patch)
treec00cef798d26bf5f68f1657b01a490533365f015 /src
parenteba9d8f840a5b81f0188d109e63631c9a34c28e9 (diff)
downloadmrust-1f9a4180a3b54f85f37919ba4ca709f8e8250bb6.tar.gz
macro_rules - Rework pattern matching to not use try-catch
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.cpp3
-rw-r--r--src/ast/ast.hpp21
-rw-r--r--src/ast/crate.cpp2
-rw-r--r--src/ast/crate.hpp4
-rw-r--r--src/expand/macro_rules.cpp8
-rw-r--r--src/expand/macro_rules.hpp2
-rw-r--r--src/expand/mod.cpp2
-rw-r--r--src/hir/from_ast.cpp2
-rw-r--r--src/hir/hir.hpp2
-rw-r--r--src/macro_rules/eval.cpp (renamed from src/macros.cpp)1485
-rw-r--r--src/macro_rules/macro_rules.hpp (renamed from src/macros.hpp)46
-rw-r--r--src/macro_rules/macro_rules_ptr.hpp31
-rw-r--r--src/macro_rules/mod.cpp203
-rw-r--r--src/macro_rules/parse.cpp (renamed from src/parse/macro_rules.cpp)210
-rw-r--r--src/macro_rules/pattern_checks.hpp10
-rw-r--r--src/main.cpp5
-rw-r--r--src/parse/common.hpp2
-rw-r--r--src/parse/expr.cpp1
-rw-r--r--src/parse/root.cpp1
19 files changed, 1028 insertions, 1012 deletions
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 23e9bfea..84218591 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -313,6 +313,9 @@ void Module::add_submod(bool is_public, ::std::string name, Module mod, MetaItem
DEBUG("mod.m_name = " << name << ", attrs = " << attrs);
this->add_item( is_public, mv$(name), Item::make_Module({mv$(mod)}), mv$(attrs) );
}
+void Module::add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro) {
+ m_macros.push_back( Named<MacroRulesPtr>( mv$(name), mv$(macro), is_exported ) );
+}
void Module::prescan()
{
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index b7de73ac..d1e8c6a2 100644
--- a/src/ast/ast.hpp
+++ b/src/ast/ast.hpp
@@ -19,17 +19,18 @@
#include "../parse/tokentree.hpp"
#include "../types.hpp"
-#include "../macros.hpp"
#include <serialise.hpp>
-#include "pattern.hpp"
-#include "attrs.hpp"
-#include "expr.hpp"
-#include "macro.hpp"
-#include "item.hpp"
+#include <ast/pattern.hpp>
+#include <ast/attrs.hpp>
+#include <ast/expr.hpp>
+#include <ast/item.hpp>
+#include <ast/macro.hpp>
#include "generics.hpp"
+#include <macro_rules/macro_rules_ptr.hpp>
+
namespace AST {
class Crate;
@@ -551,7 +552,7 @@ private:
::std::vector<Module*> m_anon_modules;
::std::vector< NamedNS<const MacroRules*> > m_macro_import_res; // Vec of imported macros (not serialised)
- ::std::vector< Named<MacroRules> > m_macros;
+ ::std::vector< Named<MacroRulesPtr> > m_macros;
public:
char m_index_populated = 0; // 0 = no, 1 = partial, 2 = complete
@@ -599,9 +600,7 @@ public:
void add_neg_impl(ImplDef impl) {
m_neg_impls.emplace_back( ::std::move(impl) );
}
- void add_macro(bool is_exported, ::std::string name, MacroRules macro) {
- m_macros.push_back( Named<MacroRules>( move(name), move(macro), is_exported ) );
- }
+ void add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro);
void add_macro_import(::std::string name, const MacroRules& mr) {
m_macro_import_res.push_back( NamedNS<const MacroRules*>( mv$(name), &mr, false ) );
}
@@ -641,7 +640,7 @@ public:
::std::vector<MacroInvocation>& macro_invs() { return m_macro_invocations; }
- const NamedList<MacroRules>& macros() const { return m_macros; }
+ const NamedList<MacroRulesPtr>& macros() const { return m_macros; }
const ::std::vector<NamedNS<const MacroRules*> > macro_imports_res() const { return m_macro_import_res; }
diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp
index d40879f3..500598b0 100644
--- a/src/ast/crate.cpp
+++ b/src/ast/crate.cpp
@@ -325,7 +325,7 @@ const MacroRules* ExternCrate::find_macro_rules(const ::std::string& name)
{
auto i = m_mr_macros.find(name);
if(i != m_mr_macros.end())
- return &i->second;
+ return &*i->second;
return nullptr;
}
diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp
index dbb9ca0d..b88b9307 100644
--- a/src/ast/crate.hpp
+++ b/src/ast/crate.hpp
@@ -79,7 +79,7 @@ private:
class ExternCrate:
public Serialisable
{
- ::std::map< ::std::string, MacroRules > m_mr_macros;
+ ::std::map< ::std::string, MacroRulesPtr > m_mr_macros;
//::MIR::Module m_root_module;
@@ -87,6 +87,8 @@ class ExternCrate:
public:
ExternCrate();
ExternCrate(const char *path);
+ ExternCrate(const ExternCrate&) = delete;
+ ExternCrate(ExternCrate&&) = default;
const MacroRules* find_macro_rules(const ::std::string& name);
diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp
index 968bf5f9..1689746c 100644
--- a/src/expand/macro_rules.cpp
+++ b/src/expand/macro_rules.cpp
@@ -4,6 +4,7 @@
#include "../ast/ast.hpp"
#include "../parse/common.hpp"
#include "macro_rules.hpp"
+#include <macro_rules/macro_rules.hpp>
class CMacroRulesExpander:
public ExpandProcMacro
@@ -15,9 +16,10 @@ class CMacroRulesExpander:
if( ident == "" )
ERROR(sp, E0000, "macro_rules! requires an identifier" );
+ DEBUG("Parsing macro_rules! " << ident);
TTStream lex(tt);
auto mac = Parse_MacroRules(lex);
- mod.add_macro( false, ident, mac );
+ mod.add_macro( false, ident, mv$(mac) );
return ::std::unique_ptr<TokenStream>( new TTStreamO(TokenTree()) );
}
@@ -45,7 +47,7 @@ class CMacroUseHandler:
{
if( mr.name == name ) {
DEBUG("Imported " << mr.name);
- mod.add_macro_import( mr.name, mr.data );
+ mod.add_macro_import( mr.name, *mr.data );
goto _good;
}
}
@@ -67,7 +69,7 @@ class CMacroUseHandler:
for( const auto& mr : submod.macros() )
{
DEBUG("Imported " << mr.name);
- mod.add_macro_import( mr.name, mr.data );
+ mod.add_macro_import( mr.name, *mr.data );
}
for( const auto& mri : submod.macro_imports_res() )
{
diff --git a/src/expand/macro_rules.hpp b/src/expand/macro_rules.hpp
index b4e6e1e0..fc4a2851 100644
--- a/src/expand/macro_rules.hpp
+++ b/src/expand/macro_rules.hpp
@@ -4,7 +4,6 @@
#pragma once
#include <synext.hpp>
-#include "../macros.hpp"
namespace AST {
class Expr;
@@ -12,5 +11,6 @@ namespace AST {
}
class TokenTree;
class TokenStream;
+class MacroRules;
extern ::std::unique_ptr<TokenStream> Macro_Invoke(const char* name, const MacroRules& rules, const TokenTree& tt, AST::Module& mod);
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp
index 3f0911fe..0cb2c9c7 100644
--- a/src/expand/mod.cpp
+++ b/src/expand/mod.cpp
@@ -105,7 +105,7 @@ void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate&
if( input_ident != "" )
ERROR(mi_span, E0000, "macro_rules! macros can't take an ident");
- auto e = Macro_Invoke(name.c_str(), mr.data, input_tt, mod);
+ auto e = Macro_Invoke(name.c_str(), *mr.data, input_tt, mod);
return e;
}
}
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp
index 7ab503cf..9595ca02 100644
--- a/src/hir/from_ast.cpp
+++ b/src/hir/from_ast.cpp
@@ -20,7 +20,7 @@
// - Extract macros from root module
for( const auto& mac : crate.m_root_module.macros() ) {
//if( mac.data.export ) {
- macros.insert( ::std::make_pair( mac.name, mac.data ) );
+ macros.insert( ::std::make_pair( mac.name, mv$(*mac.data) ) );
//}
}
for( const auto& mac : crate.m_root_module.macro_imports_res() ) {
diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp
index ff0d82a9..cc63626f 100644
--- a/src/hir/hir.hpp
+++ b/src/hir/hir.hpp
@@ -12,7 +12,7 @@
#include <tagged_union.hpp>
-#include <macros.hpp> // DAMNIT - Why can't I have it be incomplete
+#include <macro_rules/macro_rules.hpp> // DAMNIT - Why can't I have it be incomplete
#include <hir/type.hpp>
#include <hir/path.hpp>
diff --git a/src/macros.cpp b/src/macro_rules/eval.cpp
index a5c90fee..44900807 100644
--- a/src/macros.cpp
+++ b/src/macro_rules/eval.cpp
@@ -1,846 +1,639 @@
-/*
- */
-#include "common.hpp"
-#include "macros.hpp"
-#include "parse/parseerror.hpp"
-#include "parse/tokentree.hpp"
-#include "parse/common.hpp"
-#include "ast/ast.hpp"
-#include <limits.h>
-
-typedef ::std::map< ::std::string, MacroRules> t_macro_regs;
-
-t_macro_regs g_macro_registrations;
-
-class ParameterMappings
-{
- // MultiMap (layer, name) -> TokenTree
- // - Multiple values are only allowed for layer>0
- typedef ::std::pair<unsigned, unsigned> t_mapping_block;
- struct Mapping
- {
- t_mapping_block block;
- ::std::vector<TokenTree> entries;
- friend ::std::ostream& operator<<(::std::ostream& os, const Mapping& x) {
- os << "(" << x.block.first << ", " << x.block.second << "): '" << x.entries << "')";
- return os;
- }
- };
- struct less_cstr {
- bool operator()(const char *a, const char *b) const { return ::std::strcmp(a,b) < 0; }
- };
-
- typedef ::std::map<const char *, Mapping, less_cstr> t_inner_map;
-
- t_inner_map m_inner;
- unsigned m_layer_count;
-public:
- ParameterMappings():
- m_inner(),
- m_layer_count(0)
- {
- }
- ParameterMappings(ParameterMappings&&) = default;
-
- const t_inner_map& inner_() const {
- return m_inner;
- }
-
- size_t layer_count() const {
- return m_layer_count+1;
- }
-
- void insert(unsigned int layer, const char *name, TokenTree data) {
- if(layer > m_layer_count)
- m_layer_count = layer;
- auto v = m_inner.insert( ::std::make_pair( name, Mapping { {layer, 0}, {} } ) );
- if(v.first->second.block.first != layer) {
- throw ParseError::Generic(FMT("matching '"<<name<<"' at multiple layers"));
- }
- v.first->second.entries.push_back( mv$(data) );
- }
-
- const TokenTree* get(unsigned int layer, unsigned int iteration, const char *name, unsigned int idx) const
- {
- const auto it = m_inner.find( name );
- if( it == m_inner.end() ) {
- DEBUG("m_mappings = " << m_inner);
- return nullptr;
- }
- const auto& e = it->second;
- if( e.block.first < layer ) {
- DEBUG(name<<" higher layer (" << e.block.first << ")");
- return nullptr;
- }
- else if( e.block.first > layer ) {
- throw ParseError::Generic( FMT("'" << name << "' is still repeating at this layer") );
- }
- else if( idx >= e.entries.size() ) {
- DEBUG("Not enough mappings for name " << name << " at layer " << layer << " PI " << iteration);
- return nullptr;
- }
- else {
- DEBUG(name << " #" << idx << ": " << e.entries[idx]);
- return &e.entries[idx];
- }
- }
- unsigned int count(unsigned int layer, unsigned int iteration, const char *name) const
- {
- const auto it = m_inner.find( name );
- if( it == m_inner.end() ) {
- DEBUG("("<<layer<<","<<iteration<<",'"<<name<<"') not found m_mappings = " << m_inner);
- return 0;
- }
- const auto& e = it->second;
-
- if( e.block.first < layer ) {
- DEBUG(name<<" higher layer (" << e.block.first << ")");
- return UINT_MAX;
- }
- else if( e.block.first > layer ) {
- //throw ParseError::Generic( FMT("'" << name << "' is still repeating at this layer") );
- // ignore mismatch
- return UINT_MAX;
- }
- else {
- return it->second.entries.size();
- }
- }
-};
-
-class MacroExpander:
- public TokenStream
-{
-public:
-
-private:
- const RcString m_macro_filename;
-
- const ::std::string m_crate_name;
- const ::std::vector<MacroRuleEnt>& m_root_contents;
- const ParameterMappings m_mappings;
-
-
- struct t_offset {
- unsigned read_pos;
- unsigned loop_index;
- unsigned max_index;
- };
- /// Layer states : Index and Iteration
- ::std::vector< t_offset > m_offsets;
- ::std::vector< size_t > m_layer_iters;
-
- /// Cached pointer to the current layer
- const ::std::vector<MacroRuleEnt>* m_cur_ents; // For faster lookup.
-
- Token m_next_token; // used for inserting a single token into the stream
- ::std::unique_ptr<TTStream> m_ttstream;
-
-public:
- MacroExpander(const MacroExpander& x) = delete;
- //MacroExpander(const MacroExpander& x):
- // m_macro_name( x.m_macro_name ),
- // m_crate_name(x.m_crate_name),
- // m_root_contents(x.m_root_contents),
- // m_mappings(x.m_mappings),
- // m_offsets({ {0,0,0} }),
- // m_cur_ents(&m_root_contents)
- //{
- // prep_counts();
- //}
- MacroExpander(const ::std::string& macro_name, const ::std::vector<MacroRuleEnt>& contents, ParameterMappings mappings, ::std::string crate_name):
- m_macro_filename( FMT("Macro:" << macro_name) ),
- m_crate_name( mv$(crate_name) ),
- m_root_contents(contents),
- m_mappings( mv$(mappings) ),
- m_offsets({ {0,0,0} }),
- m_cur_ents(&m_root_contents)
- {
- prep_counts();
- }
-
- virtual Position getPosition() const override;
- virtual Token realGetToken() override;
-private:
- const MacroRuleEnt& getCurLayerEnt() const;
- const ::std::vector<MacroRuleEnt>* getCurLayer() const;
- void prep_counts();
- unsigned int count_repeats(const ::std::vector<MacroRuleEnt>& ents, unsigned layer, unsigned iter);
-};
-
-class MacroToken:
- public TokenStream
-{
- Token m_tok;
-public:
- MacroToken(Token tok);
- virtual Position getPosition() const override;
- virtual Token realGetToken() override;
-};
-
-class MacroStringify:
- public TokenStream
-{
- Token m_tok;
-public:
- MacroStringify(const TokenTree& input);
- virtual Position getPosition() const override;
- virtual Token realGetToken() override;
-};
-
-::std::unique_ptr<TokenStream> Macro_Invoke_Concat(const TokenTree& input, enum eTokenType exp);
-::std::unique_ptr<TokenStream> Macro_Invoke_Cfg(const TokenTree& input);
-
-void Macro_InitDefaults()
-{
-}
-
-bool Macro_TryPattern(TTStream& lex, const MacroPatEnt& pat)
-{
- DEBUG("pat = " << pat);
- switch(pat.type)
- {
- case MacroPatEnt::PAT_TOKEN: {
- Token tok = lex.getToken();
- if( tok != pat.tok ) {
- PUTBACK(tok, lex);
- return false;
- }
- else {
- PUTBACK(tok, lex);
- return true;
- }
- }
- case MacroPatEnt::PAT_LOOP:
- if( pat.name == "*" )
- return true;
- return Macro_TryPattern(lex, pat.subpats[0]);
- case MacroPatEnt::PAT_BLOCK:
- return LOOK_AHEAD(lex) == TOK_BRACE_OPEN;
- case MacroPatEnt::PAT_IDENT:
- return LOOK_AHEAD(lex) == TOK_IDENT;
- case MacroPatEnt::PAT_TT:
- return LOOK_AHEAD(lex) != TOK_EOF;
- case MacroPatEnt::PAT_PATH:
- return LOOK_AHEAD(lex) == TOK_IDENT
- || LOOK_AHEAD(lex) == TOK_DOUBLE_COLON
- || LOOK_AHEAD(lex) == TOK_RWORD_SUPER;
- case MacroPatEnt::PAT_TYPE:
- try {
- TTStream slex = lex;
- Parse_TT_Type(slex);
- return true;
- }
- catch( const CompileError::Base& e ) {
- return false;
- }
- case MacroPatEnt::PAT_EXPR:
- return Parse_IsTokValue( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_STMT:
- try {
- TTStream slex = lex;
- Parse_TT_Stmt(slex);
- return true;
- }
- catch( const CompileError::Base& e ) {
- return false;
- }
- case MacroPatEnt::PAT_PAT:
- try {
- TTStream slex = lex;
- Parse_TT_Pattern(slex);
- return true;
- }
- catch( const CompileError::Base& e ) {
- return false;
- }
- case MacroPatEnt::PAT_META:
- return LOOK_AHEAD(lex) == TOK_IDENT;
- }
- throw ParseError::Todo(lex, FMT("Macro_TryPattern : " << pat));
-}
-
-bool Macro_HandlePattern(TTStream& lex, const MacroPatEnt& pat, unsigned int layer, ParameterMappings& bound_tts)
-{
- TRACE_FUNCTION_F("layer = " << layer);
- Token tok;
- TokenTree val;
-
- if( !Macro_TryPattern(lex, pat) ) {
- DEBUG("FAIL");
- return false;
- }
-
- switch(pat.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- DEBUG("Token " << pat.tok);
- GET_CHECK_TOK(tok, lex, pat.tok.type());
- break;
- case MacroPatEnt::PAT_LOOP:
- //case MacroPatEnt::PAT_OPTLOOP:
- {
- unsigned int match_count = 0;
- DEBUG("Loop");
- for(;;)
- {
- if( ! Macro_TryPattern(lex, pat.subpats[0]) )
- {
- DEBUG("break");
- break;
- }
- for( unsigned int i = 0; i < pat.subpats.size(); i ++ )
- {
- if( !Macro_HandlePattern(lex, pat.subpats[i], layer+1, bound_tts) ) {
- DEBUG("Ent " << i << " failed");
- return false;
- }
- }
- match_count += 1;
- DEBUG("succ");
- if( pat.tok.type() != TOK_NULL )
- {
- if( GET_TOK(tok, lex) != pat.tok.type() )
- {
- lex.putback( mv$(tok) );
- break;
- }
- }
- }
- DEBUG("Done (" << match_count << " matches)");
- break; }
-
- case MacroPatEnt::PAT_TT:
- DEBUG("TT");
- if( GET_TOK(tok, lex) == TOK_EOF )
- throw ParseError::Unexpected(lex, TOK_EOF);
- else
- PUTBACK(tok, lex);
- val = Parse_TT(lex, false);
- if(0)
- case MacroPatEnt::PAT_PAT:
- val = Parse_TT_Pattern(lex);
- if(0)
- case MacroPatEnt::PAT_TYPE:
- val = Parse_TT_Type(lex);
- if(0)
- case MacroPatEnt::PAT_EXPR:
- val = Parse_TT_Expr(lex);
- if(0)
- case MacroPatEnt::PAT_STMT:
- val = Parse_TT_Stmt(lex);
- if(0)
- case MacroPatEnt::PAT_PATH:
- val = Parse_TT_Path(lex, false); // non-expr mode
- if(0)
- case MacroPatEnt::PAT_BLOCK:
- val = Parse_TT_Block(lex);
- if(0)
- case MacroPatEnt::PAT_META:
- val = Parse_TT_Meta(lex);
- if(0)
- case MacroPatEnt::PAT_IDENT:
- {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- val = TokenTree(tok);
- }
- bound_tts.insert( layer, pat.name.c_str(), ::std::move(val) );
- break;
-
- //default:
- // throw ParseError::Todo("full macro pattern matching");
- }
- return true;
-}
-
-::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const TokenTree& input)
-{
- TRACE_FUNCTION;
-
- // TODO: Use types in `parse/macro_rules.cpp` to evaluate
-
- // 2. Check input token tree against possible variants
- // 3. Bind names
- // 4. Return expander
- int i = 0;
- for(const auto& rule : rules.m_rules)
- {
- Token tok;
- // Create token stream for input tree
- TTStream lex(input);
- ParameterMappings bound_tts;
- // Parse according to rules
- try
- {
- for(const auto& pat : rule.m_pattern)
- {
- if( !Macro_HandlePattern(lex, pat, 0, bound_tts) )
- throw ParseError::Generic(lex, "Macro pattern failed");
- }
-
- //GET_CHECK_TOK(tok, lex, close);
- GET_CHECK_TOK(tok, lex, TOK_EOF);
- DEBUG( rule.m_contents.size() << " rule contents bound to " << bound_tts.inner_().size() << " values - " << name );
- for( const auto& v : bound_tts.inner_() )
- {
- DEBUG("- " << v.first << " = [" << v.second << "]");
- }
-
- DEBUG("TODO: Obtain crate name correctly");
- TokenStream* ret_ptr = new MacroExpander(name, rule.m_contents, mv$(bound_tts), "");
- // HACK! Disable nested macro expansion
- //ret_ptr->parse_state().no_expand_macros = true;
-
- return ::std::unique_ptr<TokenStream>( ret_ptr );
- }
- catch(const CompileError::Base& e)
- {
- DEBUG("Parse of rule " << i << " of " << name <<" failed - " << e.what());
- }
- i ++;
- }
- DEBUG("");
- throw ParseError::Todo(/*source_span, */"Error when macro fails to match");
-}
-
-
-Position MacroExpander::getPosition() const
-{
- return Position(m_macro_filename, 0, m_offsets[0].read_pos);
-}
-Token MacroExpander::realGetToken()
-{
- // Use m_next_token first
- if( m_next_token.type() != TOK_NULL )
- {
- DEBUG("m_next_token = " << m_next_token);
- return ::std::move(m_next_token);
- }
- // Then try m_ttstream
- if( m_ttstream.get() )
- {
- DEBUG("TTStream set");
- Token rv = m_ttstream->getToken();
- if( rv.type() != TOK_EOF )
- return rv;
- m_ttstream.reset();
- }
- //DEBUG("ofs " << m_offsets << " < " << m_root_contents.size());
-
- // Check offset of lowest layer
- while(m_offsets.size() > 0)
- {
- unsigned int layer = m_offsets.size() - 1;
- const auto& ents = *m_cur_ents;
-
- // Obtain current read position in layer, and increment
- size_t idx = m_offsets.back().read_pos++;
-
- // Check if limit has been reached
- if( idx < ents.size() )
- {
- // - If not, just handle the next entry
- const auto& ent = ents[idx];
- // Check type of entry
- // - XXX: Hack for $crate special name
- if( ent.name == "*crate" )
- {
- DEBUG("Crate name hack");
- if( m_crate_name != "" )
- {
- m_next_token = Token(TOK_STRING, m_crate_name);
- return Token(TOK_DOUBLE_COLON);
- }
- }
- // - Expand to a parameter
- else if( ent.name != "" )
- {
- DEBUG("lookup '" << ent.name << "'");
- const TokenTree* tt;
- unsigned int search_layer = layer;
- do {
- unsigned int parent_iter = (search_layer > 0 ? m_layer_iters.at(search_layer-1) : 0);
- const size_t iter_idx = m_offsets.at(search_layer).loop_index;
- tt = m_mappings.get(search_layer, parent_iter, ent.name.c_str(), iter_idx);
- } while( !tt && search_layer-- > 0 );
- if( ! tt )
- {
- throw ParseError::Generic(*this, FMT("Cannot find '" << ent.name << "' for " << layer));
- }
- else
- {
- m_ttstream.reset( new TTStream(*tt) );
- return m_ttstream->getToken();
- }
- }
- // - Descend into a repetition
- else if( ent.subpats.size() != 0 )
- {
- DEBUG("desc: layer = " << layer << ", m_layer_iters = " << m_layer_iters);
- unsigned int layer_iter = m_layer_iters.at(layer);
- unsigned int num_repeats = this->count_repeats(ent.subpats, layer+1, layer_iter);
- if(num_repeats == UINT_MAX)
- num_repeats = 0;
- // New layer
- DEBUG("- NL = " << layer+1 << ", count = " << num_repeats );
- if( num_repeats > 0 )
- {
- // - Push an offset
- m_offsets.push_back( {0, 0, num_repeats} );
- // - Save the current layer
- m_cur_ents = getCurLayer();
- // - Restart loop for new layer
- }
- else
- {
- // Layer empty
- DEBUG("Layer " << layer+1 << " is empty");
- }
- // VVV fall through and continue loop
- }
- // - Emit a raw token
- else
- {
- return ent.tok;
- }
- // Fall through for loop
- }
- else if( layer > 0 )
- {
- // - Otherwise, restart/end loop and fall through
- DEBUG("layer = " << layer << ", m_layer_iters = " << m_layer_iters);
- auto& cur_ofs = m_offsets.back();
- DEBUG("Layer #" << layer << " Cur: " << cur_ofs.loop_index << ", Max: " << cur_ofs.max_index);
- if( cur_ofs.loop_index + 1 < cur_ofs.max_index )
- {
- m_layer_iters.at(layer) ++;
-
- DEBUG("Restart layer");
- cur_ofs.read_pos = 0;
- cur_ofs.loop_index ++;
-
- auto& loop_layer = getCurLayerEnt();
- assert(loop_layer.subpats.size());
- if( loop_layer.tok.type() != TOK_NULL ) {
- DEBUG("- Separator token = " << loop_layer.tok);
- return loop_layer.tok;
- }
- // Fall through and restart layer
- }
- else
- {
- DEBUG("Terminate layer");
- // Terminate loop, fall through to lower layers
- m_offsets.pop_back();
- // - Special case: End of macro, avoid issues
- if( m_offsets.size() == 0 )
- break;
- m_cur_ents = getCurLayer();
- }
- }
- else
- {
- DEBUG("Terminate evaluation");
- m_offsets.pop_back();
- assert( m_offsets.size() == 0 );
- }
- } // while( m_offsets NONEMPTY )
-
- DEBUG("EOF");
- return Token(TOK_EOF);
-}
-
-/// Count the number of names at each layer
-void MacroExpander::prep_counts()
-{
- m_layer_iters.resize(m_mappings.layer_count(), 0);
-}
-const MacroRuleEnt& MacroExpander::getCurLayerEnt() const
-{
- assert( m_offsets.size() > 1 );
-
- const ::std::vector<MacroRuleEnt>* ents = &m_root_contents;
- for( unsigned int i = 0; i < m_offsets.size()-2; i ++ )
- {
- unsigned int ofs = m_offsets[i].read_pos;
- assert( ofs > 0 && ofs <= ents->size() );
- ents = &(*ents)[ofs-1].subpats;
- }
- return (*ents)[m_offsets[m_offsets.size()-2].read_pos-1];
-
-}
-const ::std::vector<MacroRuleEnt>* MacroExpander::getCurLayer() const
-{
- assert( m_offsets.size() > 0 );
- const ::std::vector<MacroRuleEnt>* ents = &m_root_contents;
- for( unsigned int i = 0; i < m_offsets.size()-1; i ++ )
- {
- unsigned int ofs = m_offsets[i].read_pos;
- //DEBUG(i << " ofs=" << ofs << " / " << ents->size());
- assert( ofs > 0 && ofs <= ents->size() );
- ents = &(*ents)[ofs-1].subpats;
- //DEBUG("ents = " << ents);
- }
- return ents;
-}
-unsigned int MacroExpander::count_repeats(const ::std::vector<MacroRuleEnt>& ents, unsigned layer, unsigned iter)
-{
- bool valid = false;
- unsigned int count = 0;
- for(const auto& ent : ents)
- {
- if( ent.name != "" )
- {
- if( ent.name[0] == '*' ) {
- // Ignore meta-vars, they don't repeat
- }
- else {
- auto c = m_mappings.count(layer, iter, ent.name.c_str());
- DEBUG(c << " mappings for " << ent.name << " at (" << layer << ", " << iter << ")");
- if( c == UINT_MAX ) {
- // Ignore
- }
- else if(!valid || count == c) {
- count = c;
- valid = true;
- }
- else {
- // Mismatch!
- throw ParseError::Generic("count_repeats - iteration count mismatch");
- }
- }
- }
- else if( ent.subpats.size() > 0 )
- {
- auto c = this->count_repeats(ent.subpats, layer, iter);
- if( c == UINT_MAX ) {
- }
- else if(!valid || count == c) {
- count = c;
- valid = true;
- }
- else {
- // Mismatch!
- throw ParseError::Generic("count_repeats - iteration count mismatch (subpat)");
- }
- }
- else
- {
- // Don't care
- }
- }
-
- if(valid) {
- return count;
- }
- else {
- return UINT_MAX;
- }
-}
-
-void Macro_Invoke_Concat_Once(::std::string& s, TokenStream& lex, enum eTokenType exp)
-{
- Token tok;
- GET_TOK(tok, lex);
- if( exp == TOK_STRING )
- {
- if( tok.type() == TOK_MACRO )
- {
- // Special case, expand both concat! and stringify! internally
- // TODO: Invoke
- //auto tt = Parse_TT(lex, false);
- //auto slex = Macro_Invoke(lex, tok.str(), tt);
- //Macro_Invoke_Concat_Once(s, (*slex), exp);
- //GET_CHECK_TOK(tok, (*slex), TOK_EOF);
- }
- else if( tok.type() == exp )
- {
- s += tok.str();
- }
- else
- {
- CHECK_TOK(tok, exp);
- }
- }
- else
- {
- CHECK_TOK(tok, exp);
- s += tok.str();
- }
-}
-
-::std::unique_ptr<TokenStream> Macro_Invoke_Concat(const TokenTree& input, enum eTokenType exp)
-{
- Token tok;
- TTStream lex(input);
- ::std::string val;
- do
- {
- Macro_Invoke_Concat_Once(val, lex, exp);
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_EOF);
-
-
- return ::std::unique_ptr<TokenStream>( new MacroToken( Token(exp, val) ) );
-}
-
-::std::unique_ptr<TokenStream> Macro_Invoke_Cfg(const TokenTree& input)
-{
- Token tok;
- TTStream lex(input);
-
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string var = tok.str();
-
- if( GET_TOK(tok, lex) == TOK_EQUAL )
- {
- GET_CHECK_TOK(tok, lex, TOK_STRING);
- ::std::string val = tok.str();
- GET_CHECK_TOK(tok, lex, TOK_EOF);
- return ::std::unique_ptr<TokenStream>( new MacroToken( Token(TOK_RWORD_FALSE) ) );
- }
- else
- {
- CHECK_TOK(tok, TOK_EOF);
- return ::std::unique_ptr<TokenStream>( new MacroToken( Token(TOK_RWORD_FALSE) ) );
- }
-}
-
-MacroToken::MacroToken(Token tok):
- m_tok(tok)
-{
-}
-Position MacroToken::getPosition() const
-{
- return Position("MacroToken", 0, 0);
-}
-Token MacroToken::realGetToken()
-{
- Token ret = m_tok;
- m_tok = Token(TOK_EOF);
- return ret;
-}
-MacroStringify::MacroStringify(const TokenTree& input)
-{
- Token tok;
- TTStream lex(input);
-
- ::std::string rv;
- while( GET_TOK(tok, lex) != TOK_EOF )
- {
- rv += tok.to_str();
- rv += " ";
- }
-
- m_tok = Token(TOK_STRING, ::std::move(rv));
-}
-Position MacroStringify::getPosition() const
-{
- return Position("Stringify", 0,0);
-}
-Token MacroStringify::realGetToken()
-{
- Token ret = m_tok;
- m_tok = Token(TOK_EOF);
- return ret;
-}
-SERIALISE_TYPE_S(MacroRule, {
- s.item(m_pattern);
- s.item(m_contents);
-});
-
-
-void operator%(Serialiser& s, MacroPatEnt::Type c) {
- switch(c) {
- #define _(v) case MacroPatEnt::v: s << #v; return
- _(PAT_TOKEN);
- _(PAT_TT);
- _(PAT_PAT);
- _(PAT_TYPE);
- _(PAT_EXPR);
- _(PAT_LOOP);
- //_(PAT_OPTLOOP);
- _(PAT_STMT);
- _(PAT_PATH);
- _(PAT_BLOCK);
- _(PAT_META);
- _(PAT_IDENT);
- #undef _
- }
-}
-void operator%(::Deserialiser& s, MacroPatEnt::Type& c) {
- ::std::string n;
- s.item(n);
- #define _(v) else if(n == #v) c = MacroPatEnt::v
- if(0) ;
- _(PAT_TOKEN);
- _(PAT_TT);
- _(PAT_PAT);
- _(PAT_TYPE);
- _(PAT_EXPR);
- _(PAT_LOOP);
- //_(PAT_OPTLOOP);
- _(PAT_STMT);
- _(PAT_PATH);
- _(PAT_BLOCK);
- _(PAT_META);
- _(PAT_IDENT);
- else
- throw ::std::runtime_error( FMT("No conversion for '" << n << "'") );
- #undef _
-}
-SERIALISE_TYPE_S(MacroPatEnt, {
- s % type;
- s.item(name);
- s.item(tok);
- s.item(subpats);
-});
-::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x)
-{
- switch(x.type)
- {
- case MacroPatEnt::PAT_TOKEN: os << "=" << x.tok; break;
- case MacroPatEnt::PAT_LOOP: os << "loop w/ " << x.tok << " [" << x.subpats << "]"; break;
- default:
- os << "$" << x.name << ":";
- switch(x.type)
- {
- case MacroPatEnt::PAT_TOKEN: throw "";
- case MacroPatEnt::PAT_LOOP: throw "";
- case MacroPatEnt::PAT_TT: os << "tt"; break;
- case MacroPatEnt::PAT_PAT: os << "pat"; break;
- case MacroPatEnt::PAT_IDENT: os << "ident"; break;
- case MacroPatEnt::PAT_PATH: os << "path"; break;
- case MacroPatEnt::PAT_TYPE: os << "type"; break;
- case MacroPatEnt::PAT_EXPR: os << "expr"; break;
- case MacroPatEnt::PAT_STMT: os << "stmt"; break;
- case MacroPatEnt::PAT_BLOCK: os << "block"; break;
- case MacroPatEnt::PAT_META: os << "meta"; break;
- }
- break;
- }
- return os;
-}
-
-SERIALISE_TYPE_S(MacroRuleEnt, {
- s.item(name);
- s.item(tok);
- s.item(subpats);
-});
-
-::std::ostream& operator<<(::std::ostream& os, const MacroRuleEnt& x)
-{
- if(x.name.size())
- os << "$"<<x.name;
- else if( x.subpats.size() )
- os << "expand w/ " << x.tok << " [" << x.subpats << "]";
- else
- os << "=" << x.tok;
- return os;
-}
-
-SERIALISE_TYPE_S(MacroRules, {
- s.item( m_exported );
- s.item( m_rules );
-});
-
+/*
+ */
+#include <common.hpp>
+#include "macro_rules.hpp"
+#include <parse/parseerror.hpp>
+#include <parse/tokentree.hpp>
+#include <parse/common.hpp>
+#include <limits.h>
+#include "pattern_checks.hpp"
+
+class ParameterMappings
+{
+ // MultiMap (layer, name) -> TokenTree
+ // - Multiple values are only allowed for layer>0
+ typedef ::std::pair<unsigned, unsigned> t_mapping_block;
+ struct Mapping
+ {
+ t_mapping_block block;
+ ::std::vector<TokenTree> entries;
+ friend ::std::ostream& operator<<(::std::ostream& os, const Mapping& x) {
+ os << "(" << x.block.first << ", " << x.block.second << "): '" << x.entries << "')";
+ return os;
+ }
+ };
+
+ struct less_cstr {
+ bool operator()(const char *a, const char *b) const { return ::std::strcmp(a,b) < 0; }
+ };
+
+
+ ::std::vector<Mapping> m_mappings;
+ unsigned m_layer_count;
+
+ //::std::map<const char*, Mapping*, less_cstr> m_map;
+ ::std::map<::std::string, Mapping*> m_map;
+public:
+ ParameterMappings():
+ m_layer_count(0)
+ {
+ }
+ ParameterMappings(ParameterMappings&&) = default;
+
+ const ::std::vector<Mapping>& mappings() const { return m_mappings; }
+
+ void dump() const {
+ DEBUG("m_mappings = {" << m_mappings << "}");
+ DEBUG("m_map = {" << m_map << "}");
+ }
+
+ size_t layer_count() const {
+ return m_layer_count+1;
+ }
+
+ void insert(unsigned int layer, unsigned int name_index, TokenTree data) {
+ if(layer > m_layer_count)
+ m_layer_count = layer;
+
+ if( name_index >= m_mappings.size() ) {
+ m_mappings.resize( name_index + 1 );
+ }
+ auto& mapping = m_mappings[name_index];
+
+ if( mapping.entries.size() == 0 ) {
+ mapping.block.first = layer;
+ }
+ else if( mapping.block.first != layer) {
+ throw ParseError::Generic(FMT("matching argument #'"<<name_index<<"' at multiple layers"));
+ }
+ else {
+ }
+ mapping.entries.push_back( mv$(data) );
+ }
+
+ void reindex(const ::std::vector< ::std::string>& new_names) {
+ m_map.clear();
+
+ if( new_names.size() < m_mappings.size() ) {
+ BUG(Span(), "Macro parameter name mismatch - len["<<new_names<<"] != len["<<m_mappings<<"]");
+ }
+ for( unsigned int i = 0; i < m_mappings.size(); i ++ )
+ {
+ m_map.insert( ::std::make_pair(new_names[i].c_str(), &m_mappings[i]) );
+ }
+ }
+
+ const TokenTree* get(unsigned int layer, unsigned int iteration, const char *name, unsigned int idx) const
+ {
+ const auto it = m_map.find( name );
+ if( it == m_map.end() ) {
+ DEBUG("m_map = " << m_map);
+ return nullptr;
+ }
+ const auto& e = *it->second;
+ if( e.block.first < layer ) {
+ DEBUG(name<<" higher layer (" << e.block.first << ")");
+ return nullptr;
+ }
+ else if( e.block.first > layer ) {
+ throw ParseError::Generic( FMT("'" << name << "' is still repeating at this layer") );
+ }
+ else if( idx >= e.entries.size() ) {
+ DEBUG("Not enough mappings for name " << name << " at layer " << layer << " PI " << iteration);
+ return nullptr;
+ }
+ else {
+ DEBUG(name << " #" << idx << ": " << e.entries[idx]);
+ return &e.entries[idx];
+ }
+ }
+ unsigned int count(unsigned int layer, unsigned int iteration, const char *name) const
+ {
+ const auto it = m_map.find( name );
+ if( it == m_map.end() ) {
+ DEBUG("("<<layer<<","<<iteration<<",'"<<name<<"') not found - m_map={" << m_map << "}");
+ return 0;
+ }
+ const auto& e = *it->second;
+
+ if( e.block.first < layer ) {
+ DEBUG(name<<" higher layer (" << e.block.first << ")");
+ return UINT_MAX;
+ }
+ else if( e.block.first > layer ) {
+ //throw ParseError::Generic( FMT("'" << name << "' is still repeating at this layer") );
+ // ignore mismatch
+ return UINT_MAX;
+ }
+ else {
+ return e.entries.size();
+ }
+ }
+};
+
+class MacroExpander:
+ public TokenStream
+{
+public:
+
+private:
+ const RcString m_macro_filename;
+
+ const ::std::string m_crate_name;
+ const ::std::vector<MacroRuleEnt>& m_root_contents;
+ const ParameterMappings m_mappings;
+
+
+ struct t_offset {
+ unsigned read_pos;
+ unsigned loop_index;
+ unsigned max_index;
+ };
+ /// Layer states : Index and Iteration
+ ::std::vector< t_offset > m_offsets;
+ ::std::vector< size_t > m_layer_iters;
+
+ /// Cached pointer to the current layer
+ const ::std::vector<MacroRuleEnt>* m_cur_ents; // For faster lookup.
+
+ Token m_next_token; // used for inserting a single token into the stream
+ ::std::unique_ptr<TTStream> m_ttstream;
+
+public:
+ MacroExpander(const MacroExpander& x) = delete;
+ //MacroExpander(const MacroExpander& x):
+ // m_macro_name( x.m_macro_name ),
+ // m_crate_name(x.m_crate_name),
+ // m_root_contents(x.m_root_contents),
+ // m_mappings(x.m_mappings),
+ // m_offsets({ {0,0,0} }),
+ // m_cur_ents(&m_root_contents)
+ //{
+ // prep_counts();
+ //}
+ MacroExpander(const ::std::string& macro_name, const ::std::vector<MacroRuleEnt>& contents, ParameterMappings mappings, ::std::string crate_name):
+ m_macro_filename( FMT("Macro:" << macro_name) ),
+ m_crate_name( mv$(crate_name) ),
+ m_root_contents(contents),
+ m_mappings( mv$(mappings) ),
+ m_offsets({ {0,0,0} }),
+ m_cur_ents(&m_root_contents)
+ {
+ prep_counts();
+ }
+
+ virtual Position getPosition() const override;
+ virtual Token realGetToken() override;
+private:
+ const MacroRuleEnt& getCurLayerEnt() const;
+ const ::std::vector<MacroRuleEnt>* getCurLayer() const;
+ void prep_counts();
+ unsigned int count_repeats(const ::std::vector<MacroRuleEnt>& ents, unsigned layer, unsigned iter);
+};
+
+void Macro_InitDefaults()
+{
+}
+
+bool Macro_TryPattern(TTStream& lex, const MacroPatEnt& pat)
+{
+ DEBUG("pat = " << pat);
+ Token tok;
+ switch(pat.type)
+ {
+ case MacroPatEnt::PAT_TOKEN: {
+ GET_TOK(tok, lex);
+ bool rv = (tok == pat.tok);
+ PUTBACK(tok, lex);
+ return rv;
+ }
+ case MacroPatEnt::PAT_LOOP:
+ if( pat.name == "*" )
+ return true;
+ return Macro_TryPattern(lex, pat.subpats[0]);
+ case MacroPatEnt::PAT_BLOCK:
+ return LOOK_AHEAD(lex) == TOK_BRACE_OPEN;
+ case MacroPatEnt::PAT_IDENT:
+ return LOOK_AHEAD(lex) == TOK_IDENT;
+ case MacroPatEnt::PAT_TT:
+ return LOOK_AHEAD(lex) != TOK_EOF;
+ case MacroPatEnt::PAT_PATH:
+ return is_token_path( LOOK_AHEAD(lex) );
+ case MacroPatEnt::PAT_TYPE:
+ return is_token_type( LOOK_AHEAD(lex) );
+ case MacroPatEnt::PAT_EXPR:
+ return is_token_expr( LOOK_AHEAD(lex) );
+ case MacroPatEnt::PAT_STMT:
+ return is_token_stmt( LOOK_AHEAD(lex) );
+ case MacroPatEnt::PAT_PAT:
+ return is_token_pat( LOOK_AHEAD(lex) );
+ case MacroPatEnt::PAT_META:
+ return LOOK_AHEAD(lex) == TOK_IDENT;
+ }
+ throw ParseError::Todo(lex, FMT("Macro_TryPattern : " << pat));
+}
+
+bool Macro_HandlePattern(TTStream& lex, const MacroPatEnt& pat, unsigned int layer, ParameterMappings& bound_tts)
+{
+ TRACE_FUNCTION_F("layer = " << layer);
+ Token tok;
+ TokenTree val;
+
+ switch(pat.type)
+ {
+ case MacroPatEnt::PAT_TOKEN:
+ DEBUG("Token " << pat.tok);
+ GET_CHECK_TOK(tok, lex, pat.tok.type());
+ break;
+ case MacroPatEnt::PAT_LOOP:
+ //case MacroPatEnt::PAT_OPTLOOP:
+ {
+ unsigned int match_count = 0;
+ DEBUG("Loop");
+ for(;;)
+ {
+ if( ! Macro_TryPattern(lex, pat.subpats[0]) )
+ {
+ DEBUG("break");
+ break;
+ }
+ for( unsigned int i = 0; i < pat.subpats.size(); i ++ )
+ {
+ if( !Macro_HandlePattern(lex, pat.subpats[i], layer+1, bound_tts) ) {
+ DEBUG("Ent " << i << " failed");
+ return false;
+ }
+ }
+ match_count += 1;
+ DEBUG("succ");
+ if( pat.tok.type() != TOK_NULL )
+ {
+ if( GET_TOK(tok, lex) != pat.tok.type() )
+ {
+ lex.putback( mv$(tok) );
+ break;
+ }
+ }
+ }
+ DEBUG("Done (" << match_count << " matches)");
+ break; }
+
+ case MacroPatEnt::PAT_TT:
+ DEBUG("TT");
+ if( GET_TOK(tok, lex) == TOK_EOF )
+ throw ParseError::Unexpected(lex, TOK_EOF);
+ else
+ PUTBACK(tok, lex);
+ val = Parse_TT(lex, false);
+ if(0)
+ case MacroPatEnt::PAT_PAT:
+ val = Parse_TT_Pattern(lex);
+ if(0)
+ case MacroPatEnt::PAT_TYPE:
+ val = Parse_TT_Type(lex);
+ if(0)
+ case MacroPatEnt::PAT_EXPR:
+ val = Parse_TT_Expr(lex);
+ if(0)
+ case MacroPatEnt::PAT_STMT:
+ val = Parse_TT_Stmt(lex);
+ if(0)
+ case MacroPatEnt::PAT_PATH:
+ val = Parse_TT_Path(lex, false); // non-expr mode
+ if(0)
+ case MacroPatEnt::PAT_BLOCK:
+ val = Parse_TT_Block(lex);
+ if(0)
+ case MacroPatEnt::PAT_META:
+ val = Parse_TT_Meta(lex);
+ if(0)
+ case MacroPatEnt::PAT_IDENT:
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ val = TokenTree(tok);
+ }
+ bound_tts.insert( layer, pat.name_index, ::std::move(val) );
+ break;
+
+ //default:
+ // throw ParseError::Todo("full macro pattern matching");
+ }
+ return true;
+}
+
+::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const TokenTree& input)
+{
+ TRACE_FUNCTION;
+
+ const auto* cur_frag = &rules.m_pattern;
+ unsigned int cur_frag_ofs = 0;
+
+ ParameterMappings bound_tts;
+ unsigned int rule_index;
+
+ TTStream lex(input);
+ while(true)
+ {
+ // If not at the end of the fragment, handle that pattern
+ if( cur_frag_ofs < cur_frag->m_pats_ents.size() )
+ {
+ const auto& pat = cur_frag->m_pats_ents[cur_frag_ofs];
+ DEBUG("- try " << pat);
+ if( !Macro_HandlePattern(lex, pat, 0, bound_tts) )
+ throw ParseError::Generic(lex, "Macro pattern failed");
+ // Keep going
+ cur_frag_ofs ++;
+ }
+ else
+ {
+ // The stream has ended
+ if( LOOK_AHEAD(lex) == TOK_EOF ) {
+ // Check if an end is expected here
+ if( cur_frag->m_pattern_end == ~0u ) {
+ Token tok = lex.getToken();
+ ERROR(tok.get_pos(), E0000, "Unexpected end of macro invocation - " << cur_frag_ofs << " != len [" << cur_frag->m_pats_ents << "]");
+ }
+ // We've found the rule!
+ rule_index = cur_frag->m_pattern_end;
+ break;
+ }
+
+ // Search for which path to take
+ for(const auto& next : cur_frag->m_next_frags) {
+ assert(next.m_pats_ents.size() > 0);
+ if( Macro_TryPattern(lex, next.m_pats_ents.front()) ) {
+ cur_frag = &next;
+ cur_frag_ofs = 0;
+ goto continue_;
+ }
+ }
+
+ // No paths matched - error out
+ {
+ ::std::stringstream expected;
+ for(const auto& next : cur_frag->m_next_frags) {
+ expected << next.m_pats_ents.front() << ", ";
+ }
+
+ Token tok = lex.getToken();
+ ERROR(tok.get_pos(), E0000, "Unexpected token in macro invocation - " << tok << " - expected " << expected.str());
+ }
+
+ continue_:
+ (void)0;
+ }
+ }
+
+ const auto& rule = rules.m_rules[rule_index];
+
+ DEBUG( rule.m_contents.size() << " rule contents bound to " << bound_tts.mappings().size() << " values - " << name );
+ bound_tts.reindex( rule.m_param_names );
+ for( unsigned int i = 0; i < bound_tts.mappings().size(); i ++ )
+ {
+ DEBUG(" - " << rule.m_param_names[i] << " = [" << bound_tts.mappings()[i] << "]");
+ }
+ bound_tts.dump();
+
+ DEBUG("TODO: Obtain crate name correctly");
+ TokenStream* ret_ptr = new MacroExpander(name, rule.m_contents, mv$(bound_tts), "");
+ // HACK! Disable nested macro expansion
+ //ret_ptr->parse_state().no_expand_macros = true;
+
+ return ::std::unique_ptr<TokenStream>( ret_ptr );
+}
+
+
+Position MacroExpander::getPosition() const
+{
+ return Position(m_macro_filename, 0, m_offsets[0].read_pos);
+}
+Token MacroExpander::realGetToken()
+{
+ // Use m_next_token first
+ if( m_next_token.type() != TOK_NULL )
+ {
+ DEBUG("m_next_token = " << m_next_token);
+ return ::std::move(m_next_token);
+ }
+ // Then try m_ttstream
+ if( m_ttstream.get() )
+ {
+ DEBUG("TTStream set");
+ Token rv = m_ttstream->getToken();
+ if( rv.type() != TOK_EOF )
+ return rv;
+ m_ttstream.reset();
+ }
+ //DEBUG("ofs " << m_offsets << " < " << m_root_contents.size());
+
+ // Check offset of lowest layer
+ while(m_offsets.size() > 0)
+ {
+ unsigned int layer = m_offsets.size() - 1;
+ const auto& ents = *m_cur_ents;
+
+ // Obtain current read position in layer, and increment
+ size_t idx = m_offsets.back().read_pos++;
+
+ // Check if limit has been reached
+ if( idx < ents.size() )
+ {
+ // - If not, just handle the next entry
+ const auto& ent = ents[idx];
+ // Check type of entry
+ // - XXX: Hack for $crate special name
+ if( ent.name == "*crate" )
+ {
+ DEBUG("Crate name hack");
+ if( m_crate_name != "" )
+ {
+ m_next_token = Token(TOK_STRING, m_crate_name);
+ return Token(TOK_DOUBLE_COLON);
+ }
+ }
+ // - Expand to a parameter
+ else if( ent.name != "" )
+ {
+ DEBUG("lookup '" << ent.name << "'");
+ const TokenTree* tt;
+ unsigned int search_layer = layer;
+ do {
+ unsigned int parent_iter = (search_layer > 0 ? m_layer_iters.at(search_layer-1) : 0);
+ const size_t iter_idx = m_offsets.at(search_layer).loop_index;
+ tt = m_mappings.get(search_layer, parent_iter, ent.name.c_str(), iter_idx);
+ } while( !tt && search_layer-- > 0 );
+ if( ! tt )
+ {
+ throw ParseError::Generic(*this, FMT("Cannot find '" << ent.name << "' for " << layer));
+ }
+ else
+ {
+ m_ttstream.reset( new TTStream(*tt) );
+ return m_ttstream->getToken();
+ }
+ }
+ // - Descend into a repetition
+ else if( ent.subpats.size() != 0 )
+ {
+ DEBUG("desc: layer = " << layer << ", m_layer_iters = " << m_layer_iters);
+ unsigned int layer_iter = m_layer_iters.at(layer);
+ unsigned int num_repeats = this->count_repeats(ent.subpats, layer+1, layer_iter);
+ if(num_repeats == UINT_MAX)
+ num_repeats = 0;
+ // New layer
+ DEBUG("- NL = " << layer+1 << ", count = " << num_repeats );
+ if( num_repeats > 0 )
+ {
+ // - Push an offset
+ m_offsets.push_back( {0, 0, num_repeats} );
+ // - Save the current layer
+ m_cur_ents = getCurLayer();
+ // - Restart loop for new layer
+ }
+ else
+ {
+ // Layer empty
+ DEBUG("Layer " << layer+1 << " is empty");
+ }
+ // VVV fall through and continue loop
+ }
+ // - Emit a raw token
+ else
+ {
+ return ent.tok;
+ }
+ // Fall through for loop
+ }
+ else if( layer > 0 )
+ {
+ // - Otherwise, restart/end loop and fall through
+ DEBUG("layer = " << layer << ", m_layer_iters = " << m_layer_iters);
+ auto& cur_ofs = m_offsets.back();
+ DEBUG("Layer #" << layer << " Cur: " << cur_ofs.loop_index << ", Max: " << cur_ofs.max_index);
+ if( cur_ofs.loop_index + 1 < cur_ofs.max_index )
+ {
+ m_layer_iters.at(layer) ++;
+
+ DEBUG("Restart layer");
+ cur_ofs.read_pos = 0;
+ cur_ofs.loop_index ++;
+
+ auto& loop_layer = getCurLayerEnt();
+ assert(loop_layer.subpats.size());
+ if( loop_layer.tok.type() != TOK_NULL ) {
+ DEBUG("- Separator token = " << loop_layer.tok);
+ return loop_layer.tok;
+ }
+ // Fall through and restart layer
+ }
+ else
+ {
+ DEBUG("Terminate layer");
+ // Terminate loop, fall through to lower layers
+ m_offsets.pop_back();
+ // - Special case: End of macro, avoid issues
+ if( m_offsets.size() == 0 )
+ break;
+ m_cur_ents = getCurLayer();
+ }
+ }
+ else
+ {
+ DEBUG("Terminate evaluation");
+ m_offsets.pop_back();
+ assert( m_offsets.size() == 0 );
+ }
+ } // while( m_offsets NONEMPTY )
+
+ DEBUG("EOF");
+ return Token(TOK_EOF);
+}
+
+/// Count the number of names at each layer
+void MacroExpander::prep_counts()
+{
+ m_layer_iters.resize(m_mappings.layer_count(), 0);
+}
+const MacroRuleEnt& MacroExpander::getCurLayerEnt() const
+{
+ assert( m_offsets.size() > 1 );
+
+ const ::std::vector<MacroRuleEnt>* ents = &m_root_contents;
+ for( unsigned int i = 0; i < m_offsets.size()-2; i ++ )
+ {
+ unsigned int ofs = m_offsets[i].read_pos;
+ assert( ofs > 0 && ofs <= ents->size() );
+ ents = &(*ents)[ofs-1].subpats;
+ }
+ return (*ents)[m_offsets[m_offsets.size()-2].read_pos-1];
+
+}
+const ::std::vector<MacroRuleEnt>* MacroExpander::getCurLayer() const
+{
+ assert( m_offsets.size() > 0 );
+ const ::std::vector<MacroRuleEnt>* ents = &m_root_contents;
+ for( unsigned int i = 0; i < m_offsets.size()-1; i ++ )
+ {
+ unsigned int ofs = m_offsets[i].read_pos;
+ //DEBUG(i << " ofs=" << ofs << " / " << ents->size());
+ assert( ofs > 0 && ofs <= ents->size() );
+ ents = &(*ents)[ofs-1].subpats;
+ //DEBUG("ents = " << ents);
+ }
+ return ents;
+}
+unsigned int MacroExpander::count_repeats(const ::std::vector<MacroRuleEnt>& ents, unsigned layer, unsigned iter)
+{
+ bool valid = false;
+ unsigned int count = 0;
+ for(const auto& ent : ents)
+ {
+ if( ent.name != "" )
+ {
+ if( ent.name[0] == '*' ) {
+ // Ignore meta-vars, they don't repeat
+ }
+ else {
+ auto c = m_mappings.count(layer, iter, ent.name.c_str());
+ DEBUG(c << " mappings for " << ent.name << " at (" << layer << ", " << iter << ")");
+ if( c == UINT_MAX ) {
+ // Ignore
+ }
+ else if(!valid || count == c) {
+ count = c;
+ valid = true;
+ }
+ else {
+ // Mismatch!
+ throw ParseError::Generic("count_repeats - iteration count mismatch");
+ }
+ }
+ }
+ else if( ent.subpats.size() > 0 )
+ {
+ auto c = this->count_repeats(ent.subpats, layer, iter);
+ if( c == UINT_MAX ) {
+ }
+ else if(!valid || count == c) {
+ count = c;
+ valid = true;
+ }
+ else {
+ // Mismatch!
+ throw ParseError::Generic("count_repeats - iteration count mismatch (subpat)");
+ }
+ }
+ else
+ {
+ // Don't care
+ }
+ }
+
+ if(valid) {
+ return count;
+ }
+ else {
+ return UINT_MAX;
+ }
+}
+
diff --git a/src/macros.hpp b/src/macro_rules/macro_rules.hpp
index f10326c5..65822fa5 100644
--- a/src/macros.hpp
+++ b/src/macro_rules/macro_rules.hpp
@@ -7,13 +7,10 @@
#include <map>
#include <memory>
#include <cstring>
+#include "macro_rules_ptr.hpp"
class MacroExpander;
-namespace AST {
- class Module;
-}
-
class MacroRuleEnt:
public Serialisable
{
@@ -51,6 +48,7 @@ struct MacroPatEnt:
public Serialisable
{
::std::string name;
+ unsigned int name_index;
Token tok;
::std::vector<MacroPatEnt> subpats;
@@ -81,8 +79,9 @@ struct MacroPatEnt:
{
}
- MacroPatEnt(::std::string name, Type type):
+ MacroPatEnt(::std::string name, unsigned int name_index, Type type):
name( mv$(name) ),
+ name_index( name_index ),
tok(),
type(type)
{
@@ -101,14 +100,33 @@ struct MacroPatEnt:
SERIALISABLE_PROTOTYPES();
};
-/// A rule within a macro_rules! blcok
-class MacroRule:
+struct MacroRulesPatFrag:
public Serialisable
{
-public:
- ::std::vector<MacroPatEnt> m_pattern;
+ ::std::vector<MacroPatEnt> m_pats_ents;
+ unsigned int m_pattern_end;
+ ::std::vector< MacroRulesPatFrag > m_next_frags;
+
+ MacroRulesPatFrag():
+ m_pattern_end(~0)
+ {}
+
+ SERIALISABLE_PROTOTYPES();
+};
+
+/// An arm within a macro_rules! blcok
+struct MacroRulesArm:
+ public Serialisable
+{
+ ::std::vector< ::std::string> m_param_names;
::std::vector<MacroRuleEnt> m_contents;
+ MacroRulesArm()
+ {}
+ MacroRulesArm(::std::vector<MacroRuleEnt> contents):
+ m_contents( mv$(contents) )
+ {}
+
SERIALISABLE_PROTOTYPES();
};
@@ -118,20 +136,18 @@ class MacroRules:
{
public:
bool m_exported;
- ::std::vector<MacroRule> m_rules;
+ MacroRulesPatFrag m_pattern;
+ ::std::vector<MacroRulesArm> m_rules;
MacroRules()
{
}
- MacroRules( ::std::vector<MacroRule> rules ):
- m_rules( mv$(rules) )
- {
- }
+ virtual ~MacroRules();
SERIALISABLE_PROTOTYPES();
};
extern ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const TokenTree& input);
-extern ::std::unique_ptr<TokenStream> Macro_Invoke(const TokenStream& lex, const ::std::string& name, const TokenTree& input);
+extern MacroRulesPtr Parse_MacroRules(TokenStream& lex);
#endif // MACROS_HPP_INCLUDED
diff --git a/src/macro_rules/macro_rules_ptr.hpp b/src/macro_rules/macro_rules_ptr.hpp
new file mode 100644
index 00000000..512cbda2
--- /dev/null
+++ b/src/macro_rules/macro_rules_ptr.hpp
@@ -0,0 +1,31 @@
+/*
+ */
+#pragma once
+
+class MacroRules;
+
+class MacroRulesPtr:
+ public Serialisable
+{
+ MacroRules* m_ptr;
+public:
+ MacroRulesPtr() {}
+ MacroRulesPtr(MacroRules* p): m_ptr(p) {}
+ MacroRulesPtr(MacroRulesPtr&& x):
+ m_ptr(x.m_ptr)
+ {
+ x.m_ptr = nullptr;
+ }
+ MacroRulesPtr& operator=(MacroRulesPtr&& x)
+ {
+ m_ptr = x.m_ptr; x.m_ptr = nullptr;
+ return *this;
+ }
+
+ ~MacroRulesPtr();
+
+ MacroRules& operator*() { assert(m_ptr); return *m_ptr; }
+ const MacroRules& operator*() const { assert(m_ptr); return *m_ptr; }
+
+ SERIALISABLE_PROTOTYPES();
+};
diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp
new file mode 100644
index 00000000..e3699a3d
--- /dev/null
+++ b/src/macro_rules/mod.cpp
@@ -0,0 +1,203 @@
+/*
+ */
+#include <common.hpp>
+#include "macro_rules.hpp"
+#include <parse/parseerror.hpp>
+#include <parse/tokentree.hpp>
+#include <parse/common.hpp>
+#include <limits.h>
+
+#include "pattern_checks.hpp"
+
+bool is_token_path(eTokenType tt) {
+ switch(tt)
+ {
+ case TOK_IDENT:
+ case TOK_DOUBLE_COLON:
+ case TOK_LT:
+ case TOK_DOUBLE_LT:
+ case TOK_RWORD_SELF:
+ case TOK_RWORD_SUPER:
+ return true;
+ default:
+ return false;
+ }
+}
+bool is_token_pat(eTokenType tt) {
+ if( is_token_path(tt) )
+ return true;
+ switch( tt )
+ {
+ case TOK_PAREN_OPEN:
+ case TOK_SQUARE_OPEN:
+
+ case TOK_AMP:
+ case TOK_RWORD_BOX:
+ case TOK_RWORD_REF:
+ case TOK_RWORD_MUT:
+ case TOK_STRING:
+ case TOK_INTEGER:
+ case TOK_CHAR:
+ return true;
+ default:
+ return false;
+ }
+}
+bool is_token_type(eTokenType tt) {
+ if( is_token_path(tt) )
+ return true;
+ switch( tt )
+ {
+ case TOK_PAREN_OPEN:
+ case TOK_SQUARE_OPEN:
+ case TOK_STAR:
+ case TOK_AMP:
+ return true;
+ default:
+ return false;
+ }
+}
+bool is_token_expr(eTokenType tt) {
+ if( is_token_path(tt) )
+ return true;
+ switch( tt )
+ {
+ case TOK_AMP:
+ case TOK_STAR:
+ case TOK_PAREN_OPEN:
+ case TOK_MACRO:
+ case TOK_DASH:
+
+ case TOK_INTEGER:
+ case TOK_STRING:
+ return true;
+ default:
+ return false;
+ }
+}
+bool is_token_stmt(eTokenType tt) {
+ if( is_token_expr(tt) )
+ return true;
+ switch( tt )
+ {
+ case TOK_BRACE_OPEN:
+ case TOK_RWORD_LET:
+ return true;
+ default:
+ return false;
+ }
+}
+
+MacroRulesPtr::~MacroRulesPtr()
+{
+ if(m_ptr)
+ {
+ delete m_ptr;
+ m_ptr = nullptr;
+ }
+}
+SERIALISE_TYPE(MacroRulesPtr::, "MacroRulesPtr", {
+},{
+})
+
+SERIALISE_TYPE_S(MacroRulesArm, {
+})
+SERIALISE_TYPE_S(MacroRulesPatFrag, {
+})
+
+void operator%(Serialiser& s, MacroPatEnt::Type c) {
+ switch(c) {
+ #define _(v) case MacroPatEnt::v: s << #v; return
+ _(PAT_TOKEN);
+ _(PAT_TT);
+ _(PAT_PAT);
+ _(PAT_TYPE);
+ _(PAT_EXPR);
+ _(PAT_LOOP);
+ _(PAT_STMT);
+ _(PAT_PATH);
+ _(PAT_BLOCK);
+ _(PAT_META);
+ _(PAT_IDENT);
+ #undef _
+ }
+}
+void operator%(::Deserialiser& s, MacroPatEnt::Type& c) {
+ ::std::string n;
+ s.item(n);
+ #define _(v) else if(n == #v) c = MacroPatEnt::v
+ if(0) ;
+ _(PAT_TOKEN);
+ _(PAT_TT);
+ _(PAT_PAT);
+ _(PAT_TYPE);
+ _(PAT_EXPR);
+ _(PAT_LOOP);
+ //_(PAT_OPTLOOP);
+ _(PAT_STMT);
+ _(PAT_PATH);
+ _(PAT_BLOCK);
+ _(PAT_META);
+ _(PAT_IDENT);
+ else
+ throw ::std::runtime_error( FMT("No conversion for '" << n << "'") );
+ #undef _
+}
+SERIALISE_TYPE_S(MacroPatEnt, {
+ s % type;
+ s.item(name);
+ s.item(tok);
+ s.item(subpats);
+});
+::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x)
+{
+ switch(x.type)
+ {
+ case MacroPatEnt::PAT_TOKEN: os << "=" << x.tok; break;
+ case MacroPatEnt::PAT_LOOP: os << "loop w/ " << x.tok << " [" << x.subpats << "]"; break;
+ default:
+ os << "$" << x.name << ":";
+ switch(x.type)
+ {
+ case MacroPatEnt::PAT_TOKEN: throw "";
+ case MacroPatEnt::PAT_LOOP: throw "";
+ case MacroPatEnt::PAT_TT: os << "tt"; break;
+ case MacroPatEnt::PAT_PAT: os << "pat"; break;
+ case MacroPatEnt::PAT_IDENT: os << "ident"; break;
+ case MacroPatEnt::PAT_PATH: os << "path"; break;
+ case MacroPatEnt::PAT_TYPE: os << "type"; break;
+ case MacroPatEnt::PAT_EXPR: os << "expr"; break;
+ case MacroPatEnt::PAT_STMT: os << "stmt"; break;
+ case MacroPatEnt::PAT_BLOCK: os << "block"; break;
+ case MacroPatEnt::PAT_META: os << "meta"; break;
+ }
+ break;
+ }
+ return os;
+}
+
+SERIALISE_TYPE_S(MacroRuleEnt, {
+ s.item(name);
+ s.item(tok);
+ s.item(subpats);
+});
+
+::std::ostream& operator<<(::std::ostream& os, const MacroRuleEnt& x)
+{
+ if(x.name.size())
+ os << "$"<<x.name;
+ else if( x.subpats.size() )
+ os << "expand w/ " << x.tok << " [" << x.subpats << "]";
+ else
+ os << "=" << x.tok;
+ return os;
+}
+
+MacroRules::~MacroRules()
+{
+}
+SERIALISE_TYPE_S(MacroRules, {
+ s.item( m_exported );
+ s.item( m_rules );
+});
+
diff --git a/src/parse/macro_rules.cpp b/src/macro_rules/parse.cpp
index 94f55e2d..2d8ad374 100644
--- a/src/parse/macro_rules.cpp
+++ b/src/macro_rules/parse.cpp
@@ -1,11 +1,22 @@
+/*
+ */
#include <common.hpp>
#include "../parse/common.hpp"
#include "../parse/parseerror.hpp"
-#include "../macros.hpp"
+#include "macro_rules.hpp"
+#include "pattern_checks.hpp"
-MacroRules Parse_MacroRules(TokenStream& lex);
+MacroRulesPtr Parse_MacroRules(TokenStream& lex);
-::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, bool allow_sub, enum eTokenType open, enum eTokenType close)
+/// A rule within a macro_rules! blcok
+class MacroRule
+{
+public:
+ ::std::vector<MacroPatEnt> m_pattern;
+ ::std::vector<MacroRuleEnt> m_contents;
+};
+
+::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, bool allow_sub, enum eTokenType open, enum eTokenType close, ::std::vector< ::std::string>& names)
{
TRACE_FUNCTION;
Token tok;
@@ -36,31 +47,36 @@ MacroRules Parse_MacroRules(TokenStream& lex);
GET_CHECK_TOK(tok, lex, TOK_COLON);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
::std::string type = tok.str();
+
+ unsigned int idx = ::std::find( names.begin(), names.end(), name ) - names.begin();
+ if( idx == names.size() )
+ names.push_back( name );
+
if(0)
;
else if( type == "tt" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_TT) );
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_TT) );
else if( type == "pat" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_PAT) );
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_PAT) );
else if( type == "ident" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_IDENT) );
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_IDENT) );
else if( type == "path" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_PATH) );
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_PATH) );
else if( type == "expr" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_EXPR) );
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_EXPR) );
else if( type == "ty" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_TYPE) );
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_TYPE) );
else if( type == "meta" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_META) );
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_META) );
else if( type == "block" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_BLOCK) );
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_BLOCK) );
else
throw ParseError::Generic(lex, FMT("Unknown fragment type '" << type << "'"));
break; }
case TOK_PAREN_OPEN:
if( allow_sub )
{
- auto subpat = Parse_MacroRules_Pat(lex, true, TOK_PAREN_OPEN, TOK_PAREN_CLOSE);
+ auto subpat = Parse_MacroRules_Pat(lex, true, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names);
enum eTokenType joiner = TOK_NULL;
GET_TOK(tok, lex);
if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR )
@@ -204,7 +220,8 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex)
throw ParseError::Unexpected(lex, tok);
}
// - Pattern entries
- rule.m_pattern = Parse_MacroRules_Pat(lex, true, tok.type(), close);
+ ::std::vector< ::std::string> names;
+ rule.m_pattern = Parse_MacroRules_Pat(lex, true, tok.type(), close, names);
GET_CHECK_TOK(tok, lex, TOK_FATARROW);
@@ -223,104 +240,15 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex)
return rule;
}
-struct UnifiedPatFrag
-{
- ::std::vector<MacroPatEnt> m_pats_ents;
- unsigned int m_pattern_end;
- ::std::vector< UnifiedPatFrag > m_next_frags;
-
- UnifiedPatFrag():
- m_pattern_end(~0)
- {}
-
- UnifiedPatFrag split_at(unsigned int remaining_count) {
- UnifiedPatFrag rv;
- for(unsigned int i = remaining_count; i < m_pats_ents.size(); i ++)
- rv.m_pats_ents.push_back( mv$(m_pats_ents[i]) );
- m_pats_ents.resize(remaining_count);
- rv.m_pattern_end = m_pattern_end; m_pattern_end = ~0;
- rv.m_next_frags = mv$(m_next_frags);
- return rv;
- }
-};
-
-struct UnifiedMacroRules
-{
- UnifiedPatFrag m_pattern;
-};
-
-bool is_token_path(eTokenType tt) {
- switch(tt)
- {
- case TOK_IDENT:
- case TOK_DOUBLE_COLON:
- case TOK_LT:
- case TOK_DOUBLE_LT:
- case TOK_RWORD_SELF:
- case TOK_RWORD_SUPER:
- return true;
- default:
- return false;
- }
-}
-bool is_token_pat(eTokenType tt) {
- if( is_token_path(tt) )
- return true;
- switch( tt )
- {
- case TOK_PAREN_OPEN:
- case TOK_SQUARE_OPEN:
-
- case TOK_AMP:
- case TOK_RWORD_BOX:
- case TOK_RWORD_REF:
- case TOK_RWORD_MUT:
- case TOK_STRING:
- case TOK_INTEGER:
- case TOK_CHAR:
- return true;
- default:
- return false;
- }
-}
-bool is_token_type(eTokenType tt) {
- if( is_token_path(tt) )
- return true;
- switch( tt )
- {
- case TOK_PAREN_OPEN:
- case TOK_SQUARE_OPEN:
- case TOK_STAR:
- case TOK_AMP:
- return true;
- default:
- return false;
- }
-}
-bool is_token_expr(eTokenType tt) {
- if( is_token_path(tt) )
- return true;
- switch( tt )
- {
- case TOK_AMP:
- case TOK_STAR:
- case TOK_PAREN_OPEN:
- case TOK_MACRO:
- case TOK_DASH:
-
- case TOK_INTEGER:
- case TOK_STRING:
- return true;
- default:
- return false;
- }
-}
-
bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEnt& right)
{
if( left.type > right.type )
return patterns_are_same(sp, right, left);
+ //if( left.name != right.name ) {
+ // TODO(sp, "Handle different binding names " << left << " != " << right);
+ //}
+
// NOTE: left.type <= right.type
switch(right.type)
{
@@ -414,16 +342,9 @@ bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEn
switch(left.type)
{
case MacroPatEnt::PAT_TOKEN:
- switch(left.tok.type())
- {
- case TOK_BRACE_OPEN:
- case TOK_RWORD_LET:
+ if( is_token_stmt(left.tok.type()) )
ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- default:
- if( is_token_expr(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- }
+ return false;
case MacroPatEnt::PAT_STMT:
return true;
default:
@@ -443,29 +364,56 @@ bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEn
return false;
}
// Matches meta/attribute fragments.
- // - Compatible with everythin but a literal #[ token
case MacroPatEnt::PAT_META:
switch(left.type)
{
case MacroPatEnt::PAT_TOKEN:
- if( left.tok.type() == TOK_ATTR_OPEN )
+ if( left.tok.type() == TOK_IDENT )
ERROR(sp, E0000, "Incompatible macro fragments");
return false;
case MacroPatEnt::PAT_META:
return true;
default:
- return false;
+ ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
}
}
throw "";
}
-MacroRules Parse_MacroRules(TokenStream& lex)
+MacroRulesPatFrag split_fragment_at(MacroRulesPatFrag& frag, unsigned int remaining_count)
+{
+ MacroRulesPatFrag rv;
+ for(unsigned int i = remaining_count; i < frag.m_pats_ents.size(); i ++)
+ rv.m_pats_ents.push_back( mv$(frag.m_pats_ents[i]) );
+ frag.m_pats_ents.resize(remaining_count);
+ rv.m_pattern_end = frag.m_pattern_end; frag.m_pattern_end = ~0;
+ rv.m_next_frags = mv$(frag.m_next_frags);
+ return rv;
+}
+
+void enumerate_names(const ::std::vector<MacroPatEnt>& pats, ::std::vector< ::std::string>& names) {
+ for( const auto& pat : pats )
+ {
+ if( pat.type == MacroPatEnt::PAT_LOOP ) {
+ enumerate_names(pat.subpats, names);
+ }
+ else if( pat.name != "" ) {
+ auto b = names.begin();
+ auto e = names.end();
+ if( ::std::find(b, e, pat.name) == e ) {
+ names.push_back( pat.name );
+ }
+ }
+ }
+}
+
+MacroRulesPtr Parse_MacroRules(TokenStream& lex)
{
TRACE_FUNCTION_F("");
Token tok;
+ // Parse the patterns and replacements
::std::vector<MacroRule> rules;
while( GET_TOK(tok, lex) != TOK_EOF )
{
@@ -478,14 +426,18 @@ MacroRules Parse_MacroRules(TokenStream& lex)
}
}
- UnifiedPatFrag root_frag;
+ MacroRulesPatFrag root_frag;
+ ::std::vector<MacroRulesArm> rule_arms;
// Re-parse the patterns into a unified form
for(unsigned int rule_idx = 0; rule_idx < rules.size(); rule_idx ++)
{
const auto& rule = rules[rule_idx];
+ MacroRulesArm arm( mv$(rule.m_contents) );
- UnifiedPatFrag* cur_frag = &root_frag;
+ enumerate_names(rule.m_pattern, arm.m_param_names);
+
+ auto* cur_frag = &root_frag;
unsigned int frag_ofs = 0;
for( const auto& pat : rule.m_pattern )
{
@@ -509,7 +461,7 @@ MacroRules Parse_MacroRules(TokenStream& lex)
}
// If not, create a new frag
if( ! found ) {
- cur_frag->m_next_frags.push_back( UnifiedPatFrag() );
+ cur_frag->m_next_frags.push_back( MacroRulesPatFrag() );
cur_frag = &cur_frag->m_next_frags.back();
cur_frag->m_pats_ents.push_back( pat );
}
@@ -518,12 +470,12 @@ MacroRules Parse_MacroRules(TokenStream& lex)
}
else if( ! patterns_are_same(sp, cur_frag->m_pats_ents[frag_ofs], pat) ) {
// Difference, split the block.
- auto new_frag = cur_frag->split_at(frag_ofs);
+ auto new_frag = split_fragment_at(*cur_frag, frag_ofs);
assert( cur_frag->m_next_frags.size() == 0 );
cur_frag->m_next_frags.push_back( mv$(new_frag) );
// - Update cur_frag to a newly pushed fragment, and push this pattern to it
- cur_frag->m_next_frags.push_back( UnifiedPatFrag() );
+ cur_frag->m_next_frags.push_back( MacroRulesPatFrag() );
cur_frag = &cur_frag->m_next_frags.back();
cur_frag->m_pats_ents.push_back( pat );
frag_ofs = 1;
@@ -537,15 +489,21 @@ MacroRules Parse_MacroRules(TokenStream& lex)
// If this pattern ended before the current fragment ended
if( frag_ofs < cur_frag->m_pats_ents.size() ) {
// Split the current fragment
- auto new_frag = cur_frag->split_at(frag_ofs);
+ auto new_frag = split_fragment_at(*cur_frag, frag_ofs);
assert( cur_frag->m_next_frags.size() == 0 );
cur_frag->m_next_frags.push_back( mv$(new_frag) );
// Keep cur_frag the same
}
cur_frag->m_pattern_end = rule_idx;
+
+ rule_arms.push_back( mv$(arm) );
}
// TODO: use `root_frag` above for the actual evaluation
- return MacroRules( mv$(rules) );
+ auto rv = new MacroRules();
+ rv->m_pattern = mv$(root_frag);
+ rv->m_rules = mv$(rule_arms);
+
+ return MacroRulesPtr(rv);
}
diff --git a/src/macro_rules/pattern_checks.hpp b/src/macro_rules/pattern_checks.hpp
new file mode 100644
index 00000000..820a9ef4
--- /dev/null
+++ b/src/macro_rules/pattern_checks.hpp
@@ -0,0 +1,10 @@
+/*
+ */
+#pragma once
+
+extern bool is_token_path(eTokenType tt);
+extern bool is_token_pat(eTokenType tt);
+extern bool is_token_type(eTokenType tt);
+extern bool is_token_expr(eTokenType tt);
+extern bool is_token_stmt(eTokenType tt);
+
diff --git a/src/main.cpp b/src/main.cpp
index 963491d5..8bd944ef 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,6 +22,7 @@ int g_debug_indent_level = 0;
bool debug_enabled()
{
+ //return g_cur_phase != "Parse";
return g_cur_phase != "Parse" && g_cur_phase != "Expand";
}
::std::ostream& debug_output(int indent, const char* function)
@@ -145,14 +146,16 @@ int main(int argc, char *argv[])
});
// Typecheck / type propagate module (type annotations of all values)
// - Check all generic conditions (ensure referenced trait is valid)
- // > Also mark parameter with applicable traits
+ // > Binds the trait path to the actual trait definition
CompilePhaseV("TypecheckBounds", [&]() {
//Typecheck_GenericBounds(crate);
});
// - Check all generic parameters match required conditions (without doing full typeck)
+ // >
CompilePhaseV("TypecheckParams", [&]() {
//Typecheck_GenericParams(crate);
});
+ // TODO: Evaluate all constants (or MIR them then evaluate)
// - Full function typeck
CompilePhaseV("TypecheckExpr", [&]() {
//Typecheck_Expr(crate);
diff --git a/src/parse/common.hpp b/src/parse/common.hpp
index 9ba8b8cd..d7f84315 100644
--- a/src/parse/common.hpp
+++ b/src/parse/common.hpp
@@ -44,8 +44,6 @@ extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::AST::MetaIte
extern TypeRef Parse_Type(TokenStream& lex);
extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable);
-extern MacroRules Parse_MacroRules(TokenStream& lex);
-
extern void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl);
extern void Parse_Mod_Item(TokenStream& lex, bool file_controls_dir, const ::std::string& file_path, AST::Module& mod, bool is_public, AST::MetaItems meta_items);
extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod, bool file_controls_dir, const ::std::string& path);
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index e047c408..7094cf96 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -13,7 +13,6 @@
#include "parseerror.hpp"
#include "../ast/ast.hpp"
#include "common.hpp"
-#include "../macros.hpp"
#include <iostream>
#include "tokentree.hpp"
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index dd3d8904..4f856fbc 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -13,7 +13,6 @@
#include "../ast/crate.hpp"
#include "parseerror.hpp"
#include "common.hpp"
-#include "../macros.hpp"
#include <cassert>
::std::string dirname(::std::string input) {