1 using System;
2 using System.Collections;
3
4 namespace soulcm.scm2html
5 {
6 public class LinkerVisitor : Visitor
7 {
8 public LinkerVisitor() :
9 domain(null), currentParser(null), currentRule(null), stage(Stage.addParsers)
10 {
11 }
12 public enum Stage
13 {
14 addParsers, resolveRules
15 }
16 public override void Visit(OptionalParser& parser)
17 {
18 parser.Child()->Accept(*this);
19 }
20 public override void Visit(KleeneParser& parser)
21 {
22 parser.Child()->Accept(*this);
23 }
24 public override void Visit(PositiveParser& parser)
25 {
26 parser.Child()->Accept(*this);
27 }
28 public override void Visit(ExpectationParser& parser)
29 {
30 parser.Child()->Accept(*this);
31 }
32 public override void Visit(GroupingParser& parser)
33 {
34 parser.Child()->Accept(*this);
35 }
36 public override void Visit(SequenceParser& parser)
37 {
38 parser.Left()->Accept(*this);
39 parser.Right()->Accept(*this);
40 }
41 public override void Visit(AlternativeParser& parser)
42 {
43 parser.Left()->Accept(*this);
44 parser.Right()->Accept(*this);
45 }
46 public override void Visit(DifferenceParser& parser)
47 {
48 parser.Left()->Accept(*this);
49 parser.Right()->Accept(*this);
50 }
51 public override void Visit(ListParser& parser)
52 {
53 parser.Child()->Accept(*this);
54 }
55 public override void Visit(ActionParser& parser)
56 {
57 parser.Child()->Accept(*this);
58 }
59 public override void Visit(NonterminalParser& parser)
60 {
61 currentRule->AddNonterminal(&parser);
62 RuleParser* rule = currentParser->GetRule(parser.RuleName());
63 parser.SetRule(rule);
64 if (rule->Parameters().Count() != parser.Arguments().Count())
65 {
66 throw Exception("Rule \'" + ToUtf8(rule->Name()) + "\' takes " + ToString(rule->Parameters().Count()) + " parameters (" + ToString(parser.Arguments().Count()) + " arguments supplied). Detected in parser \'" + ToUtf8(currentParser->Name()) + "\' rule \'" + ToUtf8(currentRule->Name()) + "\'.");
67 }
68 }
69 public override void Visit(RuleParser& parser)
70 {
71 currentRule = &parser;
72 parser.Definition()->Accept(*this);
73 }
74 public override void Visit(GrammarParser& parser)
75 {
76 if (stage == Stage.addParsers)
77 {
78 domain->AddParser(&parser);
79 }
80 else if (stage == Stage.resolveRules)
81 {
82 currentParser = &parser;
83 for (const ustring& u : parser.Usings())
84 {
85 List<ustring> components = u.Split('.');
86 if (components.Count() != 2)
87 {
88 throw Exception("invalid using \'" + ToUtf8(u) + "\' in parser \'" + ToUtf8(parser.Name()) + "\'");
89 }
90 const ustring& parserName = components[0];
91 const ustring& ruleName = components[1];
92 GrammarParser* targetParser = domain->GetParser(parserName);
93 RuleParser* rule = targetParser->GetRule(ruleName);
94 parser.MapRule(rule);
95 }
96 for (const UniquePtr<RuleParser>& rule : parser.Rules())
97 {
98 rule->Accept(*this);
99 }
100 for (const Pair<ustring, ustring>& ruleInfo : parser.RuleInfos())
101 {
102 RuleParser* rule = parser.GetRule(ruleInfo.first);
103 rule->SetInfo(ruleInfo.second);
104 }
105 }
106 }
107 public override void Visit(ParserFile& parserFile)
108 {
109 for (const UniquePtr<GrammarParser>& parser : parserFile.Parsers())
110 {
111 parser->Accept(*this);
112 }
113 }
114 public override void Visit(Domain& domain)
115 {
116 this->domain = &domain;
117 stage = Stage.addParsers;
118 for (ParserFile* parserFile : domain.ParserFiles())
119 {
120 parserFile->Accept(*this);
121 }
122 stage = Stage.resolveRules;
123 for (ParserFile* parserFile : domain.ParserFiles())
124 {
125 parserFile->Accept(*this);
126 }
127 }
128 private Domain* domain;
129 private Stage stage;
130 private GrammarParser* currentParser;
131 private RuleParser* currentRule;
132 }
133 }