1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <sng2html/sng2html/LinkerVisitor.hpp>
  7 #include <sng2html/sng2html/Domain.hpp>
  8 #include <soulng/util/Unicode.hpp>
  9 #include <soulng/util/Util.hpp>
 10 
 11 namespace sng2html { namespace sng2html {
 12 
 13 using namespace soulng::unicode;
 14 using namespace soulng::util;
 15 
 16 LinkerVisitor::LinkerVisitor() : domain(nullptr)currentParser(nullptr)currentRule(nullptr)stage(Stage::addParsers)
 17 {
 18 }
 19 
 20 void LinkerVisitor::Visit(OptionalParser& parser)
 21 {
 22     parser.Child()->Accept(*this);
 23 }
 24 
 25 void LinkerVisitor::Visit(KleeneParser& parser)
 26 {
 27     parser.Child()->Accept(*this);
 28 }
 29 
 30 void LinkerVisitor::Visit(PositiveParser& parser)
 31 {
 32     parser.Child()->Accept(*this);
 33 }
 34 
 35 void LinkerVisitor::Visit(ExpectationParser& parser)
 36 {
 37     parser.Child()->Accept(*this);
 38 }
 39 
 40 void LinkerVisitor::Visit(GroupingParser& parser)
 41 {
 42     parser.Child()->Accept(*this);
 43 }
 44 
 45 void LinkerVisitor::Visit(SequenceParser& parser)
 46 {
 47     parser.Left()->Accept(*this);
 48     parser.Right()->Accept(*this);
 49 }
 50 
 51 void LinkerVisitor::Visit(AlternativeParser& parser)
 52 {
 53     parser.Left()->Accept(*this);
 54     parser.Right()->Accept(*this);
 55 }
 56 
 57 void LinkerVisitor::Visit(DifferenceParser& parser)
 58 {
 59     parser.Left()->Accept(*this);
 60     parser.Right()->Accept(*this);
 61 }
 62 
 63 void LinkerVisitor::Visit(ListParser& parser)
 64 {
 65     parser.Child()->Accept(*this);
 66 }
 67 
 68 void LinkerVisitor::Visit(ActionParser& parser)
 69 {
 70     parser.Child()->Accept(*this);
 71 }
 72 
 73 void LinkerVisitor::Visit(NonterminalParser& parser)
 74 {
 75     currentRule->AddNonterminal(&parser);
 76     RuleParser* rule = currentParser->GetRule(parser.RuleName());
 77     parser.SetRule(rule);
 78     if (rule->Parameters().size() != parser.Arguments().size())
 79     {
 80         throw std::runtime_error("Rule '" + ToUtf8(rule->Name()) + "' takes " + std::to_string(rule->Parameters().size()) + " parameters (" + 
 81             std::to_string(parser.Arguments().size()) + " arguments supplied). Detected in parser '" + ToUtf8(currentParser->Name()) + "' rule '" + ToUtf8(currentRule->Name()) + "'.");
 82     }
 83 }
 84 
 85 void LinkerVisitor::Visit(RuleParser& parser)
 86 {
 87     currentRule = &parser;
 88     parser.Definition()->Accept(*this);
 89 }
 90 
 91 void LinkerVisitor::Visit(GrammarParser& parser)
 92 {
 93     if (stage == Stage::addParsers)
 94     {
 95         domain->AddParser(&parser);
 96     }
 97     else if (stage == Stage::resolveRules)
 98     {
 99         currentParser = &parser;
100         for (const auto& u : parser.Usings())
101         {
102             std::vector<std::u32string> components = Split(u'.');
103             if (components.size() != 2)
104             {
105                 throw std::runtime_error("invalid using '" + ToUtf8(u) + "' in parser '" + ToUtf8(parser.Name()) + "'");
106             }
107             const std::u32string& parserName = components[0];
108             const std::u32string& ruleName = components[1];
109             GrammarParser* targetParser = domain->GetParser(parserName);
110             RuleParser* rule = targetParser->GetRule(ruleName);
111             parser.MapRule(rule);
112         }
113         for (const auto& rule : parser.Rules())
114         {
115             rule->Accept(*this);
116         }
117         for (const auto& ruleInfo : parser.RuleInfos())
118         {
119             RuleParser* rule = parser.GetRule(ruleInfo.first);
120             rule->SetInfo(ruleInfo.second);
121         }
122     }
123 }
124 
125 void LinkerVisitor::Visit(ParserFile& parserFile)
126 {
127     for (const auto& parser : parserFile.Parsers())
128     {
129         parser->Accept(*this);
130     }
131 }
132 
133 void LinkerVisitor::Visit(Domain& domain)
134 {
135     this->domain = &domain;
136     stage = Stage::addParsers;
137     for (const auto& parserFile : domain.ParserFiles())
138     {
139         parserFile->Accept(*this);
140     }
141     stage = Stage::resolveRules;
142     for (const auto& parserFile : domain.ParserFiles())
143     {
144         parserFile->Accept(*this);
145     }
146 }
147 
148 } } // namespace sng2html::sng2html