2323import traceback
2424
2525from bison_ import ParserEngine
26+ from os import makedirs
27+
2628from .node import BisonNode
2729from .convert import bisonToPython
2830
31+
2932class BisonSyntaxError (Exception ):
3033 def __init__ (self , msg , args = []):
3134 super (BisonSyntaxError , self ).__init__ (msg )
@@ -34,6 +37,7 @@ def __init__(self, msg, args=[]):
3437 self .first_line , self .first_col , self .last_line , self .last_col , \
3538 self .message , self .token_value = args
3639
40+
3741class TimeoutError (Exception ):
3842 pass
3943
@@ -94,11 +98,14 @@ class BisonParser(object):
9498 # Default to sys.stdin.
9599 file = None
96100
101+ # Create a marker for input parsing.
102+ marker = 0
103+
97104 # Last parsed target, top of parse tree.
98105 last = None
99106
100107 # Enable this to keep all temporary engine build files.
101- keepfiles = 0
108+ keepfiles = 1
102109
103110 # Prefix of the shared object / dll file. Defaults to 'modulename-engine'.
104111 # If the module is executed directly, "__main__" will be used (since that
@@ -128,6 +135,9 @@ def __init__(self, **kw):
128135 - defaultNodeClass - the class to use for creating parse nodes, default
129136 is self.defaultNodeClass (in this base class, BisonNode)
130137 """
138+ self .buildDirectory = './pybison-' + type (self ).__name__ + '/'
139+ makedirs (self .buildDirectory , exist_ok = True )
140+
131141 # setup
132142 read = kw .get ('read' , None )
133143 if read :
@@ -195,7 +205,7 @@ def _handle(self, targetname, option, names, values):
195205 # % (targetname, repr(self.last)))
196206 else :
197207 if self .verbose :
198- print ('no handler for %s, using default' % targetname )
208+ print ('no handler for %s, using default' % targetname )
199209
200210 cls = self .default_node_class
201211 self .last = cls (target = targetname , option = option , names = names ,
@@ -208,6 +218,7 @@ def handle_timeout(self, signum, frame):
208218 raise TimeoutError ('Computation exceeded timeout limit.' )
209219
210220 def reset (self ):
221+ self .marker = 0
211222 self .engine .reset ()
212223
213224 def run (self , ** kw ):
@@ -223,11 +234,13 @@ def run(self, **kw):
223234 print ('Parser.run: calling engine' )
224235
225236 # grab keywords
237+ i_opened_a_file = False
226238 fileobj = kw .get ('file' , self .file )
227239 if isinstance (fileobj , str ):
228240 filename = fileobj
229241 try :
230242 fileobj = open (fileobj , 'rb' )
243+ i_opened_a_file = True
231244 except :
232245 raise Exception ('Cannot open input file "%s"' % fileobj )
233246 else :
@@ -248,15 +261,15 @@ def run(self, **kw):
248261 if read :
249262 self .read = read
250263
251- if self .verbose and self .file . closed :
252- print ('Parser.run(): self.file ' , self .file , 'is closed ' )
264+ if self .verbose and self .marker :
265+ print ('Parser.run(): self.marker ( ' , self .marker , ') is set ' )
253266
254267 error_count = 0
268+ self .last = None
255269
256270 # TODO: add option to fail on first error.
257- while not self .file . closed :
271+ while not self .marker :
258272 # do the parsing job, spew if error
259- self .last = None
260273 self .engine .reset ()
261274
262275 try :
@@ -275,7 +288,7 @@ def run(self, **kw):
275288 if hasattr (self , 'hook_run' ):
276289 self .last = self .hook_run (filename , self .last )
277290
278- if self .verbose and not self .file . closed :
291+ if self .verbose and not self .marker :
279292 print ('last:' , self .last )
280293
281294 if self .verbose :
@@ -284,10 +297,15 @@ def run(self, **kw):
284297 # restore old values
285298 self .file = oldfile
286299 self .read = oldread
300+ self .marker = 0
287301
288302 if self .verbose :
289303 print ('------------------ result=' , self .last )
290304
305+ # close the file if we opened one
306+ if i_opened_a_file and fileobj :
307+ fileobj .close ()
308+
291309 # TODO: return last result (see while loop):
292310 # return self.last[:-1]
293311 return self .last
@@ -305,13 +323,13 @@ def read(self, nbytes):
305323 if self .verbose :
306324 print ('Parser.read: want %s bytes' % nbytes )
307325
308- bytes = self .file .readline (nbytes )
326+ _bytes = self .file .readline (nbytes )
309327
310328 if self .verbose :
311- print ('Parser.read: got %s bytes' % len (bytes ))
312- print (bytes )
329+ print ('Parser.read: got %s bytes' % len (_bytes ))
330+ print (_bytes )
313331
314- return bytes
332+ return _bytes
315333
316334 def report_last_error (self , filename , error ):
317335 """
@@ -328,22 +346,22 @@ def report_last_error(self, filename, error):
328346
329347 """
330348
331- #if filename != None:
332- # msg = '%s:%d: "%s" near "%s"' \
333- # % ((filename,) + error)
349+ # if filename != None:
350+ # msg = '%s:%d: "%s" near "%s"' \
351+ # % ((filename,) + error)
334352
335- # if not self.interactive:
336- # raise BisonSyntaxError(msg)
353+ # if not self.interactive:
354+ # raise BisonSyntaxError(msg)
337355
338- # print >>sys.stderr, msg
339- #elif hasattr(error, '__getitem__') and isinstance(error[0], int):
340- # msg = 'Line %d: "%s" near "%s"' % error
356+ # print >>sys.stderr, msg
357+ # elif hasattr(error, '__getitem__') and isinstance(error[0], int):
358+ # msg = 'Line %d: "%s" near "%s"' % error
341359
342- # if not self.interactive:
343- # raise BisonSyntaxError(msg)
360+ # if not self.interactive:
361+ # raise BisonSyntaxError(msg)
344362
345- # print >>sys.stderr, msg
346- #else:
363+ # print >>sys.stderr, msg
364+ # else:
347365 if not self .interactive :
348366 raise
349367
@@ -352,8 +370,30 @@ def report_last_error(self, filename, error):
352370
353371 print ('ERROR:' , error )
354372
355- def report_syntax_error (self , msg , yytext , first_line , first_col ,
356- last_line , last_col ):
373+ def report_syntax_error (self , msg , yytext , first_line , first_col , last_line , last_col ):
374+
375+ def color_white (txt ):
376+ return "\033 [39m" + txt
377+
378+ def color_red (txt ):
379+ return "\033 [31m" + txt
380+
381+ def color_blue (txt ):
382+ return "\033 [34m" + txt
383+
384+ def make_bold (txt ):
385+ return "\033 [1m" + txt
386+
387+ def reset_style (txt ):
388+ return "\033 [0m" + txt
389+
357390 yytext = yytext .replace ('\n ' , '\\ n' )
358391 args = (msg , yytext , first_line , first_col , last_line , last_col )
359- raise BisonSyntaxError ('\033 [1m\033 [31mError:\033 [0m %s \n \t \033 [34m└ near \033 [1m"%s"\033 [0m\033 [34m (see \033 [39m\033 [1mline %d, pos %d to line %d, pos %d\033 [0m\033 [34m).\033 [0m' % args , args )
392+ err_msg = '' .join ([
393+ color_red (make_bold ("Error: " )), reset_style ("%s" ), "\n " , "\t " ,
394+ color_blue ("└ near " ), make_bold ('"%s"' ),
395+ reset_style (color_blue (" (see " )),
396+ color_white (make_bold ("line %d, pos %d to line %d, pos %d" )),
397+ reset_style (color_blue (")." )), reset_style ('' )
398+ ])
399+ raise BisonSyntaxError (err_msg % args , list (args ))
0 commit comments