1 module ctpg.dsl.typed;
2 
3 import std.algorithm   : count;
4 import std.conv : to;
5 
6 import ctpg : parse;
7 import ctpg.parser_kind : ParserKind;
8 
9 import ctpg.dsl.typed.node : Node;
10 import ctpg.dsl.typed.parsers : defs;
11 
12 import ctpg.dsl.typed.visitors : applySkipLiteral, applyMemoizeSkip, applyMemoizeLiteral, applyMemoizeNonterminal, expandSkip, removeMemoizeDuplicates, removeSkipWithDuplicates, generate;
13 
14 import selflinoin : makeCompilationErrorMessage;
15 
16 
17 string generateParsers(string src, size_t line = __LINE__ , string file = __FILE__)
18 {
19     /+
20         パスの順番どうしよう?
21         生成オプションの中に「スキップをメモ化」ってのがあるから、生成オプション適応を先にやると、どれがスキップだかわからなくなって困る。
22             SKIPを置き換えるんじゃなくて残して、SKIPの下にスキップパーサを入れるみたいな構造なら、どれがスキップパーサか分かる。
23             それなら、別にapplyMemoizeSkipを先にやる必要はなくなる
24         うーん、単純にスキップをメモ化だけを単独で最初にやっちゃうって方法がいいかな
25         てか、それぞれの生成オプションごとに関数を用意してやるのがいいのかも知れない
26         てか、生成オプションの渡し方とかどうするんですかね・・・
27         うーん、オプションもDSLの中に書いてもらおうかなぁ・・・
28         結局、生成オプションごとに関数を作ることにした。オプションはDSL内に書いてもらう
29         古いctpgの実装だと、リテラルはskip!(memoize!(literal))ってなってるから、
30         適応の順番はskip->memoizeになる
31     +/
32     /+
33         applySetSkipする前と後のSKIPは別にするべきなのかどうかみたいな話
34         ・別にするべき
35             ・前と後で意味合いが変わる。同じだと紛らわしい
36             ・childrenにスキップパーサを追加する必要がある
37         ・同じにするべき
38             ・前と後で、同時に出ることはないから
39             ・別にすると名前空間が汚れる
40         これは、別の方がいいかも知れない
41         SKIPとSKIP_WITHにした。
42     +/
43     /+
44 
45     +/
46     immutable static staticImports =
47         "static import ctpg.is_wrapper;"
48         "static import ctpg.parsers;"
49         "static import ctpg.combinators;"
50         "static import ctpg.caller;"
51         "static import ctpg.input;"
52         "static import ctpg.parse_result;"
53         "static import ctpg.none;";
54 
55     auto parsed = src.parse!(defs, ParserKind!(true, true))(line, file);
56 
57     if(parsed.match)
58     {
59         Node code = parsed.value
60             .applySkipLiteral()
61             .applyMemoizeSkip(true)
62             .applyMemoizeLiteral(false)
63             .applyMemoizeNonterminal()
64             .expandSkip()
65             .removeMemoizeDuplicates()
66             .removeSkipWithDuplicates()
67         ;
68 
69         string generated = staticImports ~ code.generate();
70 
71         version(ctpgPrintGeneratedCode)
72         {
73             return generated ~ "pragma(msg, \"\n======== " ~ file ~ "(" ~ line.to!string ~ ") =========\n\n\"q{" ~ code.toString() ~ "}\"\n\n=====================\n\n\"q{" ~ generated ~ "});";
74         }
75         else
76         {
77             return generated;
78         }
79     }
80     else
81     {
82         return "pragma(msg,\"" ~ makeCompilationErrorMessage(parsed.error.msg, file, line + src[0 .. parsed.error.position].count('\n') + 1) ~ "\");static assert(false);";
83     }
84 }
85 
86 mixin template CTPG_DSL_TYPED(string src, size_t line = __LINE__ , string file = __FILE__)
87 {
88     static import ctpg.dsl.typed;
89     mixin(ctpg.dsl.typed.generateParsers(src, line, file));
90 }