root/trunk/dparser/tag/version_2/dparse.d

Revision 504, 28.1 kB (checked in by BCS, 5 years ago)

--

Line 
1 /******
2  * SEQUENCE
3  *   : ID ( '?' | '*' | '+' )? SEQUENCE
4  *   | ;
5  *
6  * CASE
7  *   : ID.action "/" SEQUENCE ;
8  *
9  * Options
10  *   : CASE ( '|' CASE )?;
11  *
12  * RULE
13  *   : ID.name ":" Options  ";" ;
14  *
15  * Grammar
16  *   : RULE Grammar
17  *   | ;
18  */
19 module dparse;
20
21 interface LexicalSource
22 {
23     ulong at();
24     void at(ulong);
25 }
26
27 interface IVector(T)
28 {
29     T[] Get();
30     uint Count();
31     char[] toString();
32 }
33
34 /+private+/ interface ICount // should be private
35 {
36     void Count(uint);
37 }
38 class Vector(T) : IVector!(T)
39 {
40     private T[] data;
41     static Vector!(T) opCall(V...)(V v)
42     {
43         auto ret = new Vector!(T);
44         int c;
45         foreach(int i,_;V)
46         {
47             static if(is(V[i] == T))
48                 c += 1;
49             else static if(is(V[i] : T[]))
50                 c += v[i].length;
51             else static if(is(V[i] : IVector!(T)))
52                 c += v[i].Count();
53             else static assert(false, "Expect some kinf of "~ T.stringof ~" can't deal with "~V[i].stringof);
54         }
55         ret.data.length = c;
56         c = 0;
57         foreach(int i,_;V)
58         {
59             static if(is(V[i] == T))
60             {
61                 ret.data[c] = v[i];
62                 c++;
63             }
64             else static if(is(V[i] == T[]))
65             {
66                 ret.data[c..c+v[i].length] = v[i];
67                 c += v[i].length;
68             }
69             else static if(is(V[i] == IVector!(T)))
70             {
71                 ret.data[c..c+v[i].Count()]  = v[i].Get();
72                 c += v[i].Count();
73             }
74             else static assert(false, "can't deal with "~V[i].stringof);
75         }
76         return ret;
77     }
78     T[] Get() { return data; }
79     uint Count() { return data.length; }
80     char[] toString()
81     {
82         return std.format.format("%s",data);
83     }
84 }
85
86 debug(dparse_test_parser_CT) debug = dparse_CT_Dump;
87
88
89 /// scan for f and return everything befor it, return null if not found
90 char[] ScanFor  (char[] str, char f) { foreach(int i, char c; str) if(c==f) return str[0..i];   return ""; }
91 /// scan for f and return everything befor it, return the input if not found
92 char[] NotAfter (char[] str, char f) { foreach(int i, char c; str) if(c==f) return str[0..i];   return str; }
93 /// return everythin after the firt f, null if not found
94 char[] ScanAfter(char[] str, char f) { foreach(int i, char c; str) if(c==f) return str[i+1..$]; return ""; }
95 /// return the index of the first f, or zero if not found
96  int   ScanForI (char[] str, char f) { foreach(int i, char c; str) if(c==f) return i;           return 0;  }
97 // return the input with leading or trailing whitespace removed.
98 char[] Trim     (char[] str)
99 {
100     foreach(int first, char f; str) if(f!=' ' && f!='\t' && f!='\r' && f!='\n')
101         foreach_reverse(int last, char l; str) if(l!=' ' && l!='\t' && l!='\r' && l!='\n')
102             return str[first..last+1];
103     return "";
104 }
105
106 char[] DropID(char[] str)
107 {
108     int i;
109     for(i = 0; i<str.length; i++)
110     {
111         char c = str[i];
112         if('0' <= c && c <= '9') continue;
113         if('_' == c) continue;
114         c = c | ('a'^'A');
115         if('a' <= c && c <= 'z') continue;
116         break;
117     }
118     if(i==str.length) return "";
119     assert(i != 0);
120
121     again: switch(str[i++])
122     {
123         case ' ', '\t', '\n', '\r':
124             if(i<str.length) goto again;
125             else             return str[i..$];
126
127         case '*', '?', '+':
128             return str[i..$];
129
130         default:
131             return str[i-1..$];
132     }
133 }
134 char[] ScanID(char[] str)
135 {
136     int i;
137     for(i = 0; i<str.length; i++)
138     {
139         char c = str[i];
140         if('0' <= c && c <= '9') continue;
141         if('_' == c) continue;
142         c = c | ('a'^'A');
143         if('a' <= c && c <= 'z') continue;
144         break;
145     }
146     if(i==str.length) return str;
147     if(i==0) return "";
148     int j = i;
149     again: switch(str[i++])
150     {
151         case ' ', '\t', '\n', '\r':
152             if(i<str.length) goto again;
153             else             return str[0..j];
154
155         case '*', '?', '+':
156             return str[0..j] ~ str[i-1];
157
158         default:
159             return str[0..j];
160     }
161 }
162
163 static assert("HelloWorld" == ScanID("HelloWorld"));
164 static assert("HelloWorld" == ScanID("HelloWorld   "));
165 static assert("HelloWorld" == ScanID("HelloWorld   Bob"));
166 static assert("Hello*" == ScanID("Hello*World   "));
167 static assert("HelloWorld+" == ScanID("HelloWorld   +*"));
168 static assert("HelloWorld*" == ScanID("HelloWorld   *Bob"));
169 static assert("Hello*" == ScanID("Hello* World   "));
170 static assert("" == ScanID("*Hello* World   "));
171 static assert("" == ScanID("$(bob, dillon) "));
172
173 template Tuple(T...) { alias T Tuple; }
174
175 template TupleSeq(uint i)
176 {
177     static if(i == 0)
178         alias Tuple!() TupleSeq;
179     else
180         alias Tuple!(TupleSeq!(i-1),i-1) TupleSeq;
181 }
182
183 enum ClauseType { One, ZeroOrOne, ZeroOrMore, OneOrMore }
184
185 struct Parse_Clause(char[] name)
186 {
187          static if(name[$-1] == '?') static const ClauseType Type = ClauseType.ZeroOrOne;
188     else static if(name[$-1] == '*') static const ClauseType Type = ClauseType.ZeroOrMore;
189     else static if(name[$-1] == '+') static const ClauseType Type = ClauseType.OneOrMore;
190     else  static const ClauseType Type = ClauseType.One;
191
192     static if(Type == ClauseType.One)
193     {
194         static const char[] Name = name;
195         debug(dparse_CT_Dump)static const char[] StringOf = name ~ '.';
196     }
197     else
198     {
199         static const char[] Name = name[0..$-1];
200         debug(dparse_CT_Dump)static const char[] StringOf = name;
201     }
202 }
203
204 struct Parse_Clauses(char[] file)
205 {
206     static if(file.length == 0)
207     {
208         debug(dparse_CT_Dump)static const char[] StringOf = "";
209         alias Tuple!() Clauses;
210     }
211     else
212     {
213         static assert(ScanID(file) != "", "Could not Parse a Clause out of \""~file~\");
214         alias Parse_Clause!(ScanID(file)) firstClause;
215         alias Parse_Clauses!(Trim(DropID(file))) otherClauses;
216         alias Tuple!(firstClause, otherClauses.Clauses) Clauses;
217         debug(dparse_CT_Dump)static const char[] StringOf = firstClause.StringOf ~ otherClauses.StringOf;
218     }
219 }
220
221 template Parse_Case(char[] file)
222 {
223     const bool Success = ScanForI(file,'/') != 0;
224
225     static if(Success)
226     {
227         const char[] Action = Trim(ScanFor(file,'/'));
228         alias Parse_Clauses!(Trim(ScanAfter(file,'/'))) Clauses;
229         debug(dparse_CT_Dump)const char[] StringOf = Action ~ "("~Clauses.StringOf ~")";
230     }
231     else
232     {
233         debug(dparse_CT_Dump)const char[] StringOf = "";
234     }
235 }
236
237 template Parse_Options(char[] file)
238 {
239     static if(file == null) const bool Success = false; else{
240     static if(ScanForI(file,'|'))
241     {
242         alias Parse_Case!(NotAfter(file,'|')) firstCase;
243         alias Parse_Options!(ScanAfter(file,'|')) otherCases;
244
245         static if(otherCases.Success)
246         {
247             alias Tuple!(firstCase,otherCases.Cases) Cases;
248             alias Tuple!(firstCase.Action,otherCases.ActionNames) ActionNames;
249             debug(dparse_CT_Dump)const char[] StringOf = firstCase.StringOf~" | "~otherCases.StringOf;
250         }
251         else
252         {
253             static assert(Trim(ScanFor(file,'|')).length == 0 , "Found \""~Trim(ScanAfter(file,'|'))~"\" could not parse as Cases");
254             alias Tuple!(firstCase) Cases;
255             alias Tuple!(firstCase.Action) ActionNames;
256             debug(dparse_CT_Dump)const char[] StringOf = firstCase.StringOf;
257         }
258         const bool Success = firstCase.Success;
259     }
260     else
261     {
262         alias Parse_Case!(file) firstCase;
263         alias Tuple!(firstCase) Cases;
264         alias Tuple!(firstCase.Action) ActionNames;
265         debug(dparse_CT_Dump)const char[] StringOf = firstCase.StringOf;
266         const bool Success = firstCase.Success;
267     }}
268
269     template hasALeftH(char[] name, T...)
270     {
271         static if(T.length == 0)                            const bool hasALeftH = false;
272         else static if(T[0].Clauses.Clauses.length == 0)    const bool hasALeftH = hasALeftH!(name,T[1..$]);
273         else static if(T[0].Clauses.Clauses[0].Name != name)const bool hasALeftH = hasALeftH!(name,T[1..$]);
274         else                                                const bool hasALeftH = true;
275     }
276     static if(Success) template hasALeft(char[] name) { const bool hasALeft = hasALeftH!(name,Cases); }
277
278     debug(dparse_CT_Dump)static if(!is(typeof(StringOf))) const char[] StringOf = "x";
279 }
280
281 template Parse_Rule(char[] file)
282 {
283     static if(file.length == 0 || ScanForI(file,':') == 0)
284     {
285         const bool Success = false;
286         debug(dparse_CT_Dump)const char[] StringOf = null;
287     }
288     else
289     {
290         const char[] Name = Trim(ScanFor(file,':'));
291         alias Parse_Options!(Trim(ScanAfter(file,':'))) Options;
292         const bool Success = Options.Success;
293         debug(dparse_CT_Dump)const char[] StringOf = Name ~ "{" ~ Options.StringOf~ "}";
294
295         const bool IsLeftRec = Options.hasALeft!(Name);;
296         alias Options.ActionNames ActionNames;
297     }
298 }
299
300 template Parse_Grammar(char[] file)
301 {
302     alias Parse_Rule!(Trim(ScanFor(file,';'))) firstRule;
303
304     const bool Success = firstRule.Success;
305     static assert(Success || Trim(file).length == 0, "Found \""~file[0..($>20?20:$)]~"\" could not parse as a rule");
306
307     static if(Success)
308     {
309         alias Parse_Grammar!(Trim(ScanAfter(file,';'))) otherRules;
310         static if(otherRules.Success)
311         {
312             debug(dparse_CT_Dump)const char[] StringOf = "[ " ~ firstRule.StringOf ~ ", " ~ otherRules.StringOf[1..$-2] ~ " ]";
313             alias Tuple!(firstRule, otherRules.Rules) Rules;
314         }
315         else
316         {
317             debug(dparse_CT_Dump)const char[] StringOf = "[ " ~ firstRule.StringOf ~ " ]";
318             alias firstRule Rules;
319         }
320
321         template select(char[] str)
322         {
323             static if(firstRule.Name == str)
324                 alias firstRule select;
325             else static if(otherRules.Success)
326                 alias otherRules.select!(str) select;
327             else
328                 static assert(false,"Grammar does not define "~str);
329         }
330
331         template has(char[] str)
332         {
333             static if(firstRule.Name == str)
334                 static const bool has = true;
335             else static if(otherRules.Success)
336                 static const bool has = otherRules.has!(str);
337             else
338                 static const bool has = false;
339         }
340
341         template nameset()
342         {
343             static if(otherRules.Success)
344                 alias Tuple!(firstRule.Name,  otherRules.nameset!()) nameset;
345             else
346                 alias Tuple!(firstRule.Name) nameset;
347         }
348     }
349     else
350     {
351         debug(dparse_CT_Dump)const char[] StringOf = "[]";
352     }
353 }
354
355 debug(dparse_test_parser_CT)
356 {
357     alias Parse_Grammar!("hello:$(yo) / bob?;world: wow /   man? of+ war| wow/guy*steel; ") parsed;
358     pragma(msg, parsed.StringOf);
359     pragma(msg, parsed.select!("world").StringOf);
360 }
361
362 /******************************************************************************
363  * Extract the first Class type from the input tuple
364  */
365 template ExtractClass(Types...)
366 {
367     static if(Types.length > 0)
368     {
369         static if(is(Types[0] P == class)) alias P ExtractClass;
370         else      alias ExtractClass!(Types[1..$]) ExtractClass;
371     }
372     else static assert(false);
373 }
374
375 /******************************************************************************
376  * Return the base class of The given type
377  */
378 template BaseClass(Type)
379 {
380     static if(is(Type _ == class) && !is(_ == Object) && is(Type BaseT == super))
381         alias ExtractClass!(BaseT) BaseClass;
382     else static assert(false);
383 }
384
385 /******************************************************************************
386  * Return the Closest Common Type of the 2 given types
387  */
388 template CCT2(Type,U)
389 {
390     //pragma(msg, \t~Type.stringof ~" / "~U.stringof);
391     static if (is(Type : U))      alias U CCT2;
392     else static if (is(U : Type)) alias Type CCT2;
393     else static if(is(Type _ == class) && is(U __ == class))
394         alias CCT2!(BaseClass!(Type),U) CCT2;
395     else
396         static assert(false,"Cant find common type for "~Type.stringof~" and "~U.stringof);
397 }
398
399 /******************************************************************************
400  * return the closest common type of the Type tuple
401  */
402 template CCT(Types...)
403 {
404     //pragma(msg, ">>"~Types.stringof);
405     static if(Types.length > 1)
406         alias CCT!(CCT2!(Types[0..2]), Types[2..$]) CCT;
407     else static if(Types.length == 1)
408         alias Types[0] CCT;
409     else static assert(false);
410     //pragma(msg, "<<"~CCT.stringof);
411 }
412
413 private struct CCT_UnitTest
414 {
415     interface I {}
416     class A {}
417     class B : A, I {}
418     class C : A {}
419     class E : B {}
420     class F : B {}
421
422     static assert(is(CCT!(A, B) == A));
423     static assert(is(CCT!(B, C) == A));
424     static assert(is(CCT!(C, E) == A));
425     static assert(is(CCT!(E, F) == B));
426 }
427
428
429 template TypeOfProduction(alias SubItem,Base, char[] name)
430 {
431     alias SubItem!(Base,name).Parse getter;
432     static if(is(typeof(getter) R == return))
433     {
434         alias R T;
435         //pragma(msg,name ~ " returns " ~ R.stringof);
436     }
437     else
438         static assert(false, "failed to resolve type for "~name);
439 }
440
441 /// test what type an action returns
442 template ActionReturns(alias Action, char[] action)
443 {
444     static if(is(typeof(Action!(action).Act) R == return))
445     {
446         alias R ActionReturns;
447         debug(dparse_trace_CT) pragma(msg,action ~ " returns " ~ R.stringof);
448     }
449     else
450     {
451         alias typeof(Action!(action).Act) ActionReturns;
452         debug(dparse_trace_CT) pragma(msg,action ~ " is a " ~ ActionReturns.stringof);
453     }
454     static assert(is(typeof((cast(ActionReturns)null) is null)), NotAfter(Action.stringof,'(')~"!(\""~action~"\").Act resulted in a "~ActionReturns.stringof~" and can't be converted to null");
455 }
456
457 /// derive the return type of a production with cases using the given Actions
458 template ProductionReturns(alias Action, Actions...)
459 {
460     static assert(Actions.length > 0);
461     static if(Actions.length == 1)  alias ActionReturns!(Action,Actions[0]) ProductionReturns;
462     else                            alias CCT2!(ActionReturns!(Action,Actions[0]), ProductionReturns!(Action,Actions[1..$])) ProductionReturns;
463 }
464
465 class VariableCount(T) : IVector!(T), ICount
466 {
467     private T[] data;   // the data
468     private uint at;    // one more than the size of data in data. Zero == fixed
469
470     this()
471     {
472         data.length = 4;
473         at = 1;
474     }
475         /// add another
476     private void Add(T t)
477     {
478         if(!at) throw new Error("Can't add to fixed Vector");
479         if(data.length <= at-1) data.length = at*2;
480         data[at-1] = t;
481         at++;
482     }
483         ///
484     void Fix()
485     {
486         if(at) data.length = at-1;
487         at = 0;
488     }
489     T[] Get()
490     {
491         Fix();
492         return data;
493     }
494     uint Count()
495     {
496         return at ? at-1 : data.length;
497     }
498     void Count(uint a)
499     {
500         assert(at==0 && a <= data.length); data.length = a;
501     }
502     char[] toString()
503     {
504         return std.format.format("%s",data[0..at?at-1:$]);
505     }
506 }
507
508
509 struct Stack(T)
510 {
511     T[] data;
512     uint at = 0;
513
514     void Push(T t)
515     {
516         if(data.length <= at) data.length = (at+8)*2;
517         data[at++] = t;
518     }
519     T Peek() { return data[at]; }
520     T Pop() { return data[--at]; }
521     bool Empty(){return at==0; }
522 }
523 unittest
524 {
525     Stack!(int) st;
526     st.Push = 5;
527     st.Push = 6;
528     assert(st.Pop == 6);
529     assert(st.Pop == 5);
530 }
531
532 struct Frame { int item; uint depth; ulong at; }
533
534 ///
535 struct dparse(alias Action, alias SubItem, LexSource, char[] Grammar)
536 {
537     /// Parse the grammar
538     alias Parse_Grammar!(Grammar) GrammarAST;
539
540     template ActionReturnType(Action)
541     {
542             static if(Action.Type == ClauseType.One)
543             {
544                 alias TypeOfProduction!(SubItem,typeof(*this),Action.Name).T ActionReturnType;
545                 debug(dparse_trace_CT) pragma(msg, Action.Name~"= "~ActionReturnType.stringof);
546             }
547             else
548             {
549                 alias IVector!(TypeOfProduction!(SubItem,typeof(*this),Action.Name).T) ActionReturnType;
550                 debug(dparse_trace_CT) pragma(msg, Action.Name ~ "?*+ "~ActionReturnType.stringof);
551             }
552     }
553
554     template ActionReturnTypes(Action...)
555     {
556         static if(Action.length == 0) alias Tuple!() ActionReturnTypes;
557         static if(Action.length == 1) alias Tuple!(ActionReturnType!(Action[0])) ActionReturnTypes;
558         static if(Action.length >  1) alias Tuple!(ActionReturnType!(Action[0]), ActionReturnTypes!(Action[1..$])) ActionReturnTypes;
559     }
560
561     static TypeOfProduction!(SubItem,typeof(*this),name).T ParseOne       (char[] name)(ref Stack!(Frame) stack, int i,LexSource source)
562     {
563         debug(dparse_trace_CT) pragma(msg, "\t= "~name);
564         return SubItem!(typeof(*this),name).Parse(source);
565     }
566     static VariableCount!(TypeOfProduction!(SubItem,typeof(*this),name).T) ParseZeroOrOne (char[] name)(ref Stack!(Frame) stack, int i,LexSource source)
567     {
568         debug(dparse_trace_CT) pragma(msg, "\t? "~name);
569         Frame frame;
570         frame.item = i;
571         TypeOfProduction!(SubItem,typeof(*this),name).T tmp;
572         VariableCount!(typeof(tmp)) ret = new VariableCount!(typeof(tmp));
573
574         frame.at = source.at;
575         frame.depth = ret.Count;
576         tmp = SubItem!(typeof(*this),name).Parse(source);
577         if(tmp !is null)
578         {
579             stack.Push(frame);
580             ret.Add(tmp);
581         }
582         ret.Fix();
583         return ret;
584     }
585     static VariableCount!(TypeOfProduction!(SubItem,typeof(*this),name).T) ParseZeroOrMore(char[] name)(ref Stack!(Frame) stack, int i,LexSource source)
586     {
587         debug(dparse_trace_CT) pragma(msg, "\t* "~name);
588         Frame frame;
589         frame.item = i;
590         TypeOfProduction!(SubItem,typeof(*this),name).T tmp;
591         auto ret = new VariableCount!(typeof(tmp));
592
593         frame.at = source.at;
594         frame.depth = ret.Count;
595         while(null !is (tmp = SubItem!(typeof(*this),name).Parse(source)))
596         {
597             stack.Push(frame); // push befor each location
598
599             ret.Add(tmp);
600             frame.at = source.at;
601             frame.depth = ret.Count;
602         }
603
604         ret.Fix();
605         return ret;
606     }
607     static VariableCount!(TypeOfProduction!(SubItem,typeof(*this),name).T) ParseOneOrMore (char[] name)(ref Stack!(Frame) stack, int i,LexSource source)
608     {
609         debug(dparse_trace_CT) pragma(msg, "\t+ "~name);
610         Frame frame;
611         frame.item = i;
612         TypeOfProduction!(SubItem,typeof(*this),name).T tmp;
613         auto ret = new VariableCount!(typeof(tmp));
614
615         while(null !is (tmp = SubItem!(typeof(*this),name).Parse(source)))
616         {
617             frame.at = source.at;   // push after each location
618             frame.depth = ret.Count;
619             stack.Push(frame);
620
621             ret.Add(tmp);
622         }
623
624         if(tmp is null) return null;
625
626         stack.Pop;  // the last one is at thes position so discard it.
627         ret.Fix();
628         return ret;
629     }
630
631     enum Places { Start = -1, Abort = -2 };
632
633     static ActionReturns!(Action,ActionName) TryParseOption(char[] ActionName, alias Clauses)(LexSource source)
634     {
635         Stack!(Frame) stack;
636         Frame stackFrame;
637
638         stackFrame.item = Places.Abort;
639         stack.Push(stackFrame);
640
641         stackFrame.item = Places.Start;
642         stackFrame.at = source.at;
643         stack.Push(stackFrame);
644
645         //alias ActionReturnTypes!(Clauses.Clauses) StorageTypes;// pragma(msg, "StorageTypes: "~StorageTypes.stringof);
646         ActionReturnTypes!(Clauses.Clauses) clauseResults;
647         static assert(clauseResults.length == Clauses.Clauses.length);
648
649         again: stackFrame = stack.Pop;
650         bool back = true;
651         switch(stackFrame.item)
652         {
653             case Places.Abort:
654                 debug(dparse_trace_RT)writef("%s:%d %s <failed\n",__FILE__,__LINE__, Clauses.Clauses.stringof);
655                 return null;
656
657             case Places.Start:
658
659             back=false;
660             foreach(int i, clause; Clauses.Clauses)
661             {
662                 //pragma(msg, typeof(clauseResults[i]).stringof ~ " "~clause.Name);     // <- fails
663                 debug(dparse_trace_CT) pragma(msg, ActionReturnTypes!(Clauses.Clauses)[i].stringof ~ " "~clause.Name);
664
665                 static if(clause.Type == ClauseType.One)        if(null is (clauseResults[i] = ParseOne       !(clause.Name)(stack,i,source))) goto again;
666                 static if(clause.Type == ClauseType.ZeroOrOne)  if(null is (clauseResults[i] = ParseZeroOrOne !(clause.Name)(stack,i,source))) goto again;
667                 static if(clause.Type == ClauseType.ZeroOrMore) if(null is (clauseResults[i] = ParseZeroOrMore!(clause.Name)(stack,i,source))) goto again;
668                 static if(clause.Type == ClauseType.OneOrMore)  if(null is (clauseResults[i] = ParseOneOrMore !(clause.Name)(stack,i,source))) goto again;
669
670                 case i:;
671                 if(back)
672                 {
673                     source.at=stackFrame.at;
674                     static if(clause.Type != ClauseType.One)
675                     {
676                         //(cast(VariableCount!(ActionReturnTypes!(Clauses.Clauses)[i].Base))clauseResults[i]).Count = stackFrame.depth;
677                         (cast(ICount)clauseResults[i]).Count = stackFrame.depth;
678                     }
679                 }
680             }
681         }
682         debug(dparse_trace_RT)writef("%s:%d Action %s\n",__FILE__,__LINE__, ActionName);
683         static if(is(typeof(Action!(ActionName).Act) == return))
684             return Action!(ActionName).Act(clauseResults);
685         else
686             return Action!(ActionName).Act;
687     }
688
689     /// abstracts a function that parses the production named
690     template TryParseProduction(char[] name)
691     {
692         alias GrammarAST.select!(name) Production;
693         static if(Production.IsLeftRec)
694         {
695             static assert(false, name ~ " is directly Left Recursive (try again later)");
696         }
697         else
698         {
699             //pragma(msg, name ~ " is not directly Left Recursive");
700             //pragma(msg, Production.ActionNames);
701             alias ProductionReturns!(Action,Production.ActionNames) R;
702             static R Go(LexSource source)
703             {
704                 R ret;
705                 alias Production.Options.Cases Cases;
706                 static const int j = Cases.length;
707                 foreach(i; TupleSeq!(j))            //////// <--- HACK b/c foreach isn't working on the tuple
708                 {
709                     alias Tuple!(Cases[i].Clauses) clauses;
710                     debug(dparse_trace_CT) pragma(msg, name ~ " invloking " ~ clauses.stringof);
711                     ret = TryParseOption!(Cases[i].Action,Cases[i].Clauses)(source);
712                     if(null !is ret) break;
713                 }
714                 debug(dparse_trace_RT)writef("%s:%d %s %s\n",__FILE__,__LINE__, name, ret !is null);
715                 return ret;
716             }
717         }
718     }
719
720     static char[] GenMixin()
721     {
722         static const char[]
723             Prefix = "alias TryParseProduction!(\"",
724             Infix  = "\").Go\tParse_",
725             Suffix = ";\n";
726
727         static const int Overhead = Prefix.length + Infix.length + Suffix.length;
728        
729         alias GrammarAST.nameset!() set;
730
731         static const int i = set.stringof[5..$-1].length*2 + (Overhead-3)*set.length;
732         char[] ret;
733         foreach(name;set)
734         {
735             ret ~= Prefix;
736             ret ~= name;
737             ret ~= Infix;
738             ret ~= name;
739             ret ~= Suffix;
740         }
741         return ret;
742     }
743     debug(dparse_Mixin) pragma(msg, GenMixin());
744     mixin(GenMixin());
745 }
746
747
748 debug(dparse_test_parser_RT)
749 {
750     const char[] gram =
751     "GRAMMAR"
752         ":EchoOneR/RULE*"
753         ";"
754
755     "RULE"
756         ":MakeRule/ID Collon OPTIONS SemiCollon"
757         ";"
758
759     "OPTIONS"
760         ":AcumulateSkip/CASE NEXT*"
761         ";"
762
763     "NEXT"
764         ":EchoTwo/Pipe CASE"
765         ";"
766
767     "CASE"
768         ":MakeCase/ID Slash IDP*"
769         ";"
770
771     "IDP"
772         ":MakeID/ID SUFFIX?"
773         ";"
774
775     "SUFFIX"
776         ":EchoOneC/QMark"
777         "|EchoOneC/Star"
778         "|EchoOneC/Plus"
779         ";"
780     ;
781
782 template Foo(char[] str)
783 {
784          static if(str[1] == '0')   {Ret function() Act; static this(){ Act =  function Ret(){return new Ret();}; } }
785     else static if(str[1] == '1')   {Ret function(Ret) Act; static this(){ Act =  function Ret(Ret){return new Ret();}; } }
786     else static if(str[1] == '2')   {Ret function(Ret,Ret) Act; static this(){ Act =  function Ret(Ret,Ret){return new Ret();}; } }
787     else static if(str == "x3")     {Ret function(Ret,Ret,Ret) Act; static this(){ Act =  function Ret(Ret,Ret,Ret){return new Ret();}; } }
788     else static if(str == "y3")     {Ret function(Ret,IVector!(Ret),Ret) Act; static this(){ Act =  function Ret(Ret,IVector!(Ret),Ret){return new Ret();}; } }
789     else static if(str[1] == '4')   {Ret function(Ret,Ret,Ret,Ret) Act; static this(){ Act =  function Ret(Ret,Ret,Ret,Ret){return new Ret();}; } }
790     else
791     static assert(false);
792 }
793
794 class Rule
795 {
796     char[] name; Case[] cases;
797     this(char[]n,IVector!(Case)c) {name=n;cases=c.Get;}
798     char[] toString(){return std.format.format("%s:%s;",name,cases);}
799 }
800 class ID
801 {
802     char[] name; char type;
803     this(char[]n,IVector!(char[])t){name=n; type=t.Count?t.Get[0][0]:'.';}
804     char[] toString(){return name~type;}
805 }
806 class Case
807 {
808     char[] act; ID[] clauses;
809     this(char[]a,IVector!(ID)c){act=a;clauses=c.Get;}
810     char[] toString(){return std.format.format("%s/%s", act,clauses);}
811 }
812 template DPaprseGrammarAction(char[] str)
813 {
814     //pragma(msg, str);
815     static if(false){}
816     else static if(str == "AcumulateSkip")  IVector!(Case) Act(Case r,IVector!(Case) R)
817         {debug(dparse_trace_RT)writef(\t~str~\n);return Vector!(Case)(r,R);}
818
819     else static if(str == "MakeRule")       Rule Act(char[] n,char[],IVector!(Case) c,char[])
820         {debug(dparse_trace_RT)writef(\t~str~\n);return new Rule(n,c);}
821     else static if(str == "MakeID")         ID   Act(char[] n, IVector!(char[]) t)
822         {debug(dparse_trace_RT)writef(\t~str~\n);return new ID(n,t);}
823     else static if(str == "MakeCase")       Case Act(char[] a,char[],IVector!(ID) c)
824         {debug(dparse_trace_RT)writef(\t~str~\n);return new Case(a,c);}
825
826     else static if(str == "EchoTwo")        Case Act(char[],Case t)
827         {debug(dparse_trace_RT)writef(\t~str~\n);return t;}
828     else static if(str == "EchoOneC")       char[] Act(char[] t)
829         {debug(dparse_trace_RT)writef(\t~str~\n);return t;}
830     else static if(str == "EchoOneR")       IVector!(Rule) Act(IVector!(Rule) t)
831         {debug(dparse_trace_RT)writef(\t~str~\n);return t;}
832
833     else static assert(false, "No rule for "~str);
834 }
835
836 class DPaprseLexicalSource
837 {
838     char[] data;
839     ulong at;
840     void X(){ while(at<data.length && data[at] == ' ')at++; }
841     char It(){return at<data.length ? data[at] : '-'; }
842     char[] Lex_Collon()     { X; debug(dparse_trace_RT)writef("Lex.Collon %s\n",It);     if(data.length > at && data[at] == ':') return data[at++..$][0..1]; debug(dparse_trace_RT)writef("failed\n"); return null; }
843     char[] Lex_SemiCollon() { X; debug(dparse_trace_RT)writef("Lex.SemiCollon %s\n",It); if(data.length > at && data[at] == ';') return data[at++..$][0..1]; debug(dparse_trace_RT)writef("failed\n"); return null; }
844     char[] Lex_Pipe()       { X; debug(dparse_trace_RT)writef("Lex.Pipe %s\n",It);       if(data.length > at && data[at] == '|') return data[at++..$][0..1]; debug(dparse_trace_RT)writef("failed\n"); return null; }
845     char[] Lex_Slash()      { X; debug(dparse_trace_RT)writef("Lex.Slash %s\n",It);      if(data.length > at && data[at] == '/') return data[at++..$][0..1]; debug(dparse_trace_RT)writef("failed\n"); return null; }
846     char[] Lex_QMark()      { X; debug(dparse_trace_RT)writef("Lex.QMark %s\n",It);      if(data.length > at && data[at] == '?') return data[at++..$][0..1]; debug(dparse_trace_RT)writef("failed\n"); return null; }
847     char[] Lex_Star()       { X; debug(dparse_trace_RT)writef("Lex.Star %s\n",It);       if(data.length > at && data[at] == '*') return data[at++..$][0..1]; debug(dparse_trace_RT)writef("failed\n"); return null; }
848     char[] Lex_Plus()       { X; debug(dparse_trace_RT)writef("Lex.Plus %s\n",It);       if(data.length > at && data[at] == '+') return data[at++..$][0..1]; debug(dparse_trace_RT)writef("failed\n"); return null; }
849     char[] Lex_ID()
850     {
851         X;
852         debug(dparse_trace_RT)writef("Lex.ID\n");
853         foreach(int i, char c; data[at..$])
854             switch(c)
855             {
856                 default:
857                     if(i == 0) return null;
858                     auto ret = data[at..at+i];
859                     at += i;
860                     debug(dparse_trace_RT)writef("\"%s\"\n", ret);
861                     return ret;
862                 case '0','1','2','3','4','5','6','7','8','9','q','w','e','r',
863                      't','y','u','i','o','p','l','k','j','h','g','f','d','s',
864                      'a','z','x','c','v','b','n','m','Q','W','E','R','T','Y',
865                      'U','I','O','P','L','K','J','H','G','F','D','S','A','Z',
866                      'X','C','V','B','N','M','_':
867                      continue;
868             }
869         debug(dparse_trace_RT)writef("%s\n", data.length != 0);
870         return data;
871     }
872 }
873
874 template DPaprseRuleCall(Base, char[] name)
875 {
876     //pragma(msg,"Doing Name");
877     static if(name == "") static assert(false);
878     else static if(name == "ID")         char[] Parse(DPaprseLexicalSource source) {debug(dparse_trace_RT)writef("Sub:%s\n",name);return source.Lex_ID;}
879     else static if(name == "Collon")     char[] Parse(DPaprseLexicalSource source) {debug(dparse_trace_RT)writef("Sub:%s\n",name);return source.Lex_Collon;}
880     else static if(name == "SemiCollon") char[] Parse(DPaprseLexicalSource source) {debug(dparse_trace_RT)writef("Sub:%s\n",name);return source.Lex_SemiCollon;}
881     else static if(name == "Pipe")       char[] Parse(DPaprseLexicalSource source) {debug(dparse_trace_RT)writef("Sub:%s\n",name);return source.Lex_Pipe;}
882     else static if(name == "Slash")      char[] Parse(DPaprseLexicalSource source) {debug(dparse_trace_RT)writef("Sub:%s\n",name);return source.Lex_Slash;}
883     else static if(name == "QMark")      char[] Parse(DPaprseLexicalSource source) {debug(dparse_trace_RT)writef("Sub:%s\n",name);return source.Lex_QMark;}
884     else static if(name == "Star")       char[] Parse(DPaprseLexicalSource source) {debug(dparse_trace_RT)writef("Sub:%s\n",name);return source.Lex_Star;}
885     else static if(name == "Plus")       char[] Parse(DPaprseLexicalSource source) {debug(dparse_trace_RT)writef("Sub:%s\n",name);return source.Lex_Plus;}
886     else
887     {
888         debug(dparse_trace_RT)
889         {
890             typeof(mixin("Base.Parse_"~name))* Parse;
891             static this()
892             {
893                 Parse = function(DPaprseLexicalSource source)
894                 {
895                     writef("Call:%s\n",name);
896                     auto ret = mixin("Base.Parse_"~name~"(source)");
897                     writef("Call:%s <%s\n",name,ret !is null);
898                     return ret;
899                 };
900             }
901         }
902         else
903             mixin("alias Base.Parse_"~name~" Parse;");
904     }
905 }
906
907 //  alias dparse!(Foo,Sub,LexicalSource,gram) parserA;
908     alias dparse!(DPaprseGrammarAction,DPaprseRuleCall,DPaprseLexicalSource,gram) parserB;
909
910     import std.stdio;
911     void main()
912     {
913         auto source = new DPaprseLexicalSource;
914         source.data = gram.dup;
915
916         writef("%s\n",source.data);
917         auto a = parserB.Parse_GRAMMAR(source);
918         if(a !is null)
919 /+          foreach(int i, Rule r; a)
920             {
921                 if(r is null)
922                     writef("%d is null\n", i);
923                 else
924                     writef("%s\n",r.toString());
925             }+/
926             writef("%s\n",a.toString());
927         else
928             writef("null\n");
929     }
930 }
Note: See TracBrowser for help on using the browser.