@@ -157,9 +157,18 @@ class Tokenizer(object):
157
157
def __init__ (self , handle , interactive = False ):
158
158
if not interactive :
159
159
# reads char-by-char
160
- self .reader = itertools .chain .from_iterable (handle )
160
+ if __debug__ :
161
+ self .reader = self .char_iterator (handle )
162
+ self .__col_cnt = 0
163
+ self .__row_cnt = 0
164
+ else :
165
+ self .reader = itertools .chain .from_iterable (handle )
166
+ self .__col_cnt = None
167
+ self .__row_cnt = None
161
168
else :
162
169
self .reader = interactive_char_iterator (handle )
170
+ self .__col_cnt = None
171
+ self .__row_cnt = None
163
172
self .generator = self .create_generator (self .reader )
164
173
self .extra_queue = []
165
174
self .consume = self .consume_token
@@ -181,6 +190,12 @@ def consume_token(self):
181
190
def raw_read (self ):
182
191
return next (self .reader )
183
192
193
+ @property
194
+ def pos_info (self ):
195
+ if self .__row_cnt is not None :
196
+ return (self .__row_cnt , self .__col_cnt )
197
+ return None
198
+
184
199
@staticmethod
185
200
def create_generator (reader ):
186
201
"""Takes a file-like object and produces a stream of tokens following
@@ -210,13 +225,14 @@ def create_generator(reader):
210
225
c = next (reader )
211
226
if c != "|" and c != "\\ " :
212
227
# Only \| and \\ are supported escapings
213
- raise PysmtSyntaxError ("Unknown escaping in " \
214
- " quoted symbol: "
215
- "'\\ %s'" % c )
228
+ raise PysmtSyntaxError (
229
+ "Unknown escaping in quoted symbol: "
230
+ "'\\ %s'" % c , reader . pos_info )
216
231
s .append (c )
217
232
c = next (reader )
218
233
if not c :
219
- raise PysmtSyntaxError ("Expected '|'" )
234
+ raise PysmtSyntaxError ("Expected '|'" ,
235
+ reader .pos_info )
220
236
yield "" .join (s )
221
237
c = next (reader )
222
238
@@ -236,7 +252,8 @@ def create_generator(reader):
236
252
s .append (c )
237
253
c = next (reader )
238
254
if not c :
239
- raise PysmtSyntaxError ("Expected '|'" )
255
+ raise PysmtSyntaxError ("Expected '|'" ,
256
+ reader .pos_info )
240
257
yield '"%s"' % ("" .join (s )) # string literals maintain their quoting
241
258
242
259
else :
@@ -259,6 +276,20 @@ def create_generator(reader):
259
276
c = next (reader )
260
277
yield "" .join (tk )
261
278
279
+ def char_iterator (self , handle ):
280
+ c = handle .read (1 )
281
+ while c :
282
+ if c == "\n " :
283
+ self .__row_cnt += 1
284
+ self .__col_cnt = 0
285
+ elif c == "\r " :
286
+ pass
287
+ else :
288
+ self .__col_cnt += 1
289
+ yield c
290
+ c = handle .read (1 )
291
+
292
+
262
293
# EOC Tokenizer
263
294
264
295
@@ -449,7 +480,8 @@ def _enter_smtlib_as(self, stack, tokens, key):
449
480
#pylint: disable=unused-argument
450
481
const = self .parse_atom (tokens , "expression" )
451
482
if const != "const" :
452
- raise PysmtSyntaxError ("expected 'const' in expression after 'as'" )
483
+ raise PysmtSyntaxError ("expected 'const' in expression after 'as'" ,
484
+ tokens .pos_info )
453
485
ty = self .parse_type (tokens , "expression" )
454
486
455
487
def res (expr ):
@@ -474,7 +506,7 @@ def _smtlib_underscore(self, stack, tokens, key):
474
506
end = int (send )
475
507
except ValueError :
476
508
raise PysmtSyntaxError ("Expected number in '_ extract' "
477
- "expression" )
509
+ "expression" , tokens . pos_info )
478
510
fun = lambda x : mgr .BVExtract (x , start , end )
479
511
480
512
elif op == "zero_extend" :
@@ -483,7 +515,7 @@ def _smtlib_underscore(self, stack, tokens, key):
483
515
width = int (swidth )
484
516
except ValueError :
485
517
raise PysmtSyntaxError ("Expected number in '_ zero_extend' "
486
- "expression" )
518
+ "expression" , tokens . pos_info )
487
519
fun = lambda x : mgr .BVZExt (x , width )
488
520
489
521
elif op == "repeat" :
@@ -492,7 +524,7 @@ def _smtlib_underscore(self, stack, tokens, key):
492
524
count = int (scount )
493
525
except ValueError :
494
526
raise PysmtSyntaxError ("Expected number in '_ repeat' "
495
- "expression" )
527
+ "expression" , tokens . pos_info )
496
528
fun = lambda x : mgr .BVRepeat (x , count )
497
529
498
530
elif op == "rotate_left" :
@@ -501,7 +533,7 @@ def _smtlib_underscore(self, stack, tokens, key):
501
533
step = int (sstep )
502
534
except ValueError :
503
535
raise PysmtSyntaxError ("Expected number in '_ rotate_left' "
504
- "expression" )
536
+ "expression" , tokens . pos_info )
505
537
fun = lambda x : mgr .BVRol (x , step )
506
538
507
539
elif op == "rotate_right" :
@@ -510,7 +542,7 @@ def _smtlib_underscore(self, stack, tokens, key):
510
542
step = int (sstep )
511
543
except ValueError :
512
544
raise PysmtSyntaxError ("Expected number in '_ rotate_left' "
513
- "expression" )
545
+ "expression" , tokens . pos_info )
514
546
fun = lambda x : mgr .BVRor (x , step )
515
547
516
548
elif op == "sign_extend" :
@@ -519,7 +551,7 @@ def _smtlib_underscore(self, stack, tokens, key):
519
551
width = int (swidth )
520
552
except ValueError :
521
553
raise PysmtSyntaxError ("Expected number in '(_ sign_extend) "
522
- "expression'" )
554
+ "expression'" , tokens . pos_info )
523
555
fun = lambda x : mgr .BVSExt (x , width )
524
556
525
557
elif op .startswith ("bv" ):
@@ -528,11 +560,12 @@ def _smtlib_underscore(self, stack, tokens, key):
528
560
width = int (self .parse_atom (tokens , "expression" ))
529
561
except ValueError :
530
562
raise PysmtSyntaxError ("Expected number in '_ bv' expression: "
531
- "'%s'" % op )
563
+ "'%s'" % op , tokens . pos_info )
532
564
fun = mgr .BV (v , width )
533
565
534
566
else :
535
- raise PysmtSyntaxError ("Unexpected '_' expression '%s'" % op )
567
+ raise PysmtSyntaxError ("Unexpected '_' expression '%s'" % op ,
568
+ tokens .pos_info )
536
569
537
570
stack [- 1 ].append (lambda : fun )
538
571
@@ -640,7 +673,8 @@ def _enter_let(self, stack, tokens, key):
640
673
self .consume_opening (tokens , "expression" )
641
674
while current != ")" :
642
675
if current != "(" :
643
- raise PysmtSyntaxError ("Expected '(' in let binding" )
676
+ raise PysmtSyntaxError ("Expected '(' in let binding" ,
677
+ tokens .pos_info )
644
678
vname = self .parse_atom (tokens , "expression" )
645
679
expr = self .get_expression (tokens )
646
680
newvals [vname ] = expr
@@ -669,7 +703,7 @@ def _enter_quantifier(self, stack, tokens, key):
669
703
self .consume_opening (tokens , "expression" )
670
704
while current != ")" :
671
705
if current != "(" :
672
- raise PysmtSyntaxError ("Expected '(' in let binding" )
706
+ raise PysmtSyntaxError ("Expected '(' in let binding" , tokens . pos_info )
673
707
vname = self .parse_atom (tokens , "expression" )
674
708
typename = self .parse_type (tokens , "expression" )
675
709
@@ -700,7 +734,8 @@ def _enter_annotation(self, stack, tokens, key):
700
734
while tk != ")" :
701
735
if not tk .startswith (":" ):
702
736
raise PysmtSyntaxError ("Annotations keyword should start with"
703
- " colon! Offending token: '%s'" % tk )
737
+ " colon! Offending token: '%s'" % tk ,
738
+ tokens .pos_info )
704
739
keyword = tk [1 :]
705
740
tk = tokens .consume ()
706
741
value = None
@@ -752,7 +787,8 @@ def get_expression(self, tokens):
752
787
lst = stack .pop ()
753
788
fun = lst .pop (0 )
754
789
except IndexError :
755
- raise PysmtSyntaxError ("Unexpected ')'" )
790
+ raise PysmtSyntaxError ("Unexpected ')'" ,
791
+ tokens .pos_info )
756
792
757
793
try :
758
794
res = fun (* lst )
@@ -816,10 +852,12 @@ def parse_atoms(self, tokens, command, min_size, max_size=None):
816
852
if current == ")" :
817
853
raise PysmtSyntaxError ("Expected at least %d arguments in "
818
854
"%s command." % \
819
- (min_size , command ))
855
+ (min_size , command ),
856
+ tokens .pos_info )
820
857
if current == "(" :
821
858
raise PysmtSyntaxError ("Unexpected token '(' in %s "
822
- "command." % command )
859
+ "command." % command ,
860
+ tokens .pos_info )
823
861
res .append (current )
824
862
825
863
for _ in xrange (min_size , max_size + 1 ):
@@ -828,11 +866,13 @@ def parse_atoms(self, tokens, command, min_size, max_size=None):
828
866
return res
829
867
if current == "(" :
830
868
raise PysmtSyntaxError ("Unexpected token '(' in %s "
831
- "command." % command )
869
+ "command." % command ,
870
+ tokens .pos_info )
832
871
res .append (current )
833
872
raise PysmtSyntaxError ("Unexpected token '%s' in %s command. Expected " \
834
- "at most %d arguments." % (current , command ,
835
- max_size ))
873
+ "at most %d arguments." % \
874
+ (current , command , max_size ),
875
+ tokens .pos_info )
836
876
837
877
def parse_type (self , tokens , command , type_params = None , additional_token = None ):
838
878
"""Parses a single type name from the tokens"""
@@ -857,15 +897,17 @@ def parse_type(self, tokens, command, type_params=None, additional_token=None):
857
897
ts = tokens .consume ()
858
898
if ts != "BitVec" :
859
899
raise PysmtSyntaxError ("Unexpected token '%s' in %s command." % \
860
- (ts , command ))
900
+ (ts , command ),
901
+ tokens .pos_info )
861
902
862
903
size = 0
863
904
dim = tokens .consume ()
864
905
try :
865
906
size = int (dim )
866
907
except ValueError :
867
908
raise PysmtSyntaxError ("Unexpected token '%s' in %s command." % \
868
- (dim , command ))
909
+ (dim , command ),
910
+ tokens .pos_info )
869
911
870
912
self .consume_closing (tokens , command )
871
913
res = self .env .type_manager .BVType (size )
@@ -874,7 +916,8 @@ def parse_type(self, tokens, command, type_params=None, additional_token=None):
874
916
base_type = self .cache .get (op )
875
917
if base_type is None or not isinstance (base_type , _TypeDecl ):
876
918
raise PysmtSyntaxError ("Unexpected token '%s' in %s command." % \
877
- (op , command ))
919
+ (op , command ),
920
+ tokens .pos_info )
878
921
pparams = []
879
922
has_free_params = False
880
923
for _ in range (base_type .arity ):
@@ -907,7 +950,8 @@ def definition(*args):
907
950
res = self .cache .get (var )
908
951
else :
909
952
raise PysmtSyntaxError ("Unexpected token '%s' in %s command." % \
910
- (var , command ))
953
+ (var , command ),
954
+ tokens .pos_info )
911
955
912
956
if isinstance (res , _TypeDecl ):
913
957
return res ()
@@ -920,7 +964,8 @@ def parse_atom(self, tokens, command):
920
964
var = tokens .consume ()
921
965
if var == "(" or var == ")" :
922
966
raise PysmtSyntaxError ("Unexpected token '%s' in %s command." % \
923
- (var , command ))
967
+ (var , command ),
968
+ tokens .pos_info )
924
969
return var
925
970
926
971
def parse_params (self , tokens , command ):
@@ -962,14 +1007,16 @@ def consume_opening(self, tokens, command):
962
1007
p = tokens .consume ()
963
1008
if p != "(" :
964
1009
raise PysmtSyntaxError ("Unexpected token '%s' in %s command. " \
965
- "Expected '('" % (p , command ))
1010
+ "Expected '('" %
1011
+ (p , command ), tokens .pos_info )
966
1012
967
1013
def consume_closing (self , tokens , command ):
968
1014
""" Consumes a single ')' """
969
1015
p = tokens .consume ()
970
1016
if p != ")" :
971
1017
raise PysmtSyntaxError ("Unexpected token '%s' in %s command. " \
972
- "Expected ')'" % (p , command ))
1018
+ "Expected ')'" %
1019
+ (p , command , tokens .pos_info ))
973
1020
974
1021
def _function_call_helper (self , v , * args ):
975
1022
""" Helper function for dealing with function calls """
@@ -988,7 +1035,7 @@ def get_assignment_list(self, script):
988
1035
current = tokens .consume ()
989
1036
while current != ")" :
990
1037
if current != "(" :
991
- raise PysmtSyntaxError ("'(' expected" )
1038
+ raise PysmtSyntaxError ("'(' expected" , tokens . pos_info )
992
1039
vname = self .get_expression (tokens )
993
1040
expr = self .get_expression (tokens )
994
1041
self .consume_closing (tokens , current )
@@ -1125,7 +1172,8 @@ def _cmd_declare_sort(self, current, tokens):
1125
1172
try :
1126
1173
type_ = self .env .type_manager .Type (typename , int (arity ))
1127
1174
except ValueError :
1128
- raise PysmtSyntaxError ("Expected an integer as arity of type %s" % typename )
1175
+ raise PysmtSyntaxError ("Expected an integer as arity of type %s." % \
1176
+ typename , tokens .pos_info )
1129
1177
self .cache .bind (typename , type_ )
1130
1178
return SmtLibCommand (current , [type_ ])
1131
1179
0 commit comments