-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathmessages.py
2477 lines (2188 loc) · 86 KB
/
messages.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# © 2021-2023 Intel Corporation
# SPDX-License-Identifier: MPL-2.0
from .logging import (DMLError, DMLWarning, SimpleSite, PortingMessage, ICE,
dollar)
def truncate(s, maxlen):
"Make sure that s is not longer than maxlen"
if len(s) > maxlen:
return s[:maxlen-3] + '...'
return s
def binary_dump(lh, rh):
"""Produce a string to use in warning and error messages describing
operands to a binary operation"""
return ("LH: '%s' of type '%s'\n"
"RH: '%s' of type '%s'"
% (truncate(str(lh), 40), lh.ctype(),
truncate(str(rh), 40), rh.ctype()))
def unary_dump(rh):
"""Produce a string to use in warning and error messages describing
operands to a binary operation"""
return ("RH: '%s' of type '%s'"
% (truncate(str(rh), 40), rh.ctype()))
class EAFTER(DMLError):
"""
An illegal `after` statement was specified. The method callback specified
may not have any output parameters/return values. If the after is with a
time delay or bound to a hook, every input parameter must be of serializable
type (unless that input parameter receives a message component of a hook).
"""
fmt = "illegal 'after' statement%s with callback method '%s': %s"
def __init__(self, site, hookexpr, method, unserializable):
if unserializable:
msg = (('every method input parameter %smust be of serializable '
+ 'type')
% ('not receiving a message component '
* (hookexpr is not None),))
else:
msg = ('method must not have any %s'
% ('output parameters' if site.dml_version() == (1, 2)
else 'return values'))
on_hook = (f" bound to hook '{hookexpr}'"
if hookexpr is not None else '')
DMLError.__init__(self, site, on_hook, method.name, msg)
self.method = method
self.unserializable = unserializable
def log(self):
DMLError.log(self)
self.print_site_message(
self.method.site,
"method declaration"
+ ''.join(
f"\nmethod parameter '{pname}' is of unserializable type: "
+ f"{ptype}"
for (pname, ptype) in self.unserializable or []))
class EAFTERSENDNOW(DMLError):
"""
An illegal `after` statement was specified where the callback is `send_now`
of a hook. Every message component type of the hook must be serializable
(unless that component is provided through a message component parameter
of the `after` statement, if the `after` statement is attaching the
callback to another hook.)
"""
version = "1.4"
fmt = ("illegal 'after' statement%s with callback '%s.send_now': "
+ "every message component of '%s' %smust be of serializable type%s"
)
def __init__(self, site, target_hook, callback_hook, unserializable):
# Two hooks involved makes this messy, clarify as well as possible
clarification = ("not provided through a message component parameter "
"of the 'after' " * (target_hook is not None))
unserializable_msg = (''.join(
f"\nmessage component {idx} is of unserializable type: "
+ f"{ptype}"
for (idx, ptype) in unserializable))
on_hook = (f"bound to hook '{target_hook}'"
if target_hook is not None else '')
DMLError.__init__(self, site, on_hook, callback_hook, callback_hook,
clarification, unserializable_msg)
class EAFTERHOOK(DMLError):
"""
An illegal hook-bound `after` statement was specified.
The number of message component parameters must be equal to the number of
message components of the hook.
"""
version = "1.4"
fmt = ("illegal 'after' statement bound to hook '%s': "
+ 'hook has %d message components, but %d message component '
+ 'parameters are given')
class EAFTERMSGCOMPPARAM(DMLError):
"""Message component parameters bound by a hook-bound after statement can
only be used as direct arguments to the specified callback method, and
cannot be used in arbitrary expressions.
"""
version = "1.4"
fmt = ("'%s' is a message component parameter, and can only be used as a "
"direct argument to the callback method of the after statement")
class EHOOKTYPE(DMLError):
"""There are some minor restrictions to a hook's message component
types. Anonymous structs and arrays of variable/unknown size are not
supported.
"""
version = "1.4"
fmt = ("'%s' is a not a valid message component type for a hook, as it "
"is or contains some %s")
class ECYCLICIMP(DMLError):
"""
A DML file imports itself, either directly or indirectly.
"""
fmt = "cyclic import"
def __init__(self, sites):
DMLError.__init__(self, sites[0])
self.other_sites = sites[1:]
def log(self):
DMLError.log(self)
for site in self.other_sites:
self.print_site_message(site, "via here")
class ECYCLICTEMPLATE(DMLError):
"""
A template inherits from itself, either directly or indirectly.
"""
fmt = "cyclic template inheritance"
def __init__(self, sites):
DMLError.__init__(self, sites[0])
self.other_sites = sites[1:]
def log(self):
DMLError.log(self)
for site in self.other_sites:
self.print_site_message(site, "via here")
class EAMBINH(DMLError):
"""If a method or parameter has multiple definitions, then there must
be a unique definition that overrides all other definitions.
"""
fmt = "conflicting definitions of %s when instantiating %s and %s"
def __init__(self, site, other_site, method, rank_desc1, rank_desc2,
overridable=True):
DMLError.__init__(self, site, method, rank_desc1, rank_desc2)
extra_lines = []
if other_site:
extra_lines.append((other_site, "conflicting definition"))
def how_to_instantiate(rank_desc):
# we ignore 'in each' blocks here. In order to get a
# rank superior to an 'in each' block, one needs to
# instantiate the parent template or file.
if rank_desc.kind == 'file':
return "add 'import \"%s\"' in this file" % (
rank_desc.text,)
elif rank_desc.kind == 'template':
return "add 'is %s' near this line" % (rank_desc.text,)
else:
assert rank_desc.kind == 'verbatim'
# should not happen
return "instantiate %s" % rank_desc.text
if overridable:
# conflicting default methods
extra_lines.append((
site, "to resolve, either %s..."
% (how_to_instantiate(rank_desc2),)))
extra_lines.append((
other_site, "... or %s" % (how_to_instantiate(
rank_desc1),)))
else:
# one non-default method
extra_lines.append((
site, "probable resolution: " + how_to_instantiate(
rank_desc2)))
self.extra_lines = extra_lines
def log(self):
DMLError.log(self)
for (site, msg) in self.extra_lines:
self.print_site_message(site, msg)
class EAMBDEFAULT(DMLError):
"""A method may not invoke its default implementation if multiple
methods are overridden, and the template inheritance graph is
insufficient to infer that one default implementation overrides
the others. See section [x](language.html#calling-methods) for details.
"""
fmt = "Ambiguous invocation of default implementation"
def __init__(self, site, default_sites):
DMLError.__init__(self, site)
self.default_sites = default_sites
def log(self):
DMLError.log(self)
for site in self.default_sites:
self.print_site_message(site, "default method candidate")
class EAMETH(DMLError):
"""
An abstract method cannot override another method.
"""
fmt = "abstract method %s overrides existing method"
def __init__(self, site, prev_site, name):
DMLError.__init__(self, site, name)
self.prev_site = prev_site
def log(self):
DMLError.log(self)
self.print_site_message(
self.prev_site, "previous declaration")
class ETMETH(DMLError):
"""
A shared method cannot override a non-shared method
"""
version = "1.4"
fmt = "attempt to override non-shared method %s with shared method"
def __init__(self, site, trait_method_site, name):
DMLError.__init__(self, site, name)
self.trait_method_site = trait_method_site
def log(self):
DMLError.log(self)
self.print_site_message(
self.trait_method_site, "shared method definition")
class ETEMPLATEUPCAST(DMLError):
"""When casting to a template type, the source expression must be either
an object implementing the template, or an expression whose type is a
subtemplate of the target type."""
version = "1.4"
fmt = "invalid upcast, %s not a subtemplate of %s"
class EABSTEMPLATE(DMLError):
"""
If a template has any abstract methods or parameters, they must all be
implemented when instantiating the template.
"""
version = "1.4"
fmt = "Instantiating template %s requires abstract %s %s to be implemented"
def __init__(self, is_site, decl_site, decl_trait, kind, name):
DMLError.__init__(self, is_site, decl_trait, kind, name)
self.decl_site = decl_site
def log(self):
DMLError.log(self)
self.print_site_message(
self.decl_site, "abstract declaration")
class EIMPORT(DMLError):
"""
The file to imported could not be found. Use the `-I`
option to specify additional directories to search for imported
files.
"""
fmt = "cannot find file to import: %s"
def __init__(self, site, filename):
DMLError.__init__(self, site, filename)
class ESIMAPI(DMLError):
"""
The DML file is written in a too old version of DML. Use the
`--simics-api` option to use a sufficiently old Simics API.
"""
fmt = "DML version %s does not support API version %s"
def __init__(self, site, dml_ver, api_ver):
DMLError.__init__(self, site, dml_ver, api_ver)
class ETYPE(DMLError):
"""
The data type is not defined in the DML code.
"""
fmt = "unknown type: '%s'"
class EVARTYPE(DMLError):
"""A variable has been declared with a given type but the type is
not acceptable.
"""
fmt = "variable or field declared %s"
class ETREC(DMLError):
"""
The definition of a structure type can not have itself as direct or
indirect member.
"""
fmt = "recursive type definition of %s"
def __init__(self, sites, type):
DMLError.__init__(self, sites[0], type)
self.other_sites = sites[1:]
def log(self):
DMLError.log(self)
for site in self.other_sites:
self.print_site_message(site, "via here")
class EANONSTRUCT(DMLError):
"""
Declarations of new structs are not permitted in certain contexts,
such as method arguments, `new` expressions,
`sizeoftype` expressions and `cast` expressions.
"""
fmt = "struct declaration not allowed in a %s"
class EEMPTYSTRUCT(DMLError):
"""
A struct or layout type must have at least one field.
This restriction does not apply to structs declared in a
`extern typedef`.
"""
fmt = "struct or layout with no fields"
class ECAST(DMLError):
"""
The cast operation was not allowed. It is illegal to cast to void.
"""
fmt = "illegal cast to '%s'"
def __init__(self, site, expr, type):
DMLError.__init__(self, site, type)
class EVOID(DMLError):
"""The type `void` is not a value, and thus cannot be used as
the type of e.g. a variable or struct member"""
fmt = "illegal use of void type"
class ENBOOL(DMLError):
"""
Conditions must be properly boolean expressions; e.g., "`if (i ==
0)`" is allowed, but "`if (i)`" is not, if `i` is an
integer.
"""
fmt = "non-boolean condition: '%s' of type '%s'"
def __init__(self, expr):
DMLError.__init__(self, expr, expr, expr.ctype())
class EASSIGN(DMLError):
"""
The target of the assignment is not an l-value, and thus cannot be
assigned to.
"""
fmt = "cannot assign to this expression: '%s'"
def __init__(self, site, target):
DMLError.__init__(self, site, target)
class EASTYPE(DMLError):
"""
The target of an initializer is incompatible with the type of the
initializer.
"""
fmt = ("wrong type for initializer\n"
"got: %s\n"
"expected: %s")
def __init__(self, site, target_type, source):
self.source = source
self.target_type = target_type
DMLError.__init__(self,
site, source.ctype().describe(),
target_type.describe_assign_types())
class EINCTYPE(DMLError):
"""
The prefix and postfix increment/decrement operators can only be
used on integer and pointer expressions.
"""
fmt = ("wrong type for '%s' operator")
class EBTYPE(DMLError):
"""
An expression had the wrong type.
"""
fmt = ("wrong type\n"
"got: %s\n"
"expected: %s")
class ECSADD(DMLError):
"""
Non-constant strings cannot be concatenated using `+`.
"""
fmt = ("non-constant strings cannot be concatenated using '+'")
class EEARG(DMLError):
"""
Function and method arguments in declarations cannot be of
endian integer type.
"""
fmt = ("cannot use endian integer as argument type in declaration")
class EASSINL(DMLError):
"""
The target of the assignment is a method parameter that has been
given a constant or undefined value when inlining the method.
"""
fmt = "cannot assign to inlined parameter: '%s'"
def __init__(self, site, name):
DMLError.__init__(self, site, name)
class EERRSTMT(DMLError):
"""
The source code contained a statement "`error;`", which
forces a compilation error with the given message, or the standard message
"forced compilation error in source code".
"""
fmt = "%s"
def __init__(self, site, msg):
DMLError.__init__(self, site, msg)
class EEXTERN(DMLError):
"""An extern declared method must be fully typed and may not throw
exceptions."""
fmt = "illegal declaration of extern method"
version = "1.2"
class EEXPORT(DMLError):
"""Can only export non-inline, non-shared, non-throwing methods declared
outside object arrays."""
fmt = "cannot export this method"
version = "1.4"
def __init__(self, method_site, export_site):
DMLError.__init__(self, method_site)
self.export_site = export_site
def log(self):
DMLError.log(self)
self.print_site_message(self.export_site, "exported here")
class ESTATICEXPORT(DMLError):
"""A method reference can only be converted to a function pointer if the
method is non-inline, non-shared, non-throwing, and declared outside an
object array."""
fmt = "cannot convert this method reference to a function pointer"
version = "1.4"
def __init__(self, method_site, addressof_site):
DMLError.__init__(self, method_site)
self.addressof_site = addressof_site
def log(self):
DMLError.log(self)
self.print_site_message(self.addressof_site,
"attempted conversion here")
class EINVALID(DMLError):
"""
The expression does not produce a proper value.
"""
fmt = "invalid expression: '%s'"
def __init__(self, expr):
DMLError.__init__(self, expr, expr)
class EUNDEF(DMLError):
"""
Caused by an attempt to generate code for an expression that
contains the `undefined` value.
"""
fmt = "undefined value: '%s'"
def __init__(self, site, expr = None):
if expr is None:
expr = site
DMLError.__init__(self, site, expr)
class ESHNEG(DMLError):
"""
The right-hand side operand to a shift operator must not be negative.
"""
fmt = "shift with negative shift count: '%s"
class EDIVZ(DMLError):
"""
The right-hand side of the given / or % operator is always zero.
"""
fmt = "right-hand side operand of '%s' is zero"
# TODO: also check bitwise or/xor for type errors.
class EBINOP(DMLError):
"""
One or both of the operands have the wrong type for the given binary
operator.
"""
fmt = "illegal operands to binary '%s' \n%s"
def __init__(self, site, op, lh, rh):
DMLError.__init__(self, site, op, binary_dump(lh, rh))
class EBSLICE(DMLError):
"""
A bitslice operation was attempted on an expression that is not an
integer.
"""
fmt = "illegal bitslice operation"
class EBSSIZE(DMLError):
"""
Bit slices cannot be larger than 64 bits.
"""
fmt = "bitslice size of %s bits is not between 1 and 64"
class EBSBE(DMLError):
"""A big-endian bit slice can only be done on an expression whose type
is explicitly defined, such as a local variable or a register field."""
fmt = "bitslice with big-endian bit order and uncertain bit width"
def __init__(self, site):
DMLError.__init__(self, site)
class EZRANGE(DMLError):
"""
An array index range must start at zero.
"""
fmt = "array range must start at 0"
def __init__(self, site):
DMLError.__init__(self, site)
class ENARRAY(DMLError):
"""
Indexing can only be applied to arrays, integers (bit-slicing),
and lists.
"""
fmt = "trying to index something that isn't an array: '%s'"
def __init__(self, expr):
DMLError.__init__(self, expr, expr)
class EOOB(DMLError):
"""
The used index is outside the defined range.
"""
fmt = "array index out of bounds"
def __init__(self, expr):
DMLError.__init__(self, expr)
class EAVAR(DMLError):
"""
Indexing into constant lists can only be done with constant indexes.
"""
fmt = "cannot use variable index in a constant list"
class ECLST(DMLError):
"""
Lists may only contain constants.
"""
fmt = "non-constant element in list"
class ENLST(DMLError):
"""
A list was expected.
"""
fmt = "not a list: %s"
class ENVAL(DMLError):
"""
Only some objects can be used as values directly. An attribute can
only be accessed directly as a value if it has been declared using the
`allocate_type` parameter.
"""
fmt = "not a value: %s"
class ENORET(DMLError):
"""
If a method has output arguments, then control flow may not reach
the end of the method. Either an explicit value must be returned
in a return statement, or the execution must be aborted by an
exception or assertion failure. Note that DMLC's control flow
analysis is rather rudimentary, and can issue this error on code
that provably will return. In this case, the error message can be
silenced by adding `assert false;` to the end of the
method body.
"""
version = "1.4"
fmt = "missing return statement in method with output argument"
class EATYPE(DMLError):
"""
Either the `attr_type` or the `type` parameter of the
attribute must be specified.
"""
fmt = "attribute type undefined: %s"
def __init__(self, attr):
DMLError.__init__(self, attr, attr.identity())
class EANAME(DMLError):
"""
This name is not available as the name of an attribute, since it is
used for an automatically added attribute.
"""
fmt = "illegal attribute name: %s"
class EACHK(DMLError):
"""
An attribute must have set and get methods to be
checkpointable. This attribute has neither, and the
'configuration' parameter is either "required" or "optional".
"""
fmt = "checkpointable attribute missing set or get method"
class EANULL(DMLError):
"""
An attribute must have a set or a get method to be useful.
"""
fmt = "attribute has no get or set method"
class EREGVAL(DMLError):
"""
When a register has been specified with explicit fields, you have to
use the `get` and `set` methods to access the register as
a single value.
"""
fmt = "cannot use a register with fields as a value: %s"
def __init__(self, site, reg):
DMLError.__init__(self, site, reg.identity())
class ENOPTR(DMLError):
"""
A pointer value was expected.
"""
fmt = "not a pointer: %s (%s)"
def __init__(self, site, expr):
DMLError.__init__(self, site, expr, expr.ctype().describe())
class ENOSTRUCT(DMLError):
"""
The left-hand side operand of the `.` operator is not of struct
type.
"""
fmt = "trying to get a member of a non-struct: '%s' of type '%s'"
def __init__(self, site, expr, ctype = None):
DMLError.__init__(self, site, expr, ctype or expr.ctype())
class EBADFAIL(DMLError):
"""
An exception is thrown in a context where it will not be caught.
"""
fmt = "uncaught exception"
class EBADFAIL_dml12(DMLError):
"""If a DML 1.2 method lacks a `nothrow` annotation, and a
non-throwing DML 1.4 method calls it, then DMLC will analyze
whether the method call can actually cause an exception. If it
can, this error is reported; if not, the call is permitted.
For this error, a 1.2 method counts as throwing if it throws an
exception, or calls a `throws` marked 1.4 method, or
(recursively) if it invokes a method that counts as throwing. A
call or throw statement inside a `try` block does not cause
the method to count as throwing. The methods
`attribute.set`, `bank.read_access` and
`bank.write_access` count as throwing even if they don't
throw.
This error is normally reported while porting common DML 1.2 code
to DML 1.4: most 1.2 methods are not meant to throw exceptions,
and when converted to DML 1.4 this becomes a strict requirement
unless the method is annotated with the `throws` keyword.
The remedy for this error message is normally to insert a
`try` block around some call along the throwing call chain,
with a `catch` block that handles the exception
gracefully. The `try` block should usually be as close as
possible to the `throw` in the call chain.
"""
fmt = "uncaught exception in call to DML 1.2 method '%s'"
# DML 1.2 methods that explicitly throw.
# caller -> site of throwing statement
throwing_methods = {}
# Calls from DML 1.2 methods to other DML 1.2 methods, which may cause
# the caller to throw.
# callee -> [(call-site, caller), ...]
uncaught_method_calls = {}
# Calls from DML 1.4 methods into potentially throwing DML 1.2 methods.
# callee -> [(call-site, caller), ...]
protected_calls = {}
def __init__(self, site, call_chain, other_callers):
(_, bad_method) = call_chain[0]
DMLError.__init__(self, site, bad_method.name)
self.site = site
self.call_chain = call_chain
self.other_callers = other_callers
def log(self):
DMLError.log(self)
for (site, m) in self.call_chain:
self.print_site_message(
site, "exception propagated from %s()" % (m.name,))
(_, bad_method) = self.call_chain[0]
for (site, m) in self.other_callers:
self.print_site_message(
site, "method '%s' also called here" % (bad_method.name,))
@classmethod
def all_errors(cls):
shortest_call_chains = {
m: [(site, m)] for (m, site) in cls.throwing_methods.items()}
queue = list(cls.throwing_methods)
i = 0
while i < len(queue):
m = queue[i]
for (site, caller) in cls.uncaught_method_calls.get(m, []):
if caller not in shortest_call_chains:
queue.append(caller)
shortest_call_chains[caller] = (
[(site, caller)] + shortest_call_chains[m])
i += 1
for m in cls.protected_calls:
if m in shortest_call_chains:
(site, _) = cls.protected_calls[m][0]
yield cls(site, shortest_call_chains[m],
cls.protected_calls[m][1:])
class EAPPLY(DMLError):
"""
The applied value is not a function.
"""
fmt = ("illegal function application of '%s'\n"
"type: %s")
def __init__(self, fun, ftype = None):
if not ftype:
ftype = fun.ctype()
DMLError.__init__(self, fun, fun, ftype)
class EAPPLYMETH(DMLError):
"""
Calls to inline methods, methods that may throw, or methods that have
multiple output parameters cannot be used as arbitrary expressions. In DML
1.2, any such method must be called via the `call` or `inline` statements,
and in DML 1.4 any such method must be called either as a standalone
statement, or as an initializer (e.g., RHS of an assignment or argument of
a `return` statement).
"""
fmt = "call to method '%s' in unsupported context\n%s"
def __init__(self, site, fun):
if site.dml_version() == (1, 2):
suggestion = ("use the 'call' or 'inline' statements to call "
+ "this method")
else:
suggestion = ("perform this method call either as a standalone "
+ "statement or as an initializer (e.g., as the RHS "
+ "of an assignment)")
DMLError.__init__(self, site, fun, suggestion)
class EIDENT(DMLError):
"""
The identifier has not been declared anywhere.
"""
fmt = "unknown identifier: '%s'"
def __init__(self, site, name):
DMLError.__init__(self, site, name)
self.identifier = name
class ENAMEID(DMLError):
"""
The name parameter does not follow identifier syntax.
"""
fmt = "invalid name parameter value: '%s'"
class EFORMAT(DMLError):
"""
The log-statement format string is malformed.
"""
fmt = "malformed format string: unknown format at position %d"
class EDEVICE(DMLError):
"""
The main source file given to the DML compiler must contain a
`device` declaration.
"""
fmt = "missing device declaration"
class ELTYPE(DMLError):
"""
Log-statement type must be one of `info`, `error`,
`spec_viol`, and `unimpl`.
"""
fmt = "invalid log type: '%s'"
class ELLEV(DMLError):
"""
The log level given in a log statement must be an integer between 1 and 4.
Or 1 and 5 for a subsequent log level (`then ...`).
"""
fmt = "log level must be an integer between 1 and %d"
class ESYNTAX(DMLError):
"""
The code is malformed.
"""
fmt = "syntax error%s%s"
def __init__(self, site, tokenstr, reason):
if tokenstr:
assert isinstance(tokenstr, str)
where = " at '%s'" % truncate(tokenstr, 20)
else:
where = ""
if reason:
reason = ": " + reason
else:
reason = ""
DMLError.__init__(self, site, where, reason)
class EPARAM(DMLError):
"""
The parameter is not bound to a legal value.
"""
fmt = "illegal value for parameter '%s'"
class EUNINITIALIZED(DMLError):
"""
Some parameters that are automatically supplied by DML
cannot be accessed in early stages of compilation, such as in object-level
if statements.
"""
fmt = "value of parameter %s is not yet initialized"
class ECONDP(DMLError):
"""
It is not permitted to declare a parameter directly inside an
`if` conditional.
"""
fmt = "conditional parameters are not allowed"
class ECONDT(DMLError):
"""
It is not permitted to use a template directly inside an
`if` conditional.
"""
fmt = "conditional templates are not allowed"
class ECONDINEACH(DMLError):
"""
It is not permitted to have an `in each` statement directly
inside an `if` conditional.
"""
version = "1.4"
fmt = "conditional 'in each' is not allowed"
# TODO: Consider re-wording the semantics of this error, allocate_type is only
# relevant in 1.4 when imported from 1.2, and as per SIMICS-9393 this
# error might not even be necessary
class EATTRDATA(DMLError):
"""
Specifying `allocate_type` and using 'data'
declarations in the same attribute object is not allowed.
"""
fmt = ("cannot define both 'allocate_type' parameter "
"and local data objects")
def __init__(self, attr, allocate_type_site, data_sites):
self.allocate_site = allocate_type_site
self.data_sites = data_sites
DMLError.__init__(self, attr)
def log(self):
DMLError.log(self)
self.print_site_message(self.allocate_site, "'allocate_type' set here")
for data_site in self.data_sites:
self.print_site_message(data_site, 'data object declared here')
class ERETTYPE(DMLError):
"""
The type of the return value (if any) must be specified for methods
that implement interfaces.
"""
fmt = "no return type"
def __init__(self, meth):
DMLError.__init__(self, meth)
class ERETARGNAME(DMLError):
"""
In DML 1.4, the output arguments of a method are anonymous
"""
version = "1.4"
fmt = "method return type declarations may not be named: %s"
class EIFREF(DMLError):
"""
Interface function calls must be simple references to the method.
"""
fmt = "illegal interface method reference: %s"
class EREF(DMLError):
"""
The referenced object has not been declared.
"""
fmt = "reference to unknown object '%s'"
def __init__(self, site, name, obj = None):
if obj is None:
place = name
else:
place = "%s.%s" % (obj, name)
DMLError.__init__(self, site, place)
class ENOBJ(DMLError):
"""
A reference to an object was expected.
"""
fmt = "object expected: %s"
class EFMTARGN(DMLError):
"""
The log-statement has too few or too many arguments for the given
format string.
"""
fmt = "wrong number of arguments for format string"
class EASZVAR(DMLError):
"""
The size of an array must be a constant integer.
"""
fmt = "array upper bound is not a constant integer: %s"
class EASZR(DMLError):
"""
An array must have at least one element.
"""
fmt = "array size is less than 1"
def __init__(self, site):
DMLError.__init__(self, site)
class EASZLARGE(DMLError):
"""
Object arrays with huge dimensions are not allowed; the product of
dimension sizes must be smaller than 2<sup>31</sup>.
"""
# It would be cheap to bump the limit to 2**32 elements, but that
# would require some additional testing to check that we never use
# signed 32-bit integer arithmetic on packed indices.
fmt = f"array has too many elements (%d >= {2**31})"
class EAINCOMP(DMLError):
"""
The array has been declared more than once, in an incompatible way.
"""
fmt = "incompatible array declarations: %s"
def __init__(self, site, othersite, name, reason):
DMLError.__init__(self, site, reason)
self.othersite = othersite
def log(self):
DMLError.log(self)
if self.othersite:
self.print_site_message(self.othersite, "conflicting declaration")
class EAUNKDIMSIZE(DMLError):
"""
The size of an array dimension of an object array must be defined at least
once across all declarations of that object array.
"""
fmt = ("the size of dimension %d (with index variable '%s') is never "
+ "defined")
class ENCONST(DMLError):
"""
A constant expression was expected.
"""
fmt = "non-constant expression: %s"
class ECONT(DMLError):
"""
A `continue` statement can only be used inside a loop construct.
"""
fmt = "nothing to continue"
class ECONTU(DMLError):
"""
A `continue` statement cannot be used in a `foreach`
or `select` statement.
"""
fmt = "continue is not possible here"
class EBREAK(DMLError):
"""
A `break` statement can only be used inside a loop or switch
construct.
"""
fmt = "nothing to break from"
class ENMETH(DMLError):
"""
A method name was expected. This might be caused by using
`call` or `inline` on something that counts as a C
function rather than a method.
"""
fmt = "not a method: '%s'"
class ENDEFAULT(DMLError):
"""
The default implementation of a method was invoked, but there was
no default implementation.
"""
fmt = "no default implementation"
class EARG(DMLError):
"""
The number of input/output arguments given in the call differs from
the method definition.
"""
fmt = "wrong number of %s arguments"
class ERETLVALS(DMLError):
"""
The number of return value recipients differs from the number of values
the called method returns.
"""
version = "1.4"
fmt = "wrong number of return value recipients: Expected %d, got %d"