root/lang/haxe/Tonyu2/Parser.hx @ 35669

Revision 35669, 4.6 kB (checked in by hoge1e3, 4 years ago)
RevLine 
[35663]1//using System;
2//using System.Collections.Generic;
3
4class ParseError  {
5    var message:String;
6        public function new(mesg:String){this.message=mesg;}
7}
[35664]8typedef ParserSub = Parser->Dynamic;
[35663]9//public delegate object ParserSub();
10//public delegate void VoidSub();
11class Parser {
12        var input:String;
[35664]13        var context:Dynamic;
[35663]14        var p:Int;
15        var maxErrorPos:Int;
16        static var space = ~/^\s*/;
17        public function new(input:String) {
18          this.input=input;
19          p=0;
20        }
21        public var rest(getRest,null):String;
22        function getRest():String {
[35664]23                return input.substr(p);
[35663]24        }
25        public function  proceed(by:Int):Int {return p+=by;}
[35664]26        public var eos(isEOS,null):Bool;
27        function isEOS():Bool {
28           return p>=rest.length;
[35663]29        }
30        var lastError:String;
31        public function raise(message:String) {
32           if (maxErrorPos<p) {
33                   maxErrorPos=p;
34                   lastError = traceStr(message);
35                }         
36                throw new ParseError(traceStr(message));
37        }
38        public function raiseSyntaxError() {
39                throw ("���@�G���[: "+maxErrorPos+" - "+p+" - "+lastError);
40        }
41        public function traceStr(message:String):String {
42           return " at "+p+"  /  "+message ;
43        }
44        /*public void trace(string message) {
45           System.Diagnostics.Debug.WriteLine(message);
46        }*/
47        public function saveState():Int {
48           return p;
49        }
50        public function restoreState(st:Int) {
51           p=st;
52        }
53        static function startsWith(s:String,head:String):Bool {
54            return s.substr(0,head.length)==head;
55        }
[35669]56        public function parse(m:Dynamic):Dynamic {
57                return toClosure(m)(this);
58        }
[35663]59        public function toClosure(match:Dynamic):ParserSub {
60           if (Reflect.isFunction(match) ) {
61                   //var p:ParserSub=match;
62                   return match;
63           } else if (Std.is(match ,String)) {
64                  var message:String=match+" expected";
65                  var m:String=match;
[35664]66                  return function(t:Parser) {
67                        if (startsWith(t.rest,m)) {
68                                t.proceed(m.length);
[35663]69                                return m;
70                        }
[35664]71                        t.raise(message);
[35663]72                        return null;
73                  };
74           } else if (Std.is(match , EReg)) {
[35664]75                  var message=Std.string(match)+" expected";
[35663]76                  var r:EReg=match;
[35664]77                  return function(t:Parser) {
78                        t.skipSpace();
79                        if (r.match(t.rest)) {
80                                if (r.matchedPos().pos>0) throw ("Invalid regex; it must start with ^ :"+r);
81                                t.proceed(r.matched(0).length);
[35663]82                                return r.matched(0);
83                        }
[35664]84                        t.raise(message);
[35663]85                        return null;
86                  };
87           }
88           throw ("Invalid match: "+match);
89        }
90        public function skipSpace() {
91                if (space.match(rest)) {
92                        proceed(space.matchedPos().len);
93                }
94        }
95
96        public function toClosures(seq:Array<Dynamic> ):Array<ParserSub> {
97           var res:Array<ParserSub>=[];
98           var s;
99           for (s in seq) {
100                  res.push(toClosure(s));
101           }
102           return res;
103        }
104        public function cache(name:String, sub:ParserSub ) {
105           trace("Parsing "+name);
[35664]106           return sub(this);
[35663]107        }
108                        //# combinator
109        public function seq(seq:Array<Dynamic>):ParserSub {
110                var cls= toClosures(seq);
[35664]111                return function(t:Parser) {
[35663]112                   var res=[];
[35664]113                   var r:ParserSub;
114                   for (r in cls) {
115                                res.push(r(t));
[35663]116                   }
117                   return res;
118                };
119        }
120        public function parseSeq(s:Array<Dynamic>):Array<Dynamic> {
[35664]121                return seq(s)(this);
[35663]122        }
[35664]123        public function tryThese(_:Array<Dynamic>):ParserSub {                 
[35663]124                var subs=toClosures(_);
[35664]125                return function (t:Parser) {
[35663]126                   var res=null;
[35664]127                   var trID=Std.random(10000);
[35663]128                   trace("Trying "+trID);
129                   var lastError:ParseError =null;
[35664]130                   var sub:ParserSub;
131                   for (sub in subs) {
132                          var st=t.saveState();
[35663]133                          lastError=null;
134                          try {
[35664]135                                 res=sub(t);
[35663]136                          } catch (p:ParseError) {
137                                lastError=p;
[35664]138                                t.restoreState(st);
[35663]139                          }
140                          if (lastError==null) {trace("Trial "+trID+" OK res="+res); return res;}
141                   }
142                   throw lastError;
143           };
144        }
145
146       
147        public function rept0(_:Array<Dynamic>):ParserSub  {
148           return reptN(0,1000,seq(_));
149        }
150
151        public function rept1(_:Array<Dynamic>):ParserSub  {
152           return reptN(1,1000,seq(_));
153        }
154        public function maybe(_:Array<Dynamic>):ParserSub {
[35664]155           return function (t:Parser) {
156                 var res: Array<Dynamic> = (t.reptN(0,1,t.seq(_)))(t);
[35663]157                 if (res.length==1) return res[0];
158                 return null;
159           };
160        }
161
[35664]162        public function reptN(min:Int , max:Int, sub:ParserSub):ParserSub  {
163           return function(t:Parser) {
[35663]164                 var res=[];
[35664]165                 while (res.length<max) {
[35663]166                        var suc=true;
[35664]167                        var fail=function(t:Parser){suc=false;return null;};
168                        var tres=(t.tryThese([sub, fail]))(t);
[35663]169                        if (suc) {
170                                res.push(tres);
171                        } else {
172                                break;
173                        }
174                 }
[35664]175                 if (res.length<min) {
176                        t.raise("only "+res.length+" time for ("+min+" - "+max+")");
177                }
178                 trace("repeated "+res.length+"("+min+" - "+max+")  OK, proceed");
[35663]179                 //#if ($cnt!=@res) {die("Why $cnt ".scalar(@res));}
180                 return res;
181           };
182        }
183       
184}
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
Note: See TracBrowser for help on using the browser.