diff --git a/MODULEINFO b/MODULEINFO index 52cdba44e..2bc57d320 100644 --- a/MODULEINFO +++ b/MODULEINFO @@ -42,6 +42,7 @@ Make: dmlc $(HOST)/bin/dml/python/dml/dmllex14.py $(HOST)/bin/dml/python/dml/dmlparse.py $(HOST)/bin/dml/python/dml/dmlc.py + $(HOST)/bin/dml/python/dml/errors.py $(HOST)/bin/dml/python/dml/expr.py $(HOST)/bin/dml/python/dml/expr_util.py $(HOST)/bin/dml/python/dml/globals.py @@ -50,9 +51,9 @@ Make: dmlc $(HOST)/bin/dml/python/dml/int_register.py $(HOST)/bin/dml/python/dml/io_memory.py $(HOST)/bin/dml/python/dml/logging.py - $(HOST)/bin/dml/python/dml/messages.py $(HOST)/bin/dml/python/dml/objects.py $(HOST)/bin/dml/python/dml/output.py + $(HOST)/bin/dml/python/dml/porting.py $(HOST)/bin/dml/python/dml/provisional.py $(HOST)/bin/dml/python/dml/reginfo.py $(HOST)/bin/dml/python/dml/serialize.py @@ -65,6 +66,7 @@ Make: dmlc $(HOST)/bin/dml/python/dml/topsort.py $(HOST)/bin/dml/python/dml/traits.py $(HOST)/bin/dml/python/dml/types.py + $(HOST)/bin/dml/python/dml/warnings.py $(HOST)/bin/dml/python/dml/dml12_parsetab.py $(HOST)/bin/dml/python/dml/dml14_parsetab.py $(HOST)/bin/dml/python/LICENSE diff --git a/Makefile b/Makefile index 688a9ece2..30511e272 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ PYFILES := dml/__init__.py \ dml/dmllex14.py \ dml/dmlparse.py \ dml/dmlc.py \ + dml/errors.py \ dml/expr.py \ dml/expr_util.py \ dml/globals.py \ @@ -34,9 +35,9 @@ PYFILES := dml/__init__.py \ dml/io_memory.py \ dml/int_register.py \ dml/logging.py \ - dml/messages.py \ dml/objects.py \ dml/output.py \ + dml/porting.py \ dml/provisional.py \ dml/reginfo.py \ dml/serialize.py \ @@ -44,6 +45,7 @@ PYFILES := dml/__init__.py \ dml/slotsmeta.py \ dml/structure.py \ dml/symtab.py \ + dml/warnings.py \ __main__.py PYUNIT_FILES := $(wildcard $(DMLC_DIR)/py/dml/*_test.py) diff --git a/messages_to_md.py b/messages_to_md.py index 5ef7bd3f9..f9bb46ccd 100644 --- a/messages_to_md.py +++ b/messages_to_md.py @@ -21,30 +21,15 @@ def fmt_message(err): def extract_messages(sys_path): sys.path.append(sys_path) - from dml import messages - from dml.messages import DMLError, DMLWarning + from dml import warnings, errors - errors = [] - warnings = [] - - for n in dir(messages): - o = getattr(messages, n) - #sys.stderr.write("%s: %r\n" % (n, o)) - if isinstance(o, type): - if issubclass(o, DMLError) and o is not DMLError: - errors.append(o) - elif issubclass(o, DMLWarning) and o is not DMLWarning: - warnings.append(o) - - errors.sort(key=lambda x: x.fmt) - warnings.sort(key=lambda x: x.fmt) - return (warnings, errors) + return (warnings.all_warnings, errors.all_errors) def print_message_table(f, messages): f.write("
\n") - for m in messages: - assert m.__doc__ - f.write(f"
\n\n{fmt_message(m)} [{m.__name__}]
\n") + for (tag, m) in sorted(messages.items()): + assert m.__doc__, m + f.write(f"
\n\n{fmt_message(m)} [{tag}]
\n") doc = '\n'.join(line[4:] if line.startswith(' ') else line for line in m.__doc__.strip().splitlines()) f.write(f"
\n\n{doc}\n
\n") @@ -94,5 +79,8 @@ def matches_version(message, target): (warnings, errors) = extract_messages(args.path) with open(args.outfile, 'w') as f: print_messages( - f, [w for w in warnings if matches_version(w, args.version)], - [e for e in errors if matches_version(e, args.version)]) + f, + {tag: w for (tag, w) in warnings.items() + if matches_version(w, args.version)}, + {tag: e for (tag, e) in errors.items() + if matches_version(e, args.version)}) diff --git a/porting_to_md.py b/porting_to_md.py index abf995f37..dd0f3b4f6 100644 --- a/porting_to_md.py +++ b/porting_to_md.py @@ -5,26 +5,15 @@ [path_to_dml, outfile] = sys.argv[1:] sys.path.append(path_to_dml) -from dml import messages -from dml.messages import PortingMessage - -portings = [] - -for n in dir(messages): - o = getattr(messages, n) - if (isinstance(o, type) and issubclass(o, PortingMessage) - and o is not PortingMessage): - portings.append(o) - -portings.sort(key=lambda x: x.__name__) +from dml.porting import all_portings with open(outfile, 'w') as f: f.write("# Language differences handled by the port-dml script\n\n") f.write("
\n") - for m in portings: + for (tag, m) in sorted(all_portings.items()): assert m.__doc__ - f.write(f"
{m.__name__}
\n") + f.write(f"
{tag}
\n") doc = '\n'.join(line[4:] if line.startswith(' ') else line for line in m.__doc__.strip().splitlines()) f.write(f"
\n\n{doc}\n
\n") diff --git a/provisional_to_md.py b/provisional_to_md.py index e44784c09..429a541d9 100644 --- a/provisional_to_md.py +++ b/provisional_to_md.py @@ -8,7 +8,6 @@ dml12_only = {'1.2': True, '1.4': False}[dml_version] from dml import provisional -from dml.env import api_versions, default_api_version with open(outfile, 'w') as f: f.write(Path(header).read_text()) diff --git a/py/dead_dml_methods.py b/py/dead_dml_methods.py index 6c7aa821c..e85031eb6 100644 --- a/py/dead_dml_methods.py +++ b/py/dead_dml_methods.py @@ -115,13 +115,13 @@ def traverse_ast(ast): def method_locations(path): from dml.toplevel import parse_file, determine_version - from dml import logging, messages + from dml import logging, warnings from dml import breaking_changes # needed to parse 1.2/utility.dml breaking_changes.BreakingChange.enabled_breaking_changes = ( set(breaking_changes.changes.values()) - {breaking_changes.forbid_warning_statement}) - for warning in messages.warnings: + for warning in warnings.all_warnings: logging.ignore_warning(warning) (version, _) = determine_version(path.read_text(), path) diff --git a/py/dml/ast.py b/py/dml/ast.py index 9ef99e179..89b5eae8b 100644 --- a/py/dml/ast.py +++ b/py/dml/ast.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: MPL-2.0 import builtins -from .logging import dbg class AST(object): __slots__ = ('__site', '__args', 'kind') diff --git a/py/dml/c_backend.py b/py/dml/c_backend.py index 20fb3f9e6..2f334579e 100644 --- a/py/dml/c_backend.py +++ b/py/dml/c_backend.py @@ -1,7 +1,7 @@ # © 2021 Intel Corporation # SPDX-License-Identifier: MPL-2.0 -import sys, os +import os import itertools import operator import re @@ -12,35 +12,38 @@ import json from pathlib import Path -from . import objects, logging, crep, output, ctree, serialize, structure +from . import objects, expr_util, logging, crep, output, ctree, serialize, structure from . import traits from . import breaking_changes import dml.globals from .structure import get_attr_name, port_class_ident, need_port_proxy_attrs -from .logging import * -from .messages import * -from .output import * -from .ctree import * -from .expr import * -from .expr_util import * -from .symtab import * -from .codegen import * -from .types import * +from .logging import DMLError, ICE, report +from . import errors as E, warnings as W, porting as P +from .output import out +from . import ctree as c +from .expr import mkLit, NonValue +from .expr_util import ( + apply, param_defined, param_expr_site, param_str, + static_indices, undefined) +from .symtab import global_scope, LocalSymbol, Symtab +from . import codegen +from .codegen import codegen_inline_byname +from . import types as tp from .set import Set prototypes = [] c_split_threshold = None -log_object_t = TNamed("log_object_t") -conf_object_t = TNamed("conf_object_t") -attr_value_t = TNamed('attr_value_t') +log_object_t = tp.Named("log_object_t") +conf_object_t = tp.Named("conf_object_t") +attr_value_t = tp.Named('attr_value_t') structfilename = None def get_attr_flags(obj): conf = param_str(obj, 'configuration') - persist = param_bool(obj, 'persistent') - internal = (param_bool_fixup(obj, 'internal', True) + persist = expr_util.param_bool(obj, 'persistent') + internal = (c.param_bool_fixup(obj, 'internal', True) or obj.is_confidential()) if conf == 'required': @@ -50,7 +53,7 @@ def get_attr_flags(obj): elif conf == 'pseudo': flags = 'Sim_Attr_Pseudo' else: - raise EPARAM(param_expr_site(obj, "configuration"), "configuration") + raise E.PARAM(param_expr_site(obj, "configuration"), "configuration") if persist: flags += "|Sim_Attr_Persistent" @@ -68,12 +71,12 @@ def get_short_doc(node): else: return None else: - return param_str_or_null(node, 'shown_desc') + return expr_util.param_str_or_null(node, 'shown_desc') def get_long_doc(node): doc = None if param_defined(node, 'documentation'): - doc = param_str_fixup(node, 'documentation', "") + doc = c.param_str_fixup(node, 'documentation', "") # always check desc to catch EIDXVAR even if it isn't used desc = get_short_doc(node) if doc != None: @@ -103,14 +106,14 @@ def register_attribute(site, port, name): global registered_attribute_names if name in dml.globals.illegal_attributes: - report(EANAME(site, name)) + report(E.ANAME(site, name)) key = (port, name) if key in registered_attribute_names: - report(EATTRCOLL(site, registered_attribute_names[key])) + report(E.ATTRCOLL(site, registered_attribute_names[key])) registered_attribute_names[key] = site # Creating the C struct definition is done in two steps. First, the -# structure is built up using the DMLType type, with a TStruct as the +# structure is built up using the tp.DMLType type, with a tp.Struct as the # base. Then this is printed. def print_device_substruct(node): @@ -120,7 +123,7 @@ def print_device_substruct(node): def arraywrap(node, typ): for arraylen in reversed(node.dimsizes): - typ = TArray(typ, mkIntegerLiteral(node.site, arraylen)) + typ = tp.Array(typ, c.mkIntegerLiteral(node.site, arraylen)) return typ def composite_ctype(node, unfiltered_members, label=None): @@ -133,7 +136,7 @@ def composite_ctype(node, unfiltered_members, label=None): # mangle names so x_y.z and x.y_z give different idents label = '__devstruct_' + '_'.join("%d%s" % (s.count('_'), s) for s in crep.ancestor_cnames(node)) - structtype = TStruct(members, label) + structtype = tp.Struct(members, label) structtype.print_struct_definition() return structtype @@ -142,7 +145,7 @@ def composite_ctype(node, unfiltered_members, label=None): for (v, _) in dml.globals.static_vars: members.append((v.value, v.type)) members.append(('_immediate_after_state', - TPtr(TNamed('_dml_immediate_after_state_t')))) + tp.Ptr(tp.Named('_dml_immediate_after_state_t')))) return composite_ctype(node, members + [(crep.cname(sub), print_device_substruct(sub)) for sub in node.get_components()], @@ -153,10 +156,10 @@ def composite_ctype(node, unfiltered_members, label=None): and node.objtype == 'interface')): return arraywrap(node, crep.node_storage_type(node, node.site)) elif node.objtype == 'hook': - return arraywrap(node, TNamed('_dml_hook_t')) + return arraywrap(node, tp.Named('_dml_hook_t')) elif (node.objtype in {'register', 'field'} and dml.globals.dml_version == (1, 2)): - allocate = param_bool_fixup(node, 'allocate', True) + allocate = c.param_bool_fixup(node, 'allocate', True) if node.simple_storage: return (arraywrap(node, crep.node_storage_type(node)) if allocate else None) @@ -190,7 +193,7 @@ def members(): else: # really a _port_object_t* rather than conf_object_t*, but # there is no DML type for the former - obj = [("_obj", arraywrap(node, TPtr(conf_object_t)))] + obj = [("_obj", arraywrap(node, tp.Ptr(conf_object_t)))] return composite_ctype(node, obj + [(crep.cname(sub), print_device_substruct(sub)) @@ -204,7 +207,7 @@ def members(): allocate_type = crep.node_storage_type(node) if allocate_type: if composite_type: - report(EATTRDATA(node, + report(E.ATTRDATA(node, param_expr_site(node, 'allocate_type'), [session.site for session in node.get_recursive_components('session')])) @@ -243,7 +246,7 @@ def generate_structfile(device, filename, outprefix): out('typedef struct %s %s_t;\n\n' % (crep.cname(device), crep.cname(device))) out('conf_class_t *%s(void);\n\n' % (init_function_name(device, outprefix))) - for (name, (func, export_site)) in list(exported_methods.items()): + for (name, (func, export_site)) in list(codegen.exported_methods.items()): if export_site.dml_version() != (1, 2): out("extern %s;\n" % func.rettype.declaration( @@ -264,9 +267,9 @@ def generate_hfile(device, headers, filename): legacy_attrs = int(not breaking_changes.modern_attributes.enabled) out(f'#define DML_LEGACY_ATTRS {legacy_attrs}\n') - with allow_linemarks(): - for c in headers: - c.toc() + with output.allow_linemarks(): + for chunk in headers: + chunk.toc() out('\n') out('\n') @@ -276,11 +279,11 @@ def generate_hfile(device, headers, filename): out('#include "'+os.path.basename(structfilename)+'"\n\n') for name in dml.globals.traits: - out(f'typedef _traitref_t {cident(name)};\n') + out(f'typedef _traitref_t {tp.cident(name)};\n') # Constraints from C: - # - Types must be defined before they are referred to - # - Structs can be referred to by struct label before they are defined, + # - Types must be expr_util.defined before they are referred to + # - Structs can be referred to by struct label before they are expr_util.defined, # but the struct's definition (member list) must appear before # it can be used as a direct member of another struct. An indirect member # (struct x *member) may however appear before the struct's definition. @@ -301,33 +304,33 @@ def generate_hfile(device, headers, filename): # it depends on, except that it may appear before structs it # refers to *indirectly*, i.e. via a pointer. - # typedefs for named structs come first, because in: + # tp.typedefs for named structs come first, because in: # typedef struct { int i; } X; # typedef struct { X *x; } Y; # the C declaration of Y may appear before that of X, and the # C code for Y currently names the member type 'X' rather than 'struct X'. - for tn in global_type_declaration_order: - if tn not in typedefs: + for tn in tp.global_type_declaration_order: + if tn not in tp.typedefs: continue - t = typedefs[tn] - if isinstance(t, TStruct): + t = tp.typedefs[tn] + if isinstance(t, tp.Struct): out('typedef %sstruct %s %s;\n' % ( - 'const ' if t.const else '', cident(tn), cident(tn))) + 'const ' if t.const else '', tp.cident(tn), tp.cident(tn))) - for tn in global_type_declaration_order: - if tn in global_anonymous_structs: - global_anonymous_structs[tn].print_struct_definition() + for tn in tp.global_type_declaration_order: + if tn in tp.global_anonymous_structs: + tp.global_anonymous_structs[tn].print_struct_definition() else: - t = typedefs[tn] - if isinstance(t, TStruct): + t = tp.typedefs[tn] + if isinstance(t, tp.Struct): t.print_struct_definition() else: out('typedef ') - t.print_declaration(cident(tn)) + t.print_declaration(tp.cident(tn)) out('\n') out('\n') - for (_, t) in TStruct.late_global_struct_defs: + for (_, t) in tp.Struct.late_global_struct_defs: t.print_struct_definition() out('\n') @@ -381,7 +384,7 @@ def generate_protofile(device): def get_attr_fname(node, port, group_prefix): port_prefix = port.attrname() + '_' if port else '' if node.objtype == 'register' and node.is_confidential(): - return port_prefix + get_anonymized_name(node) + return port_prefix + c.get_anonymized_name(node) else: return port_prefix + group_prefix + crep.cname(node) @@ -397,9 +400,9 @@ def generate_attr_setter(fname, node, port, dimsizes, cprefix, loopvars, out(crep.structtype(device)+' *_dev UNUSED = (' + crep.structtype(device)+'*)_portobj->dev;\n') index_array = mkLit(port.site, '_portobj->indices', - TPtr(TInt(32, False, const=True))) - port_indices = tuple(mkIndex(port.site, index_array, - mkIntegerLiteral(port.site, i)) + tp.Ptr(tp.Int(32, False, const=True))) + port_indices = tuple(c.mkIndex(port.site, index_array, + c.mkIntegerLiteral(port.site, i)) for i in range(port.dimensions)) else: out(crep.structtype(device)+' *_dev UNUSED = (' @@ -425,18 +428,18 @@ def generate_attr_setter(fname, node, port, dimsizes, cprefix, loopvars, out('attr_value_t attr%d = %s;\n' % (dim, list_item)) valuevar = 'attr%d' % (dim,) - with NoFailure(node.site), crep.DeviceInstanceContext(): + with codegen.NoFailure(node.site), crep.DeviceInstanceContext(): setcode = [ codegen_inline_byname( node, port_indices + loopvars, '_set_attribute' if dml.globals.dml_version == (1, 2) else 'set_attribute', - [mkLit(node.site, valuevar, TNamed('attr_value_t'))], - [mkLit(node.site, '_status', TNamed('set_error_t'))], + [mkLit(node.site, valuevar, tp.Named('attr_value_t'))], + [mkLit(node.site, '_status', tp.Named('set_error_t'))], node.site, inhibit_copyin = not loopvars)] - code = mkCompound(None, declarations(fscope) + setcode) + code = c.mkCompound(None, codegen.declarations(fscope) + setcode) code.toc_inline() if dimsizes: # abort on first bad value @@ -459,9 +462,9 @@ def generate_attr_getter(fname, node, port, dimsizes, cprefix, loopvars): out(crep.structtype(device)+' *_dev UNUSED = (' + crep.structtype(device)+'*)_portobj->dev;\n') index_array = mkLit(port.site, '_portobj->indices', - TPtr(TInt(32, False, const=True))) - port_indices = tuple(mkIndex(port.site, index_array, - mkIntegerLiteral(port.site, i)) + tp.Ptr(tp.Int(32, False, const=True))) + port_indices = tuple(c.mkIndex(port.site, index_array, + c.mkIntegerLiteral(port.site, i)) for i in range(port.dimensions)) else: out(crep.structtype(device)+' *_dev UNUSED = (' @@ -485,13 +488,13 @@ def generate_attr_getter(fname, node, port, dimsizes, cprefix, loopvars): out('attr_value_t %s;\n' % (next_valuevar.read())) valuevar = next_valuevar - with NoFailure(node.site), crep.DeviceInstanceContext(): + with codegen.NoFailure(node.site), crep.DeviceInstanceContext(): getcode = codegen_inline_byname( node, port_indices + loopvars, '_get_attribute' if dml.globals.dml_version == (1, 2) else 'get_attribute', [], [valuevar], node.site) - code = mkCompound(node.site, declarations(fscope) + [getcode]) + code = c.mkCompound(node.site, codegen.declarations(fscope) + [getcode]) code.toc_inline() for depth, loopvar in reversed(list(enumerate(loopvars))): @@ -506,15 +509,15 @@ def generate_attr_getter(fname, node, port, dimsizes, cprefix, loopvars): # dimsizes, loopvars, prefix are relative to port. def check_attribute(node, port, prefix): - config_param = param_str_fixup(node, 'configuration', 'none') + config_param = c.param_str_fixup(node, 'configuration', 'none') if config_param == 'none': return if not get_long_doc(node): if (node.objtype in {'attribute', 'connect'} and config_param == 'required'): - report(WNDOCRA(node, node.logname())) + report(W.NDOCRA(node, node.logname())) elif node.objtype != 'register': - report(WNDOC(node, node.logname())) + report(W.NDOC(node, node.logname())) attrname = get_attr_name(prefix, node) register_attribute(node.site, port, attrname) if port and need_port_proxy_attrs(port): @@ -526,12 +529,12 @@ def generate_attribute_common(initcode, node, port, dimsizes, prefix, assert dml.globals.dml_version == (1, 2) attrname = get_attr_name(prefix, node) - config_param = param_str_fixup(node, 'configuration', 'none') + config_param = c.param_str_fixup(node, 'configuration', 'none') if config_param == 'none': return for _ in node.arraylens(): - loopvars += (mkLit(None, '_i'+str(len(loopvars)+1), TInt(32, False)),) + loopvars += (mkLit(None, '_i'+str(len(loopvars)+1), tp.Int(32, False)),) dimsizes += node.arraylens() doc = get_long_doc(node) @@ -541,22 +544,22 @@ def generate_attribute_common(initcode, node, port, dimsizes, prefix, doc = 'register ' + node.logname_anonymized() elif (node.objtype in {'attribute', 'connect'} and config_param == 'required'): - report(WNDOCRA(node, node.logname())) + report(W.NDOCRA(node, node.logname())) doc = "Undocumented" else: - report(WNDOC(node, node.logname())) + report(W.NDOC(node, node.logname())) doc = "Undocumented" # append the required interfaces to the docstring if node.objtype == 'connect': ifaces = [i for i in node.get_components('interface') - if param_bool(i, 'required')] + if expr_util.param_bool(i, 'required')] if ifaces: doc += ( '\n\nRequired interfaces: ' + ', '.join('' + i.name + '' for i in ifaces) + '.') - doc = mkStringConstant(node.site, doc) + doc = c.mkStringConstant(node.site, doc) fname = get_attr_fname(node, port, prefix) @@ -606,7 +609,7 @@ def generate_attribute_common(initcode, node, port, dimsizes, prefix, register_attribute( node.site, None, "%s_%s" % (port.name, attrname)) member = crep.cref_portobj( - port, (mkLit(port.site, '0', TInt(32, False)),)) + port, (mkLit(port.site, '0', tp.Int(32, False)),)) (dimsize,) = port.dimsizes initcode.out( '_register_port_array_attr(class, %s, offsetof(%s, %s),' @@ -659,7 +662,7 @@ def generate_attributes(initcode, node, port=None, prefix += crep.cname(node) + '_' for _ in node.arraylens(): loopvars += (mkLit(None, '_i' + str(len(loopvars) + 1), - TInt(32, False)),) + tp.Int(32, False)),) dimsizes += node.arraylens() for child in children: @@ -689,9 +692,9 @@ def generate_subobj_connects(init_code, device, prefixes=("",)): t = dml.globals.traits['init_as_subobj'] for (parent, node) in find_connects(device, device): if t in node.traits.ancestors: - classname = mkStringConstant( + classname = c.mkStringConstant( None, param_str(node, 'classname')).quoted - desc = (mkStringConstant(None, param_str(node, "desc")).quoted + desc = (c.mkStringConstant(None, param_str(node, "desc")).quoted if param_defined(node, 'desc') else 'NULL') cls = port_class_ident(parent) for indices in itertools.product( @@ -703,8 +706,6 @@ def generate_subobj_connects(init_code, device, prefixes=("",)): f'_DML_register_subobj_connect({cls}, ' + f'{classname}, "{name}", {desc});\n') -def apply(f): - return f() @apply class PORTOBJ(object): """Marker that indicates that a method is wrapped for a port object, @@ -722,7 +723,7 @@ def wrap_method(meth, wrapper_name, indices=()): inparams = [p.declaration() for p in meth.inp] if not meth.outp: retvar = None - rettype = TVoid() + rettype = tp.Void() elif len(meth.outp) == 1: retvar, rettype = meth.outp[0] else: @@ -735,24 +736,24 @@ def wrap_method(meth, wrapper_name, indices=()): out('_port_object_t *_portobj = (_port_object_t *)_obj;\n') out(devstruct+' *_dev UNUSED = (' + devstruct + ' *)_portobj->dev;\n') index_array = mkLit(meth.site, '_portobj->indices', - TPtr(TInt(32, False, const=True))) - indices = tuple(mkIndex(meth.site, index_array, - mkIntegerLiteral(meth.site, i)) + tp.Ptr(tp.Int(32, False, const=True))) + indices = tuple(c.mkIndex(meth.site, index_array, + c.mkIntegerLiteral(meth.site, i)) for i in range(meth.dimensions)) else: assert meth.dimensions == len(indices) out(devstruct+' *_dev UNUSED = ('+devstruct+'*)_obj;\n') - indices = tuple(mkIntegerLiteral(meth.site, i) for i in indices) + indices = tuple(c.mkIntegerLiteral(meth.site, i) for i in indices) with crep.DeviceInstanceContext(): if retvar: - mkDeclaration(meth.site, retvar, rettype, - init = get_initializer(meth.site, rettype, + c.mkDeclaration(meth.site, retvar, rettype, + init = codegen.get_initializer(meth.site, rettype, None, None, None)).toc() - with LogFailure(meth.site, meth, indices): + with codegen.LogFailure(meth.site, meth, indices): inargs = [mkLit(meth.site, p.c_ident, p.typ) for p in meth.inp] outargs = [mkLit(meth.site, v, t) for v, t in meth.outp] - codegen_call(meth.site, meth, + codegen.codegen_call(meth.site, meth, indices, inargs, outargs).toc() output_dml_state_change('_dev') @@ -768,27 +769,27 @@ def generate_implement_method(device, ifacestruct, meth, indices): # codegen_method so it generates a function that returns # the value if there is a single output parameter. # - # meth.func.fail = IgnoreFailure() + # meth.func.fail = codegen.IgnoreFailure() # meth.func.confobj = 1 - # codegen_method(meth) + # codegen.codegen_method(meth) # out(meth.get_c()) try: - require_fully_typed(None, meth) + codegen.require_fully_typed(None, meth) # Calculate the expected method signature member_type = ifacestruct.get_member_qualified(meth.name) if not member_type: - raise EMEMBER(meth.site, meth.parent.name, meth.name) - member_type = safe_realtype(member_type) - if not isinstance(member_type, TPtr): - raise EIMPLMEMBER( + raise E.MEMBER(meth.site, meth.parent.name, meth.name) + member_type = tp.safe_realtype(member_type) + if not isinstance(member_type, tp.Ptr): + raise E.IMPLMEMBER( meth.site, f'{meth.parent.name}_interface_t.{meth.name}', ifacestruct.declaration_site) func_type = member_type.base - if not isinstance(func_type, TFunction): - raise EIMPLMEMBER(meth.site, + if not isinstance(func_type, tp.Function): + raise E.IMPLMEMBER(meth.site, f'{meth.parent.name}_interface_t.{meth.name}', ifacestruct.declaration_site) iface_input_types = func_type.input_types[1:] @@ -796,24 +797,24 @@ def generate_implement_method(device, ifacestruct, meth, indices): # Check the signature if len(meth.inp) != len(iface_input_types): - raise EMETH(meth.site, None, + raise E.METH(meth.site, None, 'different number of input parameters') if len(meth.outp) != iface_num_outputs: - raise EMETH(meth.site, None, + raise E.METH(meth.site, None, 'different number of output parameters') if func_type.varargs: # currently impossible to implement a varargs interface # method in DML - raise EMETH(meth.site, None, 'interface method is variadic') + raise E.METH(meth.site, None, 'interface method is variadic') for (mp, it) in zip(meth.inp, iface_input_types): - if not safe_realtype_unconst(mp.typ).eq(safe_realtype_unconst(it)): - raise EARGT(meth.site, 'implement', meth.name, + if not tp.safe_realtype_unconst(mp.typ).eq(tp.safe_realtype_unconst(it)): + raise E.ARGT(meth.site, 'implement', meth.name, mp.typ, mp.logref, it, 'method') if iface_num_outputs and dml.globals.dml_version != (1, 2): [(_, mt)] = meth.outp - if not safe_realtype_unconst(mt).eq( - safe_realtype_unconst(func_type.output_type)): - raise EARGT(meth.site, 'implement', meth.name, + if not tp.safe_realtype_unconst(mt).eq( + tp.safe_realtype_unconst(func_type.output_type)): + raise E.ARGT(meth.site, 'implement', meth.name, mt, '', func_type.output_type, 'method') if indices is PORTOBJ: @@ -836,7 +837,7 @@ def interface_block(device, ifacestruct, methods, indices = ()): # placeholder, so try placating it with a zero. return "{ 0 }" - indent = ' ' * indent_level + indent = ' ' * output.indent_level indent2 = indent * 2 return "{\n%s%s%s}" % ( indent2, @@ -858,12 +859,12 @@ def generate_implement(code, device, impl): typename = param_str(impl, 'c_type' if dml.globals.dml_version == (1, 2) else '_c_type') - ifacetype = TNamed(typename) + ifacetype = tp.Named(typename) ifacetype.declaration_site = impl.site - ifacestruct = safe_realtype(ifacetype) + ifacestruct = tp.safe_realtype(ifacetype) - if not isinstance(ifacestruct, (TStruct, TExternStruct)): - raise EIFTYPE(impl.site, ifacetype) + if not isinstance(ifacestruct, (tp.Struct, tp.ExternStruct)): + raise E.IFTYPE(impl.site, ifacetype) port = impl.parent assert port.objtype in {'port', 'bank', 'device', 'subdevice'} @@ -871,7 +872,7 @@ def generate_implement(code, device, impl): if not port.name: # anonymous bank assert dml.globals.dml_version == (1, 2) - raise EANONPORT(impl.site, port) + raise E.ANONPORT(impl.site, port) code.out("{\n", postindent = 1) if not port.parent: # device @@ -966,7 +967,7 @@ def generate_port_class(code, device, port): port, ('%d',) * port.dimensions) portclass_name_comps = [o.name_anonymized for o in node_ancestors(port, device)] - portclass_name_comps.append(param_str_fixup(device, 'classname', '')) + portclass_name_comps.append(c.param_str_fixup(device, 'classname', '')) portclass_name = '.'.join(reversed(portclass_name_comps)) desc = string_literal(get_short_doc(port)) doc = string_literal(get_long_doc(port)) @@ -1054,11 +1055,11 @@ def generate_simple_events(device): % (info.dimensions,))) if info.args_type: - args_decl = TPtr( - conv_const(True, info.args_type)).declaration('_args') - emergency_args_c_type = TArray( + args_decl = tp.Ptr( + tp.conv_const(True, info.args_type)).declaration('_args') + emergency_args_c_type = tp.Array( info.args_type, - mkIntegerConstant(None, 1, False)).declaration('') + c.mkIntegerConstant(None, 1, False)).declaration('') out('%s = data ? data->args : (%s) { 0 };\n' % (args_decl, emergency_args_c_type)) @@ -1111,7 +1112,7 @@ def generate_simple_events(device): def generate_after_on_hooks_artifacts(device): for info in dml.globals.after_on_hook_infos: - site = SimpleSite(f'after on hook {string_literal(info.string_key)}') + site = logging.SimpleSite(f'after on hook {string_literal(info.string_key)}') start_function_definition( f'void {info.cident_callback}(conf_object_t *_obj, ' @@ -1124,8 +1125,8 @@ def generate_after_on_hooks_artifacts(device): + '= _msg;\n') if info.args_type: - args_decl = TPtr( - conv_const(True, info.args_type)).declaration('args') + args_decl = tp.Ptr( + tp.conv_const(True, info.args_type)).declaration('args') out('%s = _args;\n' % (args_decl,)) indices_lit = 'indices' if info.dimensions else None args_lit = 'args' if info.args_type else None @@ -1140,13 +1141,13 @@ def generate_after_on_hooks_artifacts(device): + 'const void *_args)') out('{\n', postindent = 1) if info.args_type: - args_type_ptr = TPtr(conv_const(True, info.args_type)) + args_type_ptr = tp.Ptr(tp.conv_const(True, info.args_type)) out(f'{args_type_ptr.declaration("args")} = _args;\n') - args_expr = mkDereference(site, mkLit(site, 'args', args_type_ptr)) + args_expr = c.mkDereference(site, mkLit(site, 'args', args_type_ptr)) else: args_expr = None out('attr_value_t out;\n') - out_expr = mkLocalVariable( + out_expr = c.mkLocalVariable( site, LocalSymbol('out', 'out', attr_value_t, site=site)) info.generate_args_serializer(site, args_expr, out_expr) out('return out;\n') @@ -1160,18 +1161,18 @@ def generate_after_on_hooks_artifacts(device): out('set_error_t _success UNUSED = Sim_Set_Ok;\n') if info.args_type: - out(f'{TPtr(info.args_type).declaration("out")} = _out;\n') - out_expr = mkDereference(site, mkLit(site, 'out', - TPtr(info.args_type))) + out(f'{tp.Ptr(info.args_type).declaration("out")} = _out;\n') + out_expr = c.mkDereference(site, mkLit(site, 'out', + tp.Ptr(info.args_type))) else: out_expr = None def error_out(exc, msg): stmts = [] - stmts.append(mkInline(site, f'_success = {exc};')) + stmts.append(c.mkInline(site, f'_success = {exc};')) if msg is not None: stmts.append( - mkInline(site, f'SIM_attribute_error("{msg}");')) - stmts.append(mkInline(site, 'goto _exit;')) + c.mkInline(site, f'SIM_attribute_error("{msg}");')) + stmts.append(c.mkInline(site, 'goto _exit;')) return stmts val_expr = mkLit(site, 'val', attr_value_t) @@ -1220,8 +1221,8 @@ def generate_immediate_after_callbacks(device): + crep.structtype(device) + '*)_obj;\n') if info.args_type: - args_decl = TPtr( - conv_const(True, info.args_type)).declaration('args') + args_decl = tp.Ptr( + tp.conv_const(True, info.args_type)).declaration('args') out('%s = _args;\n' % (args_decl,)) indices_lit = 'indices' if info.dimensions else None args_lit = 'args' if info.args_type else None @@ -1268,7 +1269,7 @@ def generate_simple_events_control_methods(device): out(f'for (uint32 _i{i} = 0; _i{i} < {dims[i]}; _i{i}++) {{\n', postindent=1) - indices = tuple(mkLit(site, f'_i{i}', TInt(32, False)) + indices = tuple(mkLit(site, f'_i{i}', tp.Int(32, False)) for i in range(len(dims))) for hook in hooks: out('_DML_cancel_afters_in_hook_queue(' @@ -1357,22 +1358,22 @@ def generate_reg_callback(meth, name): dev_t = crep.structtype(dml.globals.device) out('static bool\n') params = [p.declaration() for p in meth.inp] + [ - TPtr(t).declaration(p) for p, t in meth.outp] + tp.Ptr(t).declaration(p) for p, t in meth.outp] out('%s(void *_obj, const uint16 *indices, ' % (name,) + ', '.join(params) + ')\n') out('{\n', postindent = 1) out('%s *_dev = _obj;\n' % dev_t) - fail = ReturnFailure(meth.site) + fail = codegen.ReturnFailure(meth.site) with fail, crep.DeviceInstanceContext(): inargs = [mkLit(meth.site, p.c_ident, p.typ) for p in meth.inp] outargs = [mkLit(meth.site, "*" + n, t) for n, t in meth.outp] - code = [codegen_call( + code = [codegen.codegen_call( meth.site, meth, - tuple(mkLit(meth.site, 'indices[%d]' % i, TInt(32, False)) + tuple(mkLit(meth.site, 'indices[%d]' % i, tp.Int(32, False)) for i in range(meth.dimensions)), inargs, outargs)] - mkCompound(meth.site, code + [fail.nofail()]).toc_inline() + c.mkCompound(meth.site, code + [fail.nofail()]).toc_inline() out('}\n', preindent = -1) out('\n') @@ -1396,8 +1397,8 @@ def generate_register_tables(device): len(dims), '_DML_MI_%s' % crep.cref_method(getter), '_DML_MI_%s' % crep.cref_method(setter))) - mark_method_referenced(method_instance(getter)) - mark_method_referenced(method_instance(setter)) + codegen.mark_method_referenced(codegen.method_instance(getter)) + codegen.mark_method_referenced(codegen.method_instance(setter)) regidxs[r] = i i += 1 out('// Register tables for %s\n' % bank.name) @@ -1530,14 +1531,14 @@ def generate_hook_auxiliary_info_array(): offset = ('offsetof(%s, %s)' % (crep.structtype(dml.globals.device), crep.cref_hook( - hook, (mkIntegerConstant(hook.site, 0, False),) + hook, (c.mkIntegerConstant(hook.site, 0, False),) * hook.dimensions))) try: - typeseq_uniq = get_type_sequence_info( + typeseq_uniq = codegen.get_type_sequence_info( hook.msg_types, create_new=True).uniq items.append('{%s, %d, %d}' % (offset, typeseq_uniq, hook.uniq)) - except DMLUnkeyableType: + except tp.DMLUnkeyableType: pass # already reported if objects.Device.hooks: init = '{\n%s\n}' % (',\n'.join(f' {item}' for item in items),) @@ -1586,11 +1587,11 @@ def generate_initialize(device): stmts = [] for method_name in ['init', 'hard_reset']: method = device.get_component(method_name, 'method') - with InitFailure(method.site): - stmts.append(codegen_call_byname( + with codegen.InitFailure(method.site): + stmts.append(codegen.codegen_call_byname( method.site, device, (), method_name, [], [])) - mkCompound(device.site, stmts).toc() + c.mkCompound(device.site, stmts).toc() else: codegen_inline_byname(device, (), '_init', [], [], device.site).toc() @@ -1620,7 +1621,7 @@ def generate_finalize(device): # Functions called from new_instance shouldn't throw any # exceptions. But we don't want to force them to insert try-catch # in the init method. - with LogFailure( + with codegen.LogFailure( device.get_component('post_init', 'method').site, device, ()): code = codegen_inline_byname(device, (), 'post_init', [], [], @@ -1675,11 +1676,11 @@ def generate_pre_delete(device): out(f'for (uint32 _i{i} = 0; _i{i} < {dims[i]}; _i{i}++) {{\n', postindent=1) - indices = tuple(mkLit(device.site, f'_i{i}', TInt(32, False)) + indices = tuple(mkLit(device.site, f'_i{i}', tp.Int(32, False)) for i in range(len(dims))) for event in events: method = event.get_component('_cancel_all', 'method') - codegen_inline(method.site, method, indices, [], []).toc() + codegen.codegen_inline(method.site, method, indices, [], []).toc() for i in range(len(dims)): out('}\n', preindent=-1) @@ -1722,7 +1723,7 @@ def generate_deinit(device): out(f'for (uint32 _i{i} = 0; _i{i} < {dims[i]}; _i{i}++) {{\n', postindent=1) - indices = tuple(mkLit(device.site, f'_i{i}', TInt(32, False)) + indices = tuple(mkLit(device.site, f'_i{i}', tp.Int(32, False)) for i in range(len(dims))) for hook in hooks: out('_DML_free_hook_queue(' @@ -1754,8 +1755,8 @@ def generate_reset(device, hardness): + crep.structtype(device) + ' *)_obj;\n\n') method_name = hardness + '_reset' method = device.get_component(method_name, 'method') - with LogFailure(method.site, device, ()), crep.DeviceInstanceContext(): - code = codegen_call_byname(method.site, device, (), + with codegen.LogFailure(method.site, device, ()), crep.DeviceInstanceContext(): + code = codegen.codegen_call_byname(method.site, device, (), method_name, [], []) code.toc_inline() out('}\n\n', preindent = -1) @@ -1771,11 +1772,11 @@ def get_index_enumeration(site, dimsizes: tuple): lower = dimsizes[1:] _index_enumeration_pool[lower] = max(dimsizes[0], _index_enumeration_pool.get(lower, 0)) - t = TArray(TInt(32, False, const=True), - mkIntegerLiteral(site, len(dimsizes))) + t = tp.Array(tp.Int(32, False, const=True), + c.mkIntegerLiteral(site, len(dimsizes))) for dim in lower[::-1]: - t = TArray(t, mkIntegerLiteral(site, dim)) - return mkLit(site, '_indices_%s' % ('_'.join(map(str, lower))), TPtr(t)) + t = tp.Array(t, c.mkIntegerLiteral(site, dim)) + return mkLit(site, '_indices_%s' % ('_'.join(map(str, lower))), tp.Ptr(t)) def generate_index_enumerations(): def index_enumeration(dimsizes): @@ -1815,13 +1816,13 @@ def tuple_as_uint32_array(site, numbers, hint): assert isinstance(numbers, tuple) if not numbers: - return mkLit(site, 'NULL', TPtr(TVoid())) + return mkLit(site, 'NULL', tp.Ptr(tp.Void())) if numbers not in _int_tuple_pool: suffix = '%d_%s' % (len(_int_tuple_pool), hint) _int_tuple_pool[numbers] = suffix return mkLit(site, '_tuple%s' % (_int_tuple_pool[numbers],), - TArray(TInt(32, False, const=True), - mkIntegerLiteral(site, len(numbers)))) + tp.Array(tp.Int(32, False, const=True), + c.mkIntegerLiteral(site, len(numbers)))) def generate_tuple_table(): global _int_tuple_pool @@ -1851,7 +1852,7 @@ def generate_init_port_objs(device): fmtargs = ''.join(f', _i{i}' for i in range(port.dimensions)) out(f'strbuf_t portname = sb_newf("{portname}"{fmtargs});\n') loop_indices = tuple( - mkLit(port.site, '_i%d' % i, TInt(32, False)) + mkLit(port.site, '_i%d' % i, tp.Int(32, False)) for i in range(port.dimensions)) index_array = "%s%s" % ( index_enumeration.read(), @@ -1897,29 +1898,29 @@ def generate_init_data_objs(device): try: # only data/method obj assert not node.isindexed() - init = eval_initializer( + init = codegen.eval_initializer( node.site, node._type, node.astinit, - Location(node.parent, static_indices(node)), + c.Location(node.parent, static_indices(node)), global_scope, True) # mainly meant to capture EIDXVAR; for other errors, the error will # normally re-appear when evaluating per instance except DMLError: - with allow_linemarks(): + with output.allow_linemarks(): for indices in node.all_indices(): - index_exprs = tuple(mkIntegerLiteral(node.site, i) + index_exprs = tuple(c.mkIntegerLiteral(node.site, i) for i in indices) - nref = mkNodeRef(node.site, node, index_exprs) + nref = c.mkNodeRef(node.site, node, index_exprs) try: - init = eval_initializer( + init = codegen.eval_initializer( node.site, node._type, node.astinit, - Location(node.parent, index_exprs), + c.Location(node.parent, index_exprs), global_scope, True) except DMLError as e: report(e) else: markers = ([('store_writes_const_field', 'FALSE')] - if deep_const(node._type) else []) - coverity_markers(markers, init.site) + if tp.deep_const(node._type) else []) + output.coverity_markers(markers, init.site) out(init.assign_to(nref.read(), node._type) + ';\n') else: index_exprs = () @@ -1928,12 +1929,12 @@ def generate_init_data_objs(device): out(('for (int %s = 0; %s < %s; ++%s) {\n' % (var, var, sz, var)), postindent=1) - index_exprs += (mkLit(node.site, var, TInt(64, True)),) - nref = mkNodeRef(node.site, node, index_exprs) - with allow_linemarks(): + index_exprs += (mkLit(node.site, var, tp.Int(64, True)),) + nref = c.mkNodeRef(node.site, node, index_exprs) + with output.allow_linemarks(): markers = ([('store_writes_const_field', 'FALSE')] - if deep_const(node._type) else []) - coverity_markers(markers, init.site) + if tp.deep_const(node._type) else []) + output.coverity_markers(markers, init.site) out(init.assign_to(nref.read(), node._type) + ';\n') for _ in range(node.dimensions): out('}\n', postindent=-1) @@ -1953,11 +1954,11 @@ def generate_init(device, initcode, outprefix): doc = get_long_doc(device) if doc == None: doc = device.name + ' device' - doc = mkStringConstant(device.site, doc) + doc = c.mkStringConstant(device.site, doc) sdoc = get_short_doc(device) if sdoc: - sdoc = mkStringConstant(device.site, sdoc) + sdoc = c.mkStringConstant(device.site, sdoc) #banks = device.get_components('bank') @@ -1979,15 +1980,15 @@ def generate_init(device, initcode, outprefix): if sdoc: out('.short_desc = '+sdoc.read()+',\n') else: - report(WNSHORTDESC(device.site)) + report(W.NSHORTDESC(device.site)) out('};\n', preindent = -1) out('\n') out('conf_class_t *class = SIM_create_class("' - + param_str_fixup(device, 'classname', '') + '", &funcs);\n') + + c.param_str_fixup(device, 'classname', '') + '", &funcs);\n') out('_dev_class = class;\n') out('if (SIM_clear_exception() != SimExc_No_Exception) {\n', postindent = 1) out('fprintf(stderr, "Failed to register class ' - + param_str_fixup(device, 'classname', '') + + c.param_str_fixup(device, 'classname', '') + ': %s\\n", SIM_last_error());\n') out('return NULL;\n') out('}\n', preindent = -1) @@ -2057,8 +2058,8 @@ def generate_extern_trampoline(exported_name, func): cparams = list(func.cparams) if not func.independent: cparams[0] = ( - '_obj', TPtr(TNamed("conf_object_t")), - TPtr(TNamed("conf_object_t")).declaration('_obj')) + '_obj', tp.Ptr(tp.Named("conf_object_t")), + tp.Ptr(tp.Named("conf_object_t")).declaration('_obj')) params_string = ('void' if not cparams else ", ".join( decl for (_, _, decl) in cparams)) out("extern %s\n" % (func.rettype.declaration( @@ -2083,7 +2084,7 @@ def generate_extern_trampoline_dml12(exported_name, func): def generate_each_in_table(trait, instances): items = [] for (node, subnodes) in instances: - ident = EachIn.index_ident(node, trait) + ident = c.EachIn.index_ident(node, trait) if subnodes: add_variable_declaration(f'const uint32 {ident}', str(len(items))) @@ -2093,12 +2094,12 @@ def generate_each_in_table(trait, instances): ancestry_path = sub.traits.ancestry_paths[trait][0] base = '&%s%s' % ( sub.traits.vtable_cname(ancestry_path[0]), - ''.join('.' + cident(t.name) + ''.join('.' + tp.cident(t.name) for t in ancestry_path[1:])) num = reduce(operator.mul, sub.dimsizes, 1) uniq = sub.uniq items.append("{%s, %d, %d}" % (base, num, uniq)) - arrayname = EachIn.array_ident(trait) + arrayname = c.EachIn.array_ident(trait) if items: init = '{\n%s\n}' % (',\n'.join(f' {item}' for item in items),) add_variable_declaration( @@ -2113,7 +2114,7 @@ def generate_each_in_table(trait, instances): def generate_each_in_tables(): by_trait = {} - for ((node, trait), subobjs) in list(EachIn.instances.items()): + for ((node, trait), subobjs) in list(c.EachIn.instances.items()): by_trait.setdefault(trait, []).append((node, subobjs)) for t in by_trait: generate_each_in_table(t, by_trait[t]) @@ -2122,7 +2123,7 @@ def generate_each_in_tables(): # when dereferencing sequence params, these methods reference # the base array. add_variable_declaration( - f'const _vtable_list_t *const {EachIn.array_ident(t)}', 'NULL') + f'const _vtable_list_t *const {c.EachIn.array_ident(t)}', 'NULL') def generate_trait_deserialization_hashtables(device): inserts = [] @@ -2131,15 +2132,15 @@ def generate_trait_deserialization_hashtables(device): if trait.empty() or trait is dml.globals.object_trait: continue add_variable_declaration('ht_int_table_t ' - + f'_{cident(trait.name)}_vtable_ht', + + f'_{tp.cident(trait.name)}_vtable_ht', 'HT_INT_NULL()') for node in dml.globals.trait_instances.get(trait, ()): node.traits.mark_referenced(trait) ancestry_path = node.traits.ancestry_paths[trait][0] structref = node.traits.vtable_cname(ancestry_path[0]) pointer = '(&%s)' % ('.'.join([structref] + [ - cident(t.name) for t in ancestry_path[1:]])) - inserts.append(f'ht_insert_int(&_{cident(trait.name)}_vtable_ht, ' + tp.cident(t.name) for t in ancestry_path[1:]])) + inserts.append(f'ht_insert_int(&_{tp.cident(trait.name)}_vtable_ht, ' + f'{node.uniq}, {pointer});\n') start_function_definition('void _initialize_vtable_hts(void)') @@ -2156,7 +2157,7 @@ def generate_object_vtables_array(): ancestry_path = node.traits.ancestry_paths[dml.globals.object_trait][0] structref = node.traits.vtable_cname(ancestry_path[0]) pointer = '(&%s)' % ('.'.join([structref] + [ - cident(t.name) for t in ancestry_path[1:]])) + tp.cident(t.name) for t in ancestry_path[1:]])) else: pointer = 'NULL' items.append(pointer) @@ -2194,24 +2195,24 @@ def generate_trait_method(m): code = m.codegen_body() out('/* %s */\n' % (str(m),)) start_function_definition(m.declaration()) - with allow_linemarks(): - site_linemark(m.astbody.site) + with output.allow_linemarks(): + output.site_linemark(m.astbody.site) out('{\n', postindent=1) code.toc_inline() - site_linemark(m.rbrace_site) + output.site_linemark(m.rbrace_site) out('}\n', preindent=-1) def generate_adjustor_thunk(traitname, name, inp, outp, throws, independent, vtable_path, def_path, hardcoded_impl=None): generated_name = "__adj_%s__%s__%s" % ( traitname, '__'.join(t.name for t in vtable_path), name) - rettype = c_rettype(outp, throws) + rettype = codegen.c_rettype(outp, throws) out('static ' + rettype.declaration('\n%s' % (generated_name,))) vtable_trait = vtable_path[-1] assert vtable_trait is def_path[-1] implicit_inargs = vtable_trait.implicit_args() preargs = crep.maybe_dev_arg(independent) + implicit_inargs - inargs = [(p.c_ident, p.typ) for p in inp] + c_extra_inargs(outp, throws) + inargs = [(p.c_ident, p.typ) for p in inp] + codegen.c_extra_inargs(outp, throws) out('(%s)\n{\n' % (", ".join(t.declaration(n) for (n, t) in (preargs + inargs))), postindent=1) @@ -2219,13 +2220,13 @@ def generate_adjustor_thunk(traitname, name, inp, outp, throws, independent, [(vt_name, vtable_trait_type)] = implicit_inargs assert vtable_trait_type.trait is vtable_trait out('%s.trait = &((struct _%s *) DOWNCAST(%s, %s, %s).trait)->%s;\n' % ( - vt_name, cident(traitname), vt_name, cident(traitname), - '.'.join(cident(t.name) for t in vtable_path), - '.'.join(cident(t.name) for t in def_path))) + vt_name, tp.cident(traitname), vt_name, tp.cident(traitname), + '.'.join(tp.cident(t.name) for t in vtable_path), + '.'.join(tp.cident(t.name) for t in def_path))) if not rettype.void: out('return ') fun = hardcoded_impl or ('((struct _%s *) %s.trait)->%s' - % (cident(vtable_trait.name), vt_name, name)) + % (tp.cident(vtable_trait.name), vt_name, name)) out('%s(%s);\n' % (fun, ", ".join(['_dev'] * (not independent) + [vt_name] + [name for (name, _) in inargs]))) out('}\n', preindent=-1) @@ -2361,14 +2362,14 @@ def method_tinit_arg(trait, parent, name, scrambled_name): return thunk def print_vtable_struct_declaration(trait): - out('struct _%s {\n' % cident(trait.name), postindent=1) + out('struct _%s {\n' % tp.cident(trait.name), postindent=1) for p in trait.direct_parents: - out("struct _%s %s;\n" % (cident(p.name), cident(p.name))) + out("struct _%s %s;\n" % (tp.cident(p.name), tp.cident(p.name))) for (name, (_, ptype)) in list(trait.vtable_params.items()): - if isinstance(realtype(ptype), TTraitList): + if isinstance(tp.realtype(ptype), tp.TraitList): out(f"_each_in_param_t {name};\n") else: - out(f'{TPtr(ptype).declaration(name)};\n') + out(f'{tp.Ptr(ptype).declaration(name)};\n') for name in trait.vtable_sessions: out(f'uint32 {name};\n') # device struct offset for name in trait.vtable_hooks: @@ -2379,7 +2380,7 @@ def print_vtable_struct_declaration(trait): out(f'{t.declaration(name)};\n') for (name, memo_outs_struct) in trait.vtable_memoized_outs.items(): - decl = TPtr(memo_outs_struct).declaration(name) + decl = tp.Ptr(memo_outs_struct).declaration(name) out(f'{decl};\n') out('};\n', preindent=-1) @@ -2433,12 +2434,12 @@ def scramble_argname(name): args.append(method_tinit_arg(trait, parent, name, scrambled_name)) tinit_calls.append("_tinit_%s(%s);\n" % ( - parent.name, ", ".join(['&_ret->' + cident(parent.name)] + parent.name, ", ".join(['&_ret->' + tp.cident(parent.name)] + args))) out('static void __attribute__((optimize("O0")))\n') out('_tinit_%s(struct _%s *_ret' % (trait.name, - cident(trait.name))) + tp.cident(trait.name))) inargs = tinit_args(trait) for name in inargs: scrambled_name = scramble_argname(name) @@ -2452,10 +2453,10 @@ def scramble_argname(name): out(', %s' % (mtype.declaration(scrambled_name),)) elif member_kind == 'parameter': (site, typ) = vtable_trait.vtable_params[name] - if isinstance(realtype(typ), TTraitList): + if isinstance(tp.realtype(typ), tp.TraitList): out(f', _each_in_param_t {scrambled_name}') else: - out(f', {TPtr(typ).declaration(scrambled_name)}') + out(f', {tp.Ptr(typ).declaration(scrambled_name)}') elif member_kind == 'session': out(', uint32 %s' % (scrambled_name)) # device struct offset elif member_kind == 'hook': @@ -2463,11 +2464,11 @@ def scramble_argname(name): else: assert member_kind == 'memoized_outs' memo_outs_struct = vtable_trait.vtable_memoized_outs[name] - out(f', {TPtr(memo_outs_struct).declaration(scrambled_name)}') + out(f', {tp.Ptr(memo_outs_struct).declaration(scrambled_name)}') out(')\n{\n', postindent=1) if initializers: - out('*_ret = (struct _%s){\n' % (cident(trait.name),), + out('*_ret = (struct _%s){\n' % (tp.cident(trait.name),), postindent=1) for initializer in initializers: out("%s,\n" % (initializer,)) @@ -2505,11 +2506,11 @@ def tinit_arg(self, varname): pass class SingleParamValue(ParamValue): # evaluates to the parameter value value: str - ptype: DMLType + ptype: tp.DMLType def tinit_arg(self): - if deep_const(self.ptype): - k = TArray(self.ptype, - mkIntegerLiteral(logging.SimpleSite( + if tp.deep_const(self.ptype): + k = tp.Array(self.ptype, + c.mkIntegerLiteral(logging.SimpleSite( ""), 1)).declaration("") size = f'sizeof({self.ptype.declaration("")})' return f'memcpy(malloc({size}), ({k}) {{ {self.value} }}, {size})' @@ -2540,21 +2541,21 @@ def tinit_arg(self): class ArrayParamValue(IndexedParamValue): # evaluates to the value in one value : str - ptype : DMLType + ptype : tp.DMLType node : objects.DMLObject def decl(self, var): array_type = self.ptype for d in reversed(self.node.dimsizes): - array_type = TArray(array_type, - mkIntegerLiteral(self.node.site, d)) - return (f'{TPtr(array_type).declaration(var)} = malloc(' + array_type = tp.Array(array_type, + c.mkIntegerLiteral(self.node.site, d)) + return (f'{tp.Ptr(array_type).declaration(var)} = malloc(' f'sizeof(*{var}));\n') def init(self, var): param_indices = ''.join(f'[{i}]' for i in self.indexvars(self.node)) - if deep_const(self.ptype): + if tp.deep_const(self.ptype): # partially const values requires memcpy for # initialization - k = (TArray(self.ptype, mkIntegerLiteral(self.node.site, 1)) + k = (tp.Array(self.ptype, c.mkIntegerLiteral(self.node.site, 1)) .declaration("")) target = f'(void *)&(*{var}){param_indices}' source = f'({k}) {{ {self.value} }}' @@ -2589,7 +2590,7 @@ def tinit_arg(self, var): def init_trait_vtable(node, trait, param_overrides): method_overrides = node.traits.method_overrides - # List of strings with the arguments passed to the _tinit_* function + # c.List of strings with the arguments passed to the _tinit_* function args = [] # Sometimes, the vtable of an object array has one or more # arguments that must be initialized by evaluating an expression @@ -2629,7 +2630,7 @@ def init_trait_vtable(node, trait, param_overrides): crep.structtype(dml.globals.device), crep.cref_session( session_node, - (mkIntegerConstant(node.site, 0, False),) + (c.mkIntegerConstant(node.site, 0, False),) * node.dimensions))) elif member_kind == 'hook': hook_node = node.get_component(name) @@ -2640,7 +2641,7 @@ def init_trait_vtable(node, trait, param_overrides): typ = trait.vtable_trait(name).vtable_memoized_outs[name] if node.dimensions: for d in reversed(node.dimsizes): - typ = TArray(typ, mkIntegerLiteral(node.site, d)) + typ = tp.Array(typ, c.mkIntegerLiteral(node.site, d)) arg = f'calloc(1, sizeof({typ.declaration("")}))' else: arg = f'({{static {typ.declaration("_tmp")}; &_tmp; }})' @@ -2702,22 +2703,22 @@ def generate_init_trait_vtables(node, param_values): splitting_point() def trait_param_value(node, param_type_site, param_type): - is_sequence = isinstance(realtype(param_type), TTraitList) + is_sequence = isinstance(tp.realtype(param_type), tp.TraitList) try: try: expr = node.get_expr(static_indices(node)) if isinstance(expr, NonValue): raise expr.exc() - expr = source_for_assignment(expr.site, param_type, expr) - except EIDXVAR: - indices = tuple(mkLit(node.site, v, TInt(32, False)) + expr = c.source_for_assignment(expr.site, param_type, expr) + except E.IDXVAR: + indices = tuple(mkLit(node.site, v, tp.Int(32, False)) for v in IndexedParamValue.indexvars(node)) expr = node.get_expr(indices) if isinstance(expr, NonValue): raise expr.exc() - expr = source_for_assignment(expr.site, param_type, expr) + expr = c.source_for_assignment(expr.site, param_type, expr) if is_sequence: - if (isinstance(expr, EachIn) + if (isinstance(expr, c.EachIn) and expr.node is node.parent and expr.indices == indices[:node.dimensions]): (subobjs, base_idx, num, array_idx, @@ -2731,7 +2732,7 @@ def trait_param_value(node, param_type_site, param_type): return ArrayParamValue(expr.read(), param_type, node) else: if is_sequence: - assert isinstance(expr, EachIn), repr(expr) + assert isinstance(expr, c.EachIn), repr(expr) (subobjs, base_idx, num, array_idx, array_size) = expr.each_in_t_members() expr.mark_referenced(subobjs) @@ -2754,13 +2755,13 @@ def resolve_trait_param_values(node): def generate_trait_trampoline(method, vtable_trait): implicit_inargs = vtable_trait.implicit_args() - extra_inargs = c_extra_inargs(method.outp, method.throws) + extra_inargs = codegen.c_extra_inargs(method.outp, method.throws) inparams = ", ".join([t.declaration(n) for (n, t) in (crep.maybe_dev_arg(method.independent) + implicit_inargs)] + [p.declaration() for p in method.inp] + [t.declaration(n) for (n, t) in extra_inargs]) - rettype = c_rettype(method.outp, method.throws) + rettype = codegen.c_rettype(method.outp, method.throws) # guaranteed to exist; created by ObjTraits.mark_referenced func = method.funcs[None] @@ -2778,11 +2779,11 @@ def generate_trait_trampoline(method, vtable_trait): indices = [ mkLit(site, '((_flat_index / %d) %% %d)' % ( reduce(operator.mul, obj.dimsizes[dim + 1:], 1), - obj.dimsizes[dim]), TInt(32, False)) + obj.dimsizes[dim]), tp.Int(32, False)) for dim in range(obj.dimensions)] args = ([mkLit(site, p.c_ident, p.typ) for p in method.inp] + [mkLit(site, n, t) for (n, t) in extra_inargs]) - call_expr = mkcall_method(site, func, indices)(args) + call_expr = codegen.mkcall_method(site, func, indices)(args) if not rettype.void: out('return ') out('%s;\n' % call_expr.read()) @@ -2807,7 +2808,7 @@ def generate_vtable_instances(devnode): for trait in subnode.traits.referenced: add_variable_declaration( 'struct _%s %s' - % (cident(trait.name), subnode.traits.vtable_cname(trait))) + % (tp.cident(trait.name), subnode.traits.vtable_cname(trait))) def calculate_saved_userdata(node, dimsizes, attr_name, sym_spec = None): if node.objtype == 'method': @@ -2816,18 +2817,18 @@ def calculate_saved_userdata(node, dimsizes, attr_name, sym_spec = None): decl_site = sym.site # Reference the first index of this # static variable - var_ref = mkStaticVariable(node.site, sym) + var_ref = c.mkStaticVariable(node.site, sym) for _ in range(node.dimensions): - var_ref = mkIndex(decl_site, var_ref, - mkIntegerConstant(decl_site, 0, False)) + var_ref = c.mkIndex(decl_site, var_ref, + c.mkIntegerConstant(decl_site, 0, False)) device_member = sym.value elif node.objtype == 'saved': assert sym_spec is None decl_site = node.site # Reference the first struct member of this # saved variable - loop_vars = (mkIntegerConstant(decl_site, 0, False),) * node.dimensions - var_ref = mkNodeRef(node.site, node, loop_vars) + loop_vars = (c.mkIntegerConstant(decl_site, 0, False),) * node.dimensions + var_ref = c.mkNodeRef(node.site, node, loop_vars) device_member = crep.cref_session(node, loop_vars) else: assert False @@ -2863,18 +2864,18 @@ def generate_saved_userdata(node, dimensions, prefix): try: yield calculate_saved_userdata(child, dimensions, prefix + child.ident) - except ESERIALIZE as e: + except E.SERIALIZE as e: report(e) elif child.objtype == 'method': # if the method is not generated, the variable is dead and # we dont have to bother - if child in saved_method_variables: - for sym_spec in saved_method_variables[child]: + if child in codegen.saved_method_variables: + for sym_spec in codegen.saved_method_variables[child]: try: yield calculate_saved_userdata( child, dimensions, prefix + child.ident, sym_spec) - except ESERIALIZE as e: + except E.SERIALIZE as e: report(e) elif (isinstance(child, objects.CompositeObject) and child.objtype not in {'bank', 'port', 'subdevice'}): @@ -2882,7 +2883,7 @@ def generate_saved_userdata(node, dimensions, prefix): assert (dml.globals.dml_version == (1, 2) and child.objtype == 'field') if (child.get_recursive_components('saved') - or any(meth in saved_method_variables + or any(meth in codegen.saved_method_variables for meth in child.get_recursive_components('method'))): raise ICE(child.site, @@ -3161,33 +3162,33 @@ def generate_startup_trait_calls(data, idxvars): (node, traits) = data site = node.site - indices = tuple(mkLit(site, idx, TInt(32, False)) for idx in idxvars) + indices = tuple(mkLit(site, idx, tp.Int(32, False)) for idx in idxvars) out('{\n', postindent=1) out('_traitref_t _tref;\n') for (trait, trait_methods) in traits.items(): - ref = ObjTraitRef(site, node, trait, indices) + ref = c.ObjTraitRef(site, node, trait, indices) out(f'_tref = {ref.read()};\n') for method in trait_methods: - outargs = [mkDiscardRef(method.site) for _ in method.outp] + outargs = [c.mkDiscardRef(method.site) for _ in method.outp] - method_ref = TraitMethodDirect( - method.site, mkLit(method.site, '_tref', TTrait(trait)), method) - with IgnoreFailure(site): - codegen_call_traitmethod(method.site, method_ref, [], + method_ref = c.TraitMethodDirect( + method.site, mkLit(method.site, '_tref', tp.Trait(trait)), method) + with codegen.IgnoreFailure(site): + codegen.codegen_call_traitmethod(method.site, method_ref, [], outargs).toc() out('}\n', preindent=-1) def generate_startup_regular_call(method, idxvars): site = method.site - indices = tuple(mkLit(site, idx, TInt(32, False)) for idx in idxvars) - outargs = [mkDiscardRef(method.site) for _ in method.outp] + indices = tuple(mkLit(site, idx, tp.Int(32, False)) for idx in idxvars) + outargs = [c.mkDiscardRef(method.site) for _ in method.outp] # startup memoized methods can throw, which is ignored during startup. # Memoization of the throw then allows for the user to check whether # or not the method did throw during startup by calling the method # again. - with IgnoreFailure(site): - codegen_call(method.site, method, indices, [], outargs).toc() + with codegen.IgnoreFailure(site): + codegen.codegen_call(method.site, method, indices, [], outargs).toc() def generate_startup_calls_entry_function(devnode): start_function_definition('void _startup_calls(void)') @@ -3233,9 +3234,9 @@ def generate_startup_calls_entry_function(devnode): out('}\n', preindent=-1) -class MultiFileOutput(FileOutput): +class MultiFileOutput(output.FileOutput): def __init__(self, stem, header): - FileOutput.__init__(self, stem + '-0.c') + output.FileOutput.__init__(self, stem + '-0.c') self.stem = stem self.header = header self.index = 0 @@ -3304,7 +3305,7 @@ def generate_cfile(device, footers, if c_split_threshold: c_file = MultiFileOutput(filename_prefix, c_top) else: - c_file = FileOutput(filename_prefix + '.c') + c_file = output.FileOutput(filename_prefix + '.c') c_file.out(c_top) with c_file, device.use_for_codegen(): generate_cfile_body(device, footers, full_module, filename_prefix) @@ -3316,7 +3317,7 @@ def generate_cfile(device, footers, def generate_cfile_body(device, footers, full_module, filename_prefix): # An output buffer for code that should be included in the init function - init_code = StrOutput() + init_code = output.StrOutput() init_code.out('', postindent=1) # The marker must be generated before any lines annotated with #line @@ -3368,7 +3369,7 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): for t in list(dml.globals.traits.values()): for m in list(t.method_impls.values()): if gather_size_statistics: - ctx = StrOutput(filename=output.current().filename, + ctx = output.StrOutput(filename=output.current().filename, lineno=output.current().lineno) with ctx: generate_trait_method(m) @@ -3376,15 +3377,15 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): out(ctx.buf) else: generate_trait_method(m) - # Note: methods may be added to method_queue while doing this, + # Note: methods may be added to codegen.method_queue while doing this, # so don't try to be too smart generated_funcs = set() - while method_queue: - func = method_queue.pop() + while codegen.method_queue: + func = codegen.method_queue.pop() if func in generated_funcs: continue generated_funcs.add(func) - code = codegen_method_func(func) + code = codegen.codegen_method_func(func) specializations = [(p.ident, 'undefined' if undefined(p.expr) else p.expr.value) @@ -3392,11 +3393,11 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): if p.ident is not None and p.expr is not None] if gather_size_statistics: - ctx = StrOutput(lineno=output.current().lineno, + ctx = output.StrOutput(lineno=output.current().lineno, filename=output.current().filename) else: ctx = nullcontext() - with ErrorContext(func.method), ctx: + with logging.ErrorContext(func.method), ctx: if specializations: out('/* %s\n' % func.get_name()) for (n, v) in specializations: @@ -3406,8 +3407,8 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): out('/* %s */\n' % func.get_name()) start_function_definition(func.prototype) - with allow_linemarks(): - site_linemark(func.method.astcode.site) + with output.allow_linemarks(): + output.site_linemark(func.method.astcode.site) out('{\n', postindent=1) try: code.toc_inline() @@ -3417,7 +3418,7 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): # codegen_method, when all Expression and Statement # objects are instantiated. raise ICE(e.site, 'error during late compile stage') - site_linemark(func.method.rbrace_site) + output.site_linemark(func.method.rbrace_site) out('}\n', preindent=-1) out('\n') if gather_size_statistics: @@ -3458,10 +3459,10 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): # and generate_simple_events generate_serialize(device) - for func in statically_exported_methods: + for func in codegen.statically_exported_methods: generate_static_trampoline(func) - for (name, (func, export_site)) in list(exported_methods.items()): + for (name, (func, export_site)) in list(codegen.exported_methods.items()): if export_site.dml_version() == (1, 2): generate_extern_trampoline_dml12(name, func) else: @@ -3470,9 +3471,9 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): generate_index_enumerations() generate_tuple_table() - with allow_linemarks(): - for c in footers: - c.toc() + with output.allow_linemarks(): + for chunk in footers: + chunk.toc() out('\n') if full_module: @@ -3485,18 +3486,18 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): out('%s();\n' % (init_function_name(device, filename_prefix),)) out('}\n', preindent = -1) - if method_queue: + if codegen.method_queue: # this could e.g. be triggered if _cancel_all in # dml-builtins.dml would call another method - raise ICE(None, 'late additions to method_queue') + raise ICE(None, 'late additions to codegen.method_queue') if dml.globals.dml_version == (1, 2): - for error in EBADFAIL_dml12.all_errors(): + for error in E.BADFAIL_dml12.all_errors(): report(error) if logging.show_porting: with output.NoOutput(): - for method in PWUNUSED.typed_methods: + for method in P.WUNUSED.typed_methods: if method.site.filename().endswith('dml-builtins.dml'): # don't waste time on generating methods from dml-builtins continue @@ -3504,16 +3505,16 @@ def generate_cfile_body(device, footers, full_module, filename_prefix): # don't waste time on methods that are already converted continue # run code generation for all dead methods - func = method_instance(method) + func = codegen.method_instance(method) if func not in generated_funcs: with logging.suppress_errors(): - codegen_method_func(func).toc_inline() + codegen.codegen_method_func(func).toc_inline() - for (site, method) in list(PWUNUSED.inline_methods.items()): - if site in PWUNUSED.inlined_methods: - report(PNO_WUNUSED(method.site, 'method', method.logname())) + for (site, method) in list(P.WUNUSED.inline_methods.items()): + if site in P.WUNUSED.inlined_methods: + report(P.NO_WUNUSED(method.site, 'method', method.logname())) else: - report(PWUNUSED(method.site, 'method', method.logname())) + report(P.WUNUSED(method.site, 'method', method.logname())) def tmprename(base): try: @@ -3532,21 +3533,21 @@ def generate(device, headers, footers, prefix, source_files, full_module): generate_cfile(device, footers, prefix, hfilename, protofilename, source_files, full_module) - outfile = FileOutput(structfilename) + outfile = output.FileOutput(structfilename) with outfile: generate_structfile(device, structfilename, prefix) outfile.close() if not logging.failure: outfile.commit() - outfile = FileOutput(hfilename) + outfile = output.FileOutput(hfilename) with outfile: generate_hfile(device, headers, hfilename) outfile.close() if not logging.failure: outfile.commit() - outfile = FileOutput(protofilename) + outfile = output.FileOutput(protofilename) with outfile: generate_protofile(device) outfile.close() diff --git a/py/dml/codegen.py b/py/dml/codegen.py index 3fda604b2..b5d53363a 100644 --- a/py/dml/codegen.py +++ b/py/dml/codegen.py @@ -3,25 +3,23 @@ import re from abc import ABC, abstractmethod, abstractproperty -import operator import contextlib -from functools import reduce import itertools -import os import math -from . import objects, crep, ctree, ast, int_register, logging, serialize +from . import objects, crep, symtab, ctree, expr_util, expr, ast, int_register, logging, serialize from . import dmlparse, output from . import breaking_changes -from .logging import * -from .expr import * -from .ctree import * -from .expr_util import * -from .symtab import * -from .messages import * -from .output import * -from .types import * +from .logging import ICE, report, DMLError +from .expr import Apply, Expression, mkApply, mkLit, NonValue, typecheck_inarg_inits +from . import ctree as c +from . import porting as P +from .expr_util import defined, expr_intval, undefined +from .symtab import global_scope, MethodParamScope, Symtab +from . import errors as E, warnings as W +from .output import out +from . import types as tp from .set import Set from .slotsmeta import auto_init import dml.globals @@ -108,23 +106,23 @@ def __exit__(self, exc_type, exc_val, exc_tb): @abstractmethod def break_(self, site): pass def continue_(self, site): - raise ECONTU(site) + raise E.CONTU(site) class CLoopContext(LoopContext): '''DML loop context corresponding to a C loop''' def break_(self, site): - return [mkBreak(site)] + return [c.mkBreak(site)] def continue_(self, site): - return [mkContinue(site)] + return [c.mkContinue(site)] class NoLoopContext(LoopContext): '''DML loop context corresponding to an inlined method call. This is used to delimit the loop stack between the method containing the inline method call and the method called.''' def break_(self, site): - raise EBREAK(site) + raise E.BREAK(site) def continue_(self, site): - raise ECONT(site) + raise E.CONT(site) class GotoLoopContext(LoopContext): '''DML loop context not directly corresponding to a single C loop @@ -138,14 +136,14 @@ def __init__(self): def break_(self, site): self.used = True - return [mkGotoBreak(site, self.label)] + return [c.mkGotoBreak(site, self.label)] class ForeachSequenceLoopContext(GotoLoopContext): '''DML loop context corresponding to a foreach loop on an each-in sequence Uses of `break` is codegen:d as a goto past the outer loop, and `continue` is codegen:d as a `continue` of the inner loop''' def continue_(self, site): - return [mkContinue(site)] + return [c.mkContinue(site)] class Failure(ABC): '''Handle exceptions failure handling is supposed to handle the various kind of @@ -173,7 +171,7 @@ def fail(self, site): class InitFailure(Failure): '''Returns NULL from init_object on exception''' def fail(self, site): - return mkReturn(site, mkIntegerLiteral(site, 0)) + return c.mkReturn(site, c.mkIntegerLiteral(site, 0)) class LogFailure(Failure): '''Log exceptions as errors, without aborting execution''' @@ -183,18 +181,18 @@ def __init__(self, site, node, indices): self.indices = indices def fail(self, site): - return log_statement(site, log_object(site, self.node, self.indices), - "error", mkIntegerLiteral(site, 1), None, + return c.log_statement(site, c.log_object(site, self.node, self.indices), + "error", c.mkIntegerLiteral(site, 1), None, "Uncaught DML exception") class ReturnFailure(Failure): '''Generate boolean return statements to signal success. False means success.''' def fail(self, site): - return mkReturn(site, mkBoolConstant(site, True)) + return c.mkReturn(site, c.mkBoolConstant(site, True)) def nofail(self): '''Return code that is used to leave the method successfully''' - return mkReturn(self.site, mkBoolConstant(self.site, False)) + return c.mkReturn(self.site, c.mkBoolConstant(self.site, False)) class CatchFailure(Failure): '''Handle exceptions by re-throwing them, which in C means jumping to @@ -206,12 +204,12 @@ def __init__(self, site, method_node): def fail(self, site): if not self.label: self.label = gensym('throw') - return mkThrow(site, self.label) + return c.mkThrow(site, self.label) class IgnoreFailure(Failure): '''Ignore exceptions''' def fail(self, site): - return mkNoop(site) + return c.mkNoop(site) class ExitHandler(ABC): current = None @@ -243,7 +241,7 @@ class GotoExit_dml12(GotoExit): def codegen_exit(self, site, retvals): assert retvals is None self.used = True - return mkGoto(site, self.label) + return c.mkGoto(site, self.label) class GotoExit_dml14(GotoExit): def __init__(self, outvars): @@ -253,11 +251,11 @@ def codegen_exit(self, site, retvals): assert retvals is not None assert len(retvals) == len(self.outvars) self.used = True - return mkCompound( + return c.mkCompound( site, - [mkCopyData(site, val, out) + [c.mkCopyData(site, val, out) for (out, val) in zip(self.outvars, retvals)] - + [mkReturnFromInline(site, self.label)]) + + [c.mkReturnFromInline(site, self.label)]) class ReturnExit(ExitHandler): def __init__(self, outp, throws): @@ -268,11 +266,11 @@ def codegen_exit(self, site, retvals): return codegen_return(site, self.outp, self.throws, retvals) def memoized_return_failure_leave(site, make_ref, failed): - ran = make_ref('ran', TInt(8, True)) - threw = make_ref('threw', TBool()) - stmts = [mkCopyData(site, mkIntegerLiteral(site, 1), ran), - mkCopyData(site, mkBoolConstant(site, failed), threw), - mkReturn(site, mkBoolConstant(site, failed))] + ran = make_ref('ran', tp.Int(8, True)) + threw = make_ref('threw', tp.Bool()) + stmts = [c.mkCopyData(site, c.mkIntegerLiteral(site, 1), ran), + c.mkCopyData(site, c.mkBoolConstant(site, failed), threw), + c.mkReturn(site, c.mkBoolConstant(site, failed))] return stmts class MemoizedReturnFailure(Failure): @@ -284,12 +282,12 @@ def __init__(self, site, make_ref): self.make_ref = make_ref def fail(self, site): - return mkCompound( + return c.mkCompound( site, memoized_return_failure_leave(site, self.make_ref, True)) def nofail(self): '''Return code that is used to leave the method successfully''' - return mkCompound( + return c.mkCompound( self.site, memoized_return_failure_leave(self.site, self.make_ref, False)) @@ -301,18 +299,18 @@ def __init__(self, site, outp, throws, make_ref): self.make_ref = make_ref def codegen_exit(self, site, retvals): - ran = self.make_ref('ran', TInt(8, True)) - stmts = [mkCopyData(site, mkIntegerLiteral(site, 1), ran)] + ran = self.make_ref('ran', tp.Int(8, True)) + stmts = [c.mkCopyData(site, c.mkIntegerLiteral(site, 1), ran)] if self.throws: - threw = self.make_ref('threw', TBool()) - stmts.append(mkCopyData(site, mkBoolConstant(site, False), threw)) + threw = self.make_ref('threw', tp.Bool()) + stmts.append(c.mkCopyData(site, c.mkBoolConstant(site, False), threw)) targets = [] for ((name, typ), val) in zip(self.outp, retvals): target = self.make_ref(f'p_{name}', typ) - stmts.append(mkCopyData(site, val, target)) + stmts.append(c.mkCopyData(site, val, target)) targets.append(target) stmts.append(codegen_return(site, self.outp, self.throws, targets)) - return mkCompound(site, stmts) + return c.mkCompound(site, stmts) class Memoization(ABC): @abstractmethod @@ -333,7 +331,7 @@ def __init__(self, func): self.func = func self.method = func.method # SimpleSite wrapper to avoid linemarks being generated. - self.site = SimpleSite(self.method.site.loc()) + self.site = logging.SimpleSite(self.method.site.loc()) def make_ref(self, ref, typ): indexing = ''.join([f'[_idx{i}]' @@ -344,11 +342,11 @@ def prelude(self): struct_body = ''.join( f'{typ.declaration(name)}; ' for (name, typ) in ( - [('ran', TInt(8, True))] - + ([('threw', TBool())] if self.func.throws else []) + [('ran', tp.Int(8, True))] + + ([('threw', tp.Bool())] if self.func.throws else []) + [(f'p_{name}', typ) for (name, typ) in self.func.outp])) array_defs = ''.join([f'[{i}]' for i in self.method.dimsizes]) - struct_var_def = mkInline( + struct_var_def = c.mkInline( self.site, f'static struct {{{struct_body}}} _memo{array_defs};') return [struct_var_def] + memoization_common_prelude( @@ -366,9 +364,9 @@ def __init__(self, method): assert method.independent self.method = method # SimpleSite wrapper to avoid linemarks being generated. - self.site = SimpleSite(self.method.site.loc()) + self.site = logging.SimpleSite(self.method.site.loc()) def make_ref(self, ref, typ): - traitname = cident(self.method.trait.name) + traitname = tp.cident(self.method.trait.name) return mkLit(self.site, f'((struct _{traitname} *) _{traitname}.trait)' + f'->_memo_outs_{self.method.name}' @@ -393,8 +391,8 @@ def memoization_common_prelude(name, site, outp, throws, make_ref): # cached return values are retrieved and returned. if throws: has_run_stmts.append( - mkIf(site, make_ref('threw', TBool()), - mkReturn(site, mkBoolConstant(site, True)))) + c.mkIf(site, make_ref('threw', tp.Bool()), + c.mkReturn(site, c.mkBoolConstant(site, True)))) has_run_stmts.append( codegen_return(site, outp, throws, [make_ref(f'p_{pname}', ptype) @@ -407,16 +405,16 @@ def memoization_common_prelude(name, site, outp, throws, make_ref): # - -1: called before, but not to completion. This only happens due to an # (indirect) recursive call. Raise critical error, and then proceed # as though ran == 0. Hopefully things will turn out ok. - ran = make_ref('ran', TInt(8, True)) - unrun = [mkCase(site, mkIntegerLiteral(site, 0)), - mkCopyData(site, mkIntegerConstant(site, -1, True), ran), - mkBreak(site)] - has_run = [mkCase(site, mkIntegerLiteral(site, 1))] + has_run_stmts - running = [mkDefault(site), - mkInline(site, f'_memoized_recursion("{name}");')] - return [mkSwitch(site, - make_ref('ran', TInt(8, True)), - mkCompound(site, unrun + has_run + running))] + ran = make_ref('ran', tp.Int(8, True)) + unrun = [c.mkCase(site, c.mkIntegerLiteral(site, 0)), + c.mkCopyData(site, c.mkIntegerConstant(site, -1, True), ran), + c.mkBreak(site)] + has_run = [c.mkCase(site, c.mkIntegerLiteral(site, 1))] + has_run_stmts + running = [c.mkDefault(site), + c.mkInline(site, f'_memoized_recursion("{name}");')] + return [c.mkSwitch(site, + make_ref('ran', tp.Int(8, True)), + c.mkCompound(site, unrun + has_run + running))] class TypeSequenceInfo: """Bookkeeping surrounding a realtyped unique type sequence""" @@ -424,7 +422,7 @@ def __init__(self, types, uniq): self.types = types self.uniq = uniq self.after_on_hooks = {} - self.struct = (TStruct({f'comp{i}': typ + self.struct = (tp.Struct({f'comp{i}': typ for (i, typ) in enumerate(types)}, label=f'_typeseq_{self.uniq}') if types else None) @@ -446,7 +444,7 @@ def get_after_on_hook(self, aoh_prim_key, param_to_msg_comp, no_params, return info def get_type_sequence_info(index, create_new=False): - typeseq = TypeSequence(index) + typeseq = tp.TypeSequence(index) try: return dml.globals.type_sequence_infos[typeseq] except KeyError: @@ -596,7 +594,7 @@ class AfterDelayIntoMethodInfo(AfterDelayInfo): def __init__(self, method, uniq): self.method = method super().__init__(method, method.dimsizes, uniq) - self._args_type = (TStruct({p.c_ident: p.typ for p in method.inp}, + self._args_type = (tp.Struct({p.c_ident: p.typ for p in method.inp}, label=f'_simple_event_{self.uniq}_args') if method.inp else None) @@ -614,23 +612,23 @@ def string_key(self): def generate_callback_call(self, indices_lit, args_lit): site = self.method.site - indices = tuple(mkLit(site, f'{indices_lit}[{i}]', TInt(32, False)) + indices = tuple(mkLit(site, f'{indices_lit}[{i}]', tp.Int(32, False)) for i in range(self.method.dimensions)) args = tuple(mkLit(site, f'{args_lit}->{p.c_ident}', p.typ) for p in self.method.inp) with LogFailure(site, self.method, indices), \ crep.DeviceInstanceContext(): code = codegen_call(site, self.method, indices, args, ()) - code = mkCompound(site, [code]) + code = c.mkCompound(site, [code]) code.toc() class AfterDelayIntoSendNowInfo(AfterDelayInfo): def __init__(self, typeseq_info, uniq): super().__init__(typeseq_info, [], uniq) self .typeseq_info = typeseq_info - hookref_type = THook(typeseq_info.types, validated=True) + hookref_type = tp.Hook(typeseq_info.types, validated=True) self._args_type = ( - TStruct({'hookref': hookref_type, + tp.Struct({'hookref': hookref_type, 'args': typeseq_info.struct}, label=f'_simple_event_{self.uniq}_args') if typeseq_info.types else hookref_type) @@ -672,7 +670,7 @@ def __init__(self, typeseq_info, method, param_to_msg_comp): super().__init__(method.dimsizes, method.parent, typeseq_info, method, param_to_msg_comp, method.inp, bool(self.method.inp)) self._args_type = ( - TStruct({p.c_ident: p.typ + tp.Struct({p.c_ident: p.typ for (i, p) in enumerate(method.inp) if i not in param_to_msg_comp}, label=f'_after_on_hook_{self.uniq}_args') @@ -680,7 +678,7 @@ def __init__(self, typeseq_info, method, param_to_msg_comp): def generate_callback_call(self, indices_lit, args_lit, msg_lit): site = self.method.site - indices = tuple(mkLit(site, f'{indices_lit}[{i}]', TInt(32, False)) + indices = tuple(mkLit(site, f'{indices_lit}[{i}]', tp.Int(32, False)) for i in range(self.method.dimensions)) args = tuple( mkLit(site, @@ -692,12 +690,12 @@ def generate_callback_call(self, indices_lit, args_lit, msg_lit): with LogFailure(site, self.method, indices), \ crep.DeviceInstanceContext(): code = codegen_call(site, self.method, indices, args, ()) - code = mkCompound(site, [code]) + code = c.mkCompound(site, [code]) code.toc() def generate_args_serializer(self, site, args_expr, out_expr): sources = tuple((ctree.mkSubRef(site, args_expr, p.c_ident, "."), - safe_realtype(p.typ)) + tp.safe_realtype(p.typ)) if i not in self.param_to_msg_comp else None for (i, p) in enumerate(self.method.inp)) serialize.serialize_sources_to_list(site, sources, out_expr) @@ -710,7 +708,7 @@ def generate_args_deserializer(self, site, val_expr, out_expr, error_out): else: tmp_out_ref = None targets = tuple((ctree.mkSubRef(site, tmp_out_ref, p.c_ident, "."), - safe_realtype(p.typ)) + tp.safe_realtype(p.typ)) if i not in self.param_to_msg_comp else None for (i, p) in enumerate(self.method.inp)) @@ -746,16 +744,16 @@ def __init__(self, typeseq_info, sendnow_typeseq_info, param_to_msg_comp): has_inner_args = len(inp) > len(param_to_msg_comp) super().__init__([], dml.globals.device, typeseq_info, sendnow_typeseq_info, param_to_msg_comp, inp, True) - sendnow_hookref_type = THook(sendnow_typeseq_info.types, + sendnow_hookref_type = tp.Hook(sendnow_typeseq_info.types, validated=True) self.inner_args_type = ( - TStruct({name: typ + tp.Struct({name: typ for (i, (name, typ)) in enumerate(inp) if i not in param_to_msg_comp}, label=f'_after_on_hook_{self.uniq}_inner_args') if has_inner_args else None) self._args_type = ( - TStruct({'hookref': sendnow_hookref_type, + tp.Struct({'hookref': sendnow_hookref_type, 'args': self.inner_args_type}, label=f'_after_on_hook_{self.uniq}_args') if has_inner_args else sendnow_hookref_type) @@ -786,10 +784,10 @@ def generate_args_serializer(self, site, args_expr, out_expr): hookref = (ctree.mkSubRef(site, args_expr, "hookref", ".") if has_inner_args else args_expr) sources = [(hookref, - THook(self.sendnow_typeseq_info.types, validated=True))] + tp.Hook(self.sendnow_typeseq_info.types, validated=True))] if has_inner_args: inner_args_val_decl, inner_args_val = serialize.declare_variable( - site, 'inner_args_val', TNamed('attr_value_t')) + site, 'inner_args_val', tp.Named('attr_value_t')) inner_args_val_decl.toc() inner_args = ctree.mkSubRef(site, args_expr, 'args', '.') inner_args_sources = ( @@ -811,11 +809,11 @@ def generate_args_deserializer(self, site, val_expr, out_expr, error_out): hookref = (ctree.mkSubRef(site, tmp_out_ref, 'hookref', '.') if has_inner_args else tmp_out_ref) targets = [(hookref, - safe_realtype(THook(self.sendnow_typeseq_info.types, + tp.safe_realtype(tp.Hook(self.sendnow_typeseq_info.types, validated=True)))] if has_inner_args: inner_args_val_decl, inner_args_val = serialize.declare_variable( - site, '_inner_args_val', TNamed('attr_value_t')) + site, '_inner_args_val', tp.Named('attr_value_t')) inner_args_val_decl.toc() targets.append((inner_args_val, None)) @@ -831,7 +829,7 @@ def error_out_at_index(_i, exc, msg): inner_args = ctree.mkSubRef(site, tmp_out_ref, 'args', '.') inner_args_targets = ( (ctree.mkSubRef(site, inner_args, f'comp{i}', '.'), - safe_realtype(typ)) + tp.safe_realtype(typ)) if i not in self.param_to_msg_comp else None for (i, typ) in enumerate(self.sendnow_typeseq_info.types)) serialize.deserialize_list_to_targets( @@ -858,7 +856,7 @@ class ImmediateAfterIntoMethodInfo(ImmediateAfterInfo): def __init__(self, method, uniq): self.method = method super().__init__(method, method.dimsizes, uniq) - self._args_type = (TStruct({p.c_ident: p.typ for p in method.inp}, + self._args_type = (tp.Struct({p.c_ident: p.typ for p in method.inp}, label=f'_immediate_after_{self.uniq}_args') if method.inp else None) @@ -872,23 +870,23 @@ def types_to_declare(self): def generate_callback_call(self, indices_lit, args_lit): site = self.method.site - indices = tuple(mkLit(site, f'{indices_lit}[{i}]', TInt(32, False)) + indices = tuple(mkLit(site, f'{indices_lit}[{i}]', tp.Int(32, False)) for i in range(self.method.dimensions)) args = tuple(mkLit(site, f'{args_lit}->{p.c_ident}', p.typ) for p in self.method.inp) with LogFailure(site, self.method, indices), \ crep.DeviceInstanceContext(): code = codegen_call(site, self.method, indices, args, ()) - code = mkCompound(site, [code]) + code = c.mkCompound(site, [code]) code.toc() class ImmediateAfterIntoSendNowInfo(ImmediateAfterInfo): def __init__(self, typeseq_info, uniq): super().__init__(typeseq_info, [], uniq) self.typeseq_info = typeseq_info - hookref_type = THook(typeseq_info.types, validated=True) + hookref_type = tp.Hook(typeseq_info.types, validated=True) self._args_type = ( - TStruct({'hookref': hookref_type, + tp.Struct({'hookref': hookref_type, 'args': typeseq_info.struct}, label=f'_immediate_after_{self.uniq}_args') if typeseq_info.types else hookref_type) @@ -968,7 +966,7 @@ def declarations(scope): continue if sym.stmt: continue - decl = sym_declaration(sym) + decl = c.sym_declaration(sym) if not decl.is_empty: decls.append(decl) @@ -987,7 +985,7 @@ def codegen_expression(ast, location, scope): @expression_dispatcher def expr_set(tree, location, scope): [target, source] = tree.args - return mkAssignOp(tree.site, + return c.mkAssignOp(tree.site, codegen_expression(target, location, scope), codegen_expression(source, location, scope)) @@ -996,7 +994,7 @@ def expr_conditional(tree, location, scope): [cond, texpr, fexpr] = tree.args cond = codegen_expression(cond, location, scope) if cond.constant and dml.globals.dml_version == (1, 2): - # Constant propagate + # c.Constant propagate live_ast = texpr if cond.value else fexpr live_expr = codegen_expression_maybe_nonvalue(live_ast, location, scope) @@ -1012,10 +1010,10 @@ def expr_conditional(tree, location, scope): except DMLError as e: errors.append(e) if errors or isinstance(live_expr, NonValue): - report(PHASH(tree.site)) - report(PHASHELSE(dmlparse.end_site(texpr.site), ':')) + report(P.HASH(tree.site)) + report(P.HASHELSE(dmlparse.end_site(texpr.site), ':')) return live_expr - return mkIfExpr(tree.site, + return c.mkIfExpr(tree.site, cond, codegen_expression(texpr, location, scope), codegen_expression(fexpr, location, scope)) @@ -1023,31 +1021,31 @@ def expr_conditional(tree, location, scope): @expression_dispatcher def expr_hashcond(tree, location, scope): [cond, texpr, fexpr] = tree.args - cond = as_bool(codegen_expression(cond, location, scope)) + cond = c.as_bool(codegen_expression(cond, location, scope)) if not cond.constant: - raise ENCONST(tree.site, cond) + raise E.NCONST(tree.site, cond) live_ast = texpr if cond.value else fexpr return codegen_expression_maybe_nonvalue(live_ast, location, scope) arith_binops = { - '<': mkLessThan, - '<=': mkLessThanOrEquals, - '>': mkGreaterThan, - '>=': mkGreaterThanOrEquals, - '==': mkEquals, - '!=': mkNotEquals, - '&': mkBitAnd, - '|': mkBitOr, - '^': mkBitXOr, - '<<': mkShL, - '>>': mkShR, - '*': mkMult, - '/': mkDiv, - '%': mkMod, - '+': mkAdd, - '-': mkSubtract, - '&&': mkAnd, - '||': mkOr, + '<': c.mkLessThan, + '<=': c.mkLessThanOrEquals, + '>': c.mkGreaterThan, + '>=': c.mkGreaterThanOrEquals, + '==': c.mkEquals, + '!=': c.mkNotEquals, + '&': c.mkBitAnd, + '|': c.mkBitOr, + '^': c.mkBitXOr, + '<<': c.mkShL, + '>>': c.mkShR, + '*': c.mkMult, + '/': c.mkDiv, + '%': c.mkMod, + '+': c.mkAdd, + '-': c.mkSubtract, + '&&': c.mkAnd, + '||': c.mkOr, } @expression_dispatcher @@ -1059,29 +1057,29 @@ def expr_binop(tree, location, scope): lh = codegen_expression(lh, location, scope) if op in {'&&', '||'}: - lh = as_bool(lh) + lh = c.as_bool(lh) if lh.constant and bool(lh.value) == (op == '||'): if tree.site.dml_version() == (1, 2): if logging.show_porting: # if RH contains errors, we must convert it to #? #: with logging.suppress_errors() as errors: - as_bool(codegen_expression(rh, location, scope)) + c.as_bool(codegen_expression(rh, location, scope)) if errors: if op == '||': - report(PANDOR(tree.site, dmlparse.start_site(tree.site), dmlparse.end_site(tree.site), '||', '#? true #:', '')) + report(P.ANDOR(tree.site, dmlparse.start_site(tree.site), dmlparse.end_site(tree.site), '||', '#? true #:', '')) else: - report(PANDOR(tree.site, dmlparse.start_site(tree.site), dmlparse.end_site(tree.site), '&&', '#?', ' #: false')) + report(P.ANDOR(tree.site, dmlparse.start_site(tree.site), dmlparse.end_site(tree.site), '&&', '#?', ' #: false')) else: - as_bool(codegen_expression(rh, location, scope)) + c.as_bool(codegen_expression(rh, location, scope)) return lh - rh = as_bool(codegen_expression(rh, location, scope)) + rh = c.as_bool(codegen_expression(rh, location, scope)) else: rh = codegen_expression(rh, location, scope) return arith_binops[op](tree.site, lh, rh) def codegen_sizeof(site, expr): fun = mkLit(site, 'sizeof', - TFunction([], TNamed('size_t'), + tp.Function([], tp.Named('size_t'), varargs = True)) return Apply(site, fun, [expr], fun.ctype()) @@ -1104,36 +1102,36 @@ def expr_unop(tree, location, scope): if (not breaking_changes.dml12_remove_misc_quirks.enabled and op == 'sizeof' and rh_ast.kind == 'variable_dml12'): var = rh_ast.args[0] - if var in typedefs and scope.lookup(var) is None: - report(WSIZEOFTYPE(tree.site)) + if var in tp.typedefs and scope.lookup(var) is None: + report(W.SIZEOFTYPE(tree.site)) return codegen_sizeof( - tree.site, mkLit(tree.site, cident(var), None)) + tree.site, mkLit(tree.site, tp.cident(var), None)) try: rh = codegen_expression_maybe_nonvalue(rh_ast, location, scope) - except EIDENT as e: + except E.IDENT as e: if op == 'sizeof': - is_primitive_type = not isinstance(parse_type(e.identifier), - TNamed) - if is_primitive_type or e.identifier in typedefs: - raise EIDENTSIZEOF(e.site, e.identifier) + is_primitive_type = not isinstance(tp.parse_type(e.identifier), + tp.Named) + if is_primitive_type or e.identifier in tp.typedefs: + raise E.IDENTSIZEOF(e.site, e.identifier) raise if isinstance(rh, NonValue): if op == 'defined': if undefined(rh): - return mkBoolConstant(tree.site, False) - if isinstance(rh, (NodeRef, NonValueArrayRef, AbstractList)): - return mkBoolConstant(tree.site, True) - if op == '!' and isinstance(rh, InterfaceMethodRef): + return c.mkBoolConstant(tree.site, False) + if isinstance(rh, (c.NodeRef, expr.NonValueArrayRef, c.AbstractList)): + return c.mkBoolConstant(tree.site, True) + if op == '!' and isinstance(rh, c.InterfaceMethodRef): # see SIMICS-9868 - return mkNot(tree.site, mkMethodPresent(tree.site, rh)) - if (op == '&' and isinstance(rh, NodeRef) + return c.mkNot(tree.site, c.mkMethodPresent(tree.site, rh)) + if (op == '&' and isinstance(rh, c.NodeRef) and tree.site.dml_version() != (1, 2)): (method, indices) = rh.get_ref() if method.objtype == 'method': if (indices or not method.fully_typed or method.throws or len(method.outp) > 1): - raise ESTATICEXPORT(method.site, tree.site) + raise E.STATICEXPORT(method.site, tree.site) else: func = method_instance(method) mark_method_referenced(func) @@ -1144,35 +1142,35 @@ def expr_unop(tree, location, scope): if op == '!': if not breaking_changes.dml12_not_typecheck.enabled: t = rh.ctype() - if isinstance(safe_realtype(t), TInt) and subast_has_dollar(rh_ast): + if isinstance(tp.safe_realtype(t), tp.Int) and subast_has_dollar(rh_ast): # A previous bug caused DMLC to permit expressions on # the form '!$reg'. This pattern was fairly common; # this hack is an attempt to reduce the short-term # need to update existing models. See also bug 24248. if logging.show_porting: # triggers PBITNEQ - as_bool(rh) - return mkEquals(tree.site, rh, mkIntegerLiteral(tree.site, 0)) - return mkNot(tree.site, as_bool(rh)) - elif op == '~': return mkBitNot(tree.site, rh) - elif op == '-': return mkUnaryMinus(tree.site, rh) - elif op == '+': return mkUnaryPlus(tree.site, rh) - elif op == '&': return mkAddressOf(tree.site, rh) - elif op == '*': return mkDereference(tree.site, rh) - elif op == '++': return mkPreInc(tree.site, rh) - elif op == '--': return mkPreDec(tree.site, rh) - elif op == 'post++': return mkPostInc(tree.site, rh) - elif op == 'post--': return mkPostDec(tree.site, rh) + c.as_bool(rh) + return c.mkEquals(tree.site, rh, c.mkIntegerLiteral(tree.site, 0)) + return c.mkNot(tree.site, c.as_bool(rh)) + elif op == '~': return c.mkBitNot(tree.site, rh) + elif op == '-': return c.mkUnaryMinus(tree.site, rh) + elif op == '+': return c.mkUnaryPlus(tree.site, rh) + elif op == '&': return c.mkAddressOf(tree.site, rh) + elif op == '*': return c.mkDereference(tree.site, rh) + elif op == '++': return c.mkPreInc(tree.site, rh) + elif op == '--': return c.mkPreDec(tree.site, rh) + elif op == 'post++': return c.mkPostInc(tree.site, rh) + elif op == 'post--': return c.mkPostDec(tree.site, rh) elif op == 'sizeof': if (breaking_changes.dml12_remove_misc_quirks.enabled and not rh.addressable): - raise ERVAL(rh.site, 'sizeof') + raise E.RVAL(rh.site, 'sizeof') return codegen_sizeof(tree.site, rh) - elif op == 'defined': return mkBoolConstant(tree.site, True) + elif op == 'defined': return c.mkBoolConstant(tree.site, True) elif op == 'stringify': if not rh.constant: - raise ENCONST(rh, rh) - return mkStringConstant(tree.site, str(rh)) + raise E.NCONST(rh, rh) + return c.mkStringConstant(tree.site, str(rh)) else: raise Exception('Unknown unary operation: %s %s' % (repr(op), repr(rh))) @@ -1182,7 +1180,7 @@ def expr_typeop(tree, location, scope): [t] = tree.args (struct_defs, t) = eval_type(t, tree.site, location, scope) for (site, _) in struct_defs: - report(EANONSTRUCT(site, "'sizeoftype' expression")) + report(E.ANONSTRUCT(site, "'sizeoftype' expression")) return codegen_sizeof(tree.site, mkLit(tree.site, t.declaration(''), None)) @expression_dispatcher @@ -1190,10 +1188,10 @@ def expr_new(tree, location, scope): [t, count] = tree.args (struct_defs, t) = eval_type(t, tree.site, location, scope) for (site, _) in struct_defs: - report(EANONSTRUCT(site, "'new' expression")) + report(E.ANONSTRUCT(site, "'new' expression")) if count: count = codegen_expression(count, location, scope) - return mkNew(tree.site, t, count) + return c.mkNew(tree.site, t, count) @expression_dispatcher def expr_apply(tree, location, scope): @@ -1205,15 +1203,15 @@ def expr_apply(tree, location, scope): @expression_dispatcher def expr_variable_dml12(tree, location, scope): [name] = tree.args - e = lookup_var(tree.site, scope, name) + e = c.lookup_var(tree.site, scope, name) if e is None: - raise EIDENT(tree.site, name) + raise E.IDENT(tree.site, name) return e @expression_dispatcher def expr_variable(tree, location, scope): [name] = tree.args - e = lookup_var(tree.site, scope, name) + e = c.lookup_var(tree.site, scope, name) if scope.lookup(name) is global_scope.lookup(name) and location: # Hack: Object hierarchy is shoehorned between global scope and any # local scope @@ -1224,23 +1222,23 @@ def expr_variable(tree, location, scope): if in_dev_tree: e = in_dev_tree if e is None: - raise EIDENT(tree.site, name) + raise E.IDENT(tree.site, name) return e @expression_dispatcher def expr_discard(tree, location, scope): - return mkDiscardRef(tree.site) + return c.mkDiscardRef(tree.site) @expression_dispatcher def expr_objectref(tree, location, scope): [name] = tree.args if not location: # This happens when invoked from mkglobals - raise ENCONST(tree.site, dollar(tree.site)+name) + raise E.NCONST(tree.site, logging.dollar(tree.site)+name) e = ctree.lookup_component( tree.site, location.node, location.indices, name, False) if not e: - raise EREF(tree.site, name) + raise E.REF(tree.site, name) assert dml.globals.dml_version == (1, 2) if logging.show_porting: if (scope.lookup(name) @@ -1262,7 +1260,7 @@ def expr_objectref(tree, location, scope): prefix = 'dev.%s.' % (node.logname( tuple(e.read() for e in location.indices)),) if not tree.site.filename().endswith('dml-builtins.dml'): - report(PDOLLAR_QUALIFY( + report(P.DOLLAR_QUALIFY( dmlparse.start_site(tree.site), '', prefix)) return e @@ -1271,29 +1269,29 @@ def expr_member(tree, location, scope): [lh, op, rh] = tree.args lh = codegen_expression_maybe_nonvalue(lh, location, scope) - return mkSubRef(tree.site, lh, rh, op) + return c.mkSubRef(tree.site, lh, rh, op) @expression_dispatcher def expr_string(tree, location, scope): [val] = tree.args - return mkStringConstant(tree.site, val) + return c.mkStringConstant(tree.site, val) @expression_dispatcher def expr_int(tree, location, scope): [val] = tree.args - return mkIntegerLiteral(tree.site, val) + return c.mkIntegerLiteral(tree.site, val) @expression_dispatcher def expr_float(tree, location, scope): [val] = tree.args - return mkFloatConstant(tree.site, val) + return c.mkFloatConstant(tree.site, val) @expression_dispatcher def expr_index(tree, location, scope): [expr, index, bitorder] = tree.args expr = codegen_expression_maybe_nonvalue(expr, location, scope) index = codegen_expression_maybe_nonvalue(index, location, scope) - return mkIndex(tree.site, expr, index) + return c.mkIndex(tree.site, expr, index) @expression_dispatcher def expr_slice(tree, location, scope): @@ -1302,14 +1300,14 @@ def expr_slice(tree, location, scope): msb = codegen_expression(msb, location, scope) if lsb is not None: lsb = codegen_expression(lsb, location, scope) - return mkBitSlice(tree.site, expr, msb, lsb, bitorder) + return c.mkBitSlice(tree.site, expr, msb, lsb, bitorder) @expression_dispatcher def expr_list(tree, location, scope): [elts] = tree.args values = [codegen_expression_maybe_nonvalue(elt, location, scope) for elt in elts] - return mkList(tree.site, values) + return c.mkList(tree.site, values) @expression_dispatcher def expr_cast(tree, location, scope): @@ -1317,13 +1315,13 @@ def expr_cast(tree, location, scope): expr = codegen_expression_maybe_nonvalue(expr_ast, location, scope) (struct_defs, type) = eval_type(casttype, tree.site, location, scope) for (site, _) in struct_defs: - report(EANONSTRUCT(site, "'cast' expression")) + report(E.ANONSTRUCT(site, "'cast' expression")) - return mkCast(tree.site, expr, type) + return c.mkCast(tree.site, expr, type) @expression_dispatcher def expr_undefined(tree, location, scope): - return mkUndefined(tree.site) + return c.mkUndefined(tree.site) percent_matcher = re.compile("%") @@ -1352,7 +1350,7 @@ def fix_printf(fmt, args, argsites, site): start = m.start() m = fmt_matcher.match(fmt, start) if not m: - raise EFORMAT(site, start+1) + raise E.FORMAT(site, start+1) filtered_fmt += fmt[last_end:m.start()] last_end = m.end() @@ -1371,12 +1369,12 @@ def fix_printf(fmt, args, argsites, site): continue if argi == len(args): - raise EFMTARGN(site) + raise E.FMTARGN(site) if width == '*': - filtered_args.append(mkCast(args[argi].site, + filtered_args.append(c.mkCast(args[argi].site, ctree.as_int(args[argi]), - TInt(32, True))) + tp.Int(32, True))) argi += 1 if precision == '.*': @@ -1393,64 +1391,64 @@ def fix_printf(fmt, args, argsites, site): # purposes of logging, it is a sufficient workaround # to unconditionally cast to long long. length = "ll" - arg = mkCast(arg.site, as_int(args[argi]), TInt(64, False)) + arg = c.mkCast(arg.site, c.as_int(args[argi]), tp.Int(64, False)) elif conversion in "p": - argtype = safe_realtype(arg.ctype()) + argtype = tp.safe_realtype(arg.ctype()) - if not isinstance(argtype, TPtr): - raise EFMTARGT(argsites[argi], arg, + if not isinstance(argtype, tp.Ptr): + raise E.FMTARGT(argsites[argi], arg, argi+1, "pointer") elif conversion == 's': argtype = arg.ctype() - if isinstance(arg, (QName, HiddenName, HiddenQName)): + if isinstance(arg, (c.QName, c.HiddenName, c.HiddenQName)): qfmt, qargs = arg.fmt() filtered_fmt += qfmt - assumed_type = TInt(32, False) + assumed_type = tp.Int(32, False) for qarg in qargs: - filtered_args.append(mkCast(qarg.site, qarg, assumed_type)) + filtered_args.append(c.mkCast(qarg.site, qarg, assumed_type)) argi += 1 continue - elif isinstance(argtype, TNamed) and argtype.c == 'strbuf_t': + elif isinstance(argtype, tp.Named) and argtype.c == 'strbuf_t': arg = mkApply(site, mkLit(site, 'sb_str', - TFunction([TPtr(argtype)], - TPtr(TNamed('char', + tp.Function([tp.Ptr(argtype)], + tp.Ptr(tp.Named('char', const=True)))), - [mkAddressOf(site, arg)]) + [c.mkAddressOf(site, arg)]) filtered_fmt += "%" + flags + width + precision + length + conversion filtered_args.append(arg) argi += 1 if argi < len(args): - raise EFMTARGN(site) + raise E.FMTARGN(site) return filtered_fmt, filtered_args def eval_arraylen(size_ast, parent_scope): size = codegen_expression(size_ast, parent_scope, global_scope) if not size.constant: - raise EASZVAR(size.site, size) + raise E.ASZVAR(size.site, size) if not isinstance(size.value, int): - report(EBTYPE(size.site, size, "integer")) + report(E.BTYPE(size.site, size, "integer")) return 2 # arbitrary nonzero integer if size.value < 1: - raise EASZR(size.site) + raise E.ASZR(size.site) return size.value def eval_type(asttype, site, location, scope, extern=False, typename=None, allow_void=False): '''Interpret a type AST. - The return value is a pair (struct_defs, type), where type is the DMLType - instance, and struct_defs is a list of StructType statements required by + The return value is a pair (struct_defs, type), where type is the tp.DMLType + instance, and struct_defs is a list of tp.StructType statements required by C to interpret a declaration that uses the type. 'extern' is true inside 'extern typedef' declarations. 'typename' is used as hint for a good struct label, e.g. typedef struct { ... } foo_t; gives the label 'foo_t' which allows nicer error messages''' - assert location is None or isinstance(location, Location) + assert location is None or isinstance(location, c.Location) assert asttype @@ -1463,50 +1461,50 @@ def eval_type(asttype, site, location, scope, extern=False, typename=None, for (_, msite, name, type_ast) in info: (member_struct_defs, member_type) = eval_type( type_ast, msite, location, scope, extern) - if isinstance(member_type, TFunction): + if isinstance(member_type, tp.Function): if (not (breaking_changes .forbid_function_in_extern_struct.enabled) and extern): - member_type = TPtr(member_type) + member_type = tp.Ptr(member_type) else: - raise EFUNSTRUCT(msite) + raise E.FUNSTRUCT(msite) members[name] = member_type struct_defs.extend(member_struct_defs) if extern: - id = typename or TExternStruct.unique_id() - etype = TExternStruct(members, id, typename=typename) + id = typename or tp.ExternStruct.unique_id() + etype = tp.ExternStruct(members, id, typename=typename) elif members: - etype = TStruct(members, label=typename) + etype = tp.Struct(members, label=typename) struct_defs.append((site, etype)) else: if site.dml_version() == (1, 2): - etype = TVoid() + etype = tp.Void() else: - raise EEMPTYSTRUCT(site) + raise E.EMPTYSTRUCT(site) elif tag == 'layout': if extern: - raise ELAYOUT(site, "extern layout not permitted," + raise E.LAYOUT(site, "extern layout not permitted," + " use 'struct { }' instead") endian, fields = info member_decls = [] for (_, msite, ident, type_ast) in fields: (member_struct_defs, member_type) = eval_type( type_ast, msite, location, scope, False) - if isinstance(member_type, TFunction): - raise EFUNSTRUCT(msite) + if isinstance(member_type, tp.Function): + raise E.FUNSTRUCT(msite) member_decls.append(( msite, ident.args[0] if ident.kind == 'variable' else None, member_type)) struct_defs.extend(member_struct_defs) if not member_decls: - raise EEMPTYSTRUCT(site) - etype = TLayout(endian, member_decls, label=typename) + raise E.EMPTYSTRUCT(site) + etype = tp.Layout(endian, member_decls, label=typename) struct_defs.append((site, etype)) elif tag == 'bitfields': width, fields = info if width > 64: - raise EBFLD(site, "bitfields width is > 64") + raise E.BFLD(site, "bitfields width is > 64") members = {} for ((_, fsite, name, t), astmsb, astlsb) in fields: msb = expr_intval(codegen_expression(astmsb, location, scope)) @@ -1518,12 +1516,12 @@ def eval_type(asttype, site, location, scope, extern=False, typename=None, # guaranteed by parser assert not member_struct_defs if not mtype.is_int: - raise EBFLD(fsite, "non-integer field") + raise E.BFLD(fsite, "non-integer field") if mtype.bits != msb - lsb + 1: - raise EBFLD(fsite, "field %s has wrong size" % name) + raise E.BFLD(fsite, "field %s has wrong size" % name) members[name] = (mtype, msb, lsb) - etype = TInt(width, False, members, label=typename) + etype = tp.Int(width, False, members, label=typename) elif tag == 'typeof': expr = codegen_expression_maybe_nonvalue(info, location, scope) if isinstance(expr, NonValue): @@ -1536,14 +1534,14 @@ def eval_type(asttype, site, location, scope, extern=False, typename=None, raise expr.exc() elif (not expr.addressable and breaking_changes.dml12_remove_misc_quirks.enabled): - raise ERVAL(expr.site, 'typeof') + raise E.RVAL(expr.site, 'typeof') else: etype = expr.ctype().clone() if not etype: raise ICE(site, "No type for expression: %s (%r)" % (expr, expr)) elif tag == 'sequence': - etype = TTraitList(info) + etype = tp.TraitList(info) elif tag == 'hook': msg_comp_types = [] for (_, tsite, _, type_ast) in info: @@ -1551,11 +1549,11 @@ def eval_type(asttype, site, location, scope, extern=False, typename=None, type_ast, tsite, location, scope, extern) msg_comp_types.append(msg_comp_type) struct_defs.extend(msg_comp_struct_defs) - etype = THook(msg_comp_types) + etype = tp.Hook(msg_comp_types) else: raise ICE(site, "Strange type") elif isinstance(asttype[0], str): - etype = parse_type(asttype[0]) + etype = tp.parse_type(asttype[0]) else: raise ICE(site, "Stranger type") @@ -1564,34 +1562,34 @@ def eval_type(asttype, site, location, scope, extern=False, typename=None, asttype = asttype[1:] while asttype: if asttype[0] == 'const': - if isinstance(etype, TFunction): - raise ECONSTFUN(site) + if isinstance(etype, tp.Function): + raise E.CONSTFUN(site) etype.const = True asttype = asttype[1:] elif asttype[0] == 'pointer': if (etype.is_int and not etype.is_endian and etype.bits not in {8, 16, 32, 64}): - raise EINTPTRTYPE(site, TPtr(etype)) - etype = TPtr(etype) + raise E.INTPTRTYPE(site, tp.Ptr(etype)) + etype = tp.Ptr(etype) asttype = asttype[1:] elif asttype[0] == 'vect': if etype.void: - raise EVOID(site) - etype = TVector(etype) + raise E.VOID(site) + etype = tp.Vector(etype) asttype = asttype[1:] elif asttype[0] == 'array': if etype.void: - raise EVOID(site) - if isinstance(etype, TFunction): - raise EFUNARRAY(site) + raise E.VOID(site) + if isinstance(etype, tp.Function): + raise E.FUNARRAY(site) alen = codegen_expression(asttype[1], location, scope) - etype = TArray(etype, as_int(alen)) + etype = tp.Array(etype, c.as_int(alen)) asttype = asttype[2:] elif asttype[0] == 'funcall': if struct_defs: (site, _) = struct_defs[0] - raise EANONSTRUCT(site, "function return type") + raise E.ANONSTRUCT(site, "function return type") arg_struct_defs = [] (inarg_asts, varargs) = asttype[1] @@ -1602,29 +1600,29 @@ def eval_type(asttype, site, location, scope, extern=False, typename=None, allow_void=True) if arg_struct_defs: (site, _) = arg_struct_defs[0] - raise EANONSTRUCT(site, "function argument type") + raise E.ANONSTRUCT(site, "function argument type") if argt.void: if len(inarg_asts) == 1 and not name: # C compatibility continue else: - raise EVOID(tsite) + raise E.VOID(tsite) inargs.append(argt) # Function parameters that are declared as arrays are # interpreted as pointers for i, arg in enumerate(inargs): - if isinstance(arg, TArray): + if isinstance(arg, tp.Array): # C99 has a syntax for specifying that the array # should be converted to a const pointer, but DML # doesn't support that syntax. - inargs[i] = TPtr(arg.base, False) + inargs[i] = tp.Ptr(arg.base, False) if arg.is_int and arg.is_endian: - raise EEARG(site) + raise E.EARG(site) if etype.is_int and etype.is_endian: - raise EEARG(site) - etype = TFunction(inargs, etype, varargs) + raise E.EARG(site) + etype = tp.Function(inargs, etype, varargs) asttype = asttype[2:] else: raise ICE(site, "weird type info: " + repr(asttype)) @@ -1632,7 +1630,7 @@ def eval_type(asttype, site, location, scope, extern=False, typename=None, etype.declaration_site = site if etype.void and not allow_void: - raise EVOID(site) + raise E.VOID(site) return (struct_defs, etype) @@ -1702,7 +1700,7 @@ def eval_method_inp(inp_asts, location, scope): if type_ast: (struct_defs, t) = eval_type(type_ast, tsite, location, scope) for (site, _) in struct_defs: - report(EANONSTRUCT(site, "method argument")) + report(E.ANONSTRUCT(site, "method argument")) else: t = None if ident.kind != 'discard': @@ -1722,7 +1720,7 @@ def eval_method_outp(outp_asts, location, scope): if type_ast: (struct_defs, t) = eval_type(type_ast, tsite, location, scope) for (site, _) in struct_defs: - report(EANONSTRUCT(site, "method out argument")) + report(E.ANONSTRUCT(site, "method out argument")) else: t = None outp.append((argname, t)) @@ -1731,14 +1729,14 @@ def eval_method_outp(outp_asts, location, scope): assert type_ast (struct_defs, t) = eval_type(type_ast, tsite, location, scope) for (site, _) in struct_defs: - report(EANONSTRUCT(site, "method return type")) + report(E.ANONSTRUCT(site, "method return type")) # In 1.4, output arguments are not user-visible, but _outN is used # by the generated C function if needed. outp.append(('_out%d' % (i,), t)) return outp def check_designated_initializers(site, etype, init_asts, allow_partial): - shallow_real_etype = safe_realtype_shallow(etype) + shallow_real_etype = tp.safe_realtype_shallow(etype) duplicates = set() bad_fields = set() remaining = set(shallow_real_etype.named_members) @@ -1750,7 +1748,7 @@ def check_designated_initializers(site, etype, init_asts, allow_partial): else: remaining.remove(field) if (duplicates or bad_fields or (not allow_partial and remaining)): - raise EDATAINIT(site, + raise E.DATAINIT(site, ''.join("\nduplicate initializer for " + f"member '{field}'" for field in duplicates) @@ -1789,39 +1787,39 @@ def loss_on_truncation(v, bits, signed): def mk_bitfield_compound_initializer_expr(site, etype, inits, location, scope, static): - bitfields_expr = mkIntegerLiteral(site, 0) + bitfields_expr = c.mkIntegerLiteral(site, 0) for ((ft, msb, lsb), e) in inits: - real_ft = safe_realtype(ft) + real_ft = tp.safe_realtype(ft) if e.kind == 'initializer_scalar': e = e.args[0] og_expr = codegen_expression(e, location, scope) if static and not og_expr.constant: - raise EDATAINIT(e.site, 'non-constant expression') - expr = source_for_assignment(e.site, ft, og_expr) + raise E.DATAINIT(e.site, 'non-constant expression') + expr = c.source_for_assignment(e.site, ft, og_expr) # TODO this warning and check could be generalized and moved to - # 'source_for_assignment' -- however, currently - # 'source_for_assignment' has no clearly defined semantics and is + # 'c.source_for_assignment' -- however, currently + # 'c.source_for_assignment' has no clearly defined semantics and is # used all over the place, leading to unexpected WASTRUNCs in # certain corner cases. - # Once these issues with 'source_for_assignment' have been + # Once these issues with 'c.source_for_assignment' have been # addressed, this warning and check should be moved there. - if (isinstance(og_expr, (FloatConstant, IntegerConstant)) + if (isinstance(og_expr, (c.FloatConstant, c.IntegerConstant)) and loss_on_truncation(og_expr.value, msb - lsb + 1, real_ft.signed)): - report(WASTRUNC(e.site, ft)) + report(W.ASTRUNC(e.site, ft)) else: if not real_ft.is_bitfields: designated = e.kind == 'initializer_designated_struct' - raise EDATAINIT(site, + raise E.DATAINIT(site, f'{"designated " * designated}compound ' + 'initializer not supported for type ' + str(ft)) init_asts = e.args[0] if e.kind == 'initializer_compound': if len(real_ft.members) != len(init_asts): - raise EDATAINIT(e.site, 'mismatched number of fields') + raise E.DATAINIT(e.site, 'mismatched number of fields') inits = zip((t[1:] for t in real_ft.members_qualified), init_asts) else: @@ -1833,19 +1831,19 @@ def mk_bitfield_compound_initializer_expr(site, etype, inits, location, scope, expr = mk_bitfield_compound_initializer_expr( e.site, ft, inits, location, scope, static) - # source_for_assignment doesn't always truncate when compat_dml12_int + # c.source_for_assignment doesn't always truncate when compat_dml12_int # is in play if dml.globals.compat_dml12_int(e.site): - expr = mkCast(e.site, expr, ft) + expr = c.mkCast(e.site, expr, ft) - shifted = mkShL(e.site, expr, mkIntegerLiteral(e.site, lsb)) - bitfields_expr = mkBitOr(e.site, bitfields_expr, shifted) + shifted = c.mkShL(e.site, expr, c.mkIntegerLiteral(e.site, lsb)) + bitfields_expr = c.mkBitOr(e.site, bitfields_expr, shifted) - return source_for_assignment(site, etype, bitfields_expr) + return c.source_for_assignment(site, etype, bitfields_expr) def eval_initializer(site, etype, astinit, location, scope, static): """Deconstruct an AST for an initializer, and return a - corresponding initializer object. Report EDATAINIT errors upon + corresponding initializer object. Report E.DATAINIT errors upon invalid initializers. Initializers are required to be constant for data objects and @@ -1859,76 +1857,76 @@ def eval_initializer(site, etype, astinit, location, scope, static): number of initializers must match the number of elements of compound data types.""" def do_eval(etype, astinit): - shallow_real_etype = safe_realtype_shallow(etype) + shallow_real_etype = tp.safe_realtype_shallow(etype) if astinit.kind == 'initializer_scalar': expr = codegen_expression(astinit.args[0], location, scope) if static and not expr.constant: - raise EDATAINIT(astinit.site, 'non-constant expression') + raise E.DATAINIT(astinit.site, 'non-constant expression') - return ExpressionInitializer( - source_for_assignment(astinit.site, etype, expr)) + return c.ExpressionInitializer( + c.source_for_assignment(astinit.site, etype, expr)) elif astinit.kind == 'initializer_designated_struct': (init_asts, allow_partial) = astinit.args - if isinstance(shallow_real_etype, StructType): + if isinstance(shallow_real_etype, tp.StructType): check_designated_initializers(astinit.site, etype, init_asts, allow_partial) inits = {field: do_eval(shallow_real_etype .get_member_qualified(field), init) for (field, init) in init_asts} - return DesignatedStructInitializer(site, inits) + return c.DesignatedStructInitializer(site, inits) elif shallow_real_etype.is_int and shallow_real_etype.is_bitfields: check_designated_initializers(astinit.site, etype, init_asts, allow_partial) - return ExpressionInitializer( + return c.ExpressionInitializer( mk_bitfield_compound_initializer_expr( astinit.site, etype, ((shallow_real_etype.get_member_qualified(field), init) for (field, init) in init_asts), location, scope, static)) else: - raise EDATAINIT(site, + raise E.DATAINIT(site, 'designated compound initializer not ' + f'supported for type {etype}') assert astinit.kind == 'initializer_compound' init_asts = astinit.args[0] - if isinstance(etype, TArray): + if isinstance(etype, tp.Array): assert isinstance(etype.size, Expression) if etype.size.constant: alen = etype.size.value else: - raise EDATAINIT(site, 'variable length array') + raise E.DATAINIT(site, 'variable length array') if alen != len(init_asts): - raise EDATAINIT(site, 'mismatched array size') + raise E.DATAINIT(site, 'mismatched array size') init = tuple(do_eval(etype.base, e) for e in init_asts) - return CompoundInitializer(site, init) - elif isinstance(etype, TStruct): + return c.CompoundInitializer(site, init) + elif isinstance(etype, tp.Struct): members = list(etype.members_qualified) if len(members) != len(init_asts): - raise EDATAINIT(site, 'mismatched number of fields') + raise E.DATAINIT(site, 'mismatched number of fields') init = tuple(do_eval(mt, e) for ((mn, mt), e) in zip(members, init_asts)) - return CompoundInitializer(site, init) - elif isinstance(etype, TExternStruct): + return c.CompoundInitializer(site, init) + elif isinstance(etype, tp.ExternStruct): if len(etype.named_members) != len(init_asts): - raise EDATAINIT(site, 'mismatched number of fields') + raise E.DATAINIT(site, 'mismatched number of fields') init = {mn: do_eval(mt, e) for ((mn, mt), e) in zip(etype.members_qualified, init_asts)} - return DesignatedStructInitializer(site, init) + return c.DesignatedStructInitializer(site, init) elif etype.is_int and etype.is_bitfields: if len(etype.members) != len(init_asts): - raise EDATAINIT(site, 'mismatched number of fields') - return ExpressionInitializer( + raise E.DATAINIT(site, 'mismatched number of fields') + return c.ExpressionInitializer( mk_bitfield_compound_initializer_expr( site, etype, zip((t[1:] for t in etype.members_qualified), init_asts), location, scope, static)) - elif isinstance(etype, TNamed): - return do_eval(safe_realtype(etype), astinit) + elif isinstance(etype, tp.Named): + return do_eval(tp.safe_realtype(etype), astinit) else: - raise EDATAINIT(site, + raise E.DATAINIT(site, 'compound initializer not supported for type %s' % etype) return do_eval(etype, astinit) @@ -1938,9 +1936,9 @@ def get_initializer(site, etype, astinit, location, scope): None. This also checks for an invalid 'etype'.""" # Check that the type is defined try: - typ = realtype(etype) - except DMLUnknownType: - raise ETYPE(site, etype) + typ = tp.realtype(etype) + except tp.DMLUnknownType: + raise E.TYPE(site, etype) if astinit: try: @@ -1952,23 +1950,23 @@ def get_initializer(site, etype, astinit, location, scope): # avoid C compiler warnings it's best to do it anyway. if typ.is_int: if typ.is_endian: - return MemsetInitializer(site) + return c.MemsetInitializer(site) else: - return ExpressionInitializer(mkIntegerLiteral(site, 0)) - elif isinstance(typ, TBool): - return ExpressionInitializer(mkBoolConstant(site, False)) + return c.ExpressionInitializer(c.mkIntegerLiteral(site, 0)) + elif isinstance(typ, tp.Bool): + return c.ExpressionInitializer(c.mkBoolConstant(site, False)) elif typ.is_float: - return ExpressionInitializer(mkFloatConstant(site, 0.0)) - elif isinstance(typ, (TStruct, TExternStruct, TArray, TTrait, THook)): - return MemsetInitializer(site) - elif isinstance(typ, TPtr): - return ExpressionInitializer(mkLit(site, 'NULL', typ)) - elif isinstance(typ, TVector): - return ExpressionInitializer(mkLit(site, 'VNULL', typ)) - elif isinstance(typ, TFunction): - raise EVARTYPE(site, etype.describe()) - elif isinstance(typ, TTraitList): - return ExpressionInitializer(mkLit(site, '{NULL, 0, 0, 0, 0}', typ)) + return c.ExpressionInitializer(c.mkFloatConstant(site, 0.0)) + elif isinstance(typ, (tp.Struct, tp.ExternStruct, tp.Array, tp.Trait, tp.Hook)): + return c.MemsetInitializer(site) + elif isinstance(typ, tp.Ptr): + return c.ExpressionInitializer(mkLit(site, 'NULL', typ)) + elif isinstance(typ, tp.Vector): + return c.ExpressionInitializer(mkLit(site, 'VNULL', typ)) + elif isinstance(typ, tp.Function): + raise E.VARTYPE(site, etype.describe()) + elif isinstance(typ, tp.TraitList): + return c.ExpressionInitializer(mkLit(site, '{NULL, 0, 0, 0, 0}', typ)) raise ICE(site, "No initializer for %r" % (etype,)) statement_dispatcher = ast.astdispatcher('stmt_') @@ -1986,7 +1984,7 @@ def codegen_statement(tree, *args): stmts = codegen_statements([tree], *args) if len(stmts) == 1 and not stmts[0].is_declaration: return stmts[0] - return mkCompound(tree.site, stmts) + return c.mkCompound(tree.site, stmts) @statement_dispatcher def stmt_compound(stmt, location, scope): @@ -2002,30 +2000,30 @@ def stmt_compound(stmt, location, scope): and assign.args[0].kind == 'set'): (lh, rh) = assign.args[0].args if lh.kind == 'variable_dml12' and lh.args[0] == outarg: - report(POUTARGRETURN(lh.site, + report(P.OUTARGRETURN(lh.site, dmlparse.start_site(rh.site), ret.site)) lscope = Symtab(scope) statements = codegen_statements(stmt_asts, location, lscope) - return [mkCompound(stmt.site, declarations(lscope) + statements, + return [c.mkCompound(stmt.site, declarations(lscope) + statements, rbrace_site)] def check_shadowing(scope, name, site): if (dml.globals.dml_version == (1, 2) and isinstance(scope.parent, MethodParamScope)): if scope.parent.lookup(name, local = True): - report(WDEPRECATED(site, - 'Variable %s in top-level method scope shadows parameter' + report(W.DEPRECATED(site, + 'c.Variable %s in top-level method scope shadows parameter' % name)) sym = scope.lookup(name, local = True) if sym: - raise EDVAR(site, sym.site, name) + raise E.DVAR(site, sym.site, name) def check_varname(site, name): if name in {'char', 'double', 'float', 'int', 'long', 'short', 'signed', 'unsigned', 'void', 'register'}: - report(ESYNTAX(site, name, 'type name used as variable name')) + report(E.SYNTAX(site, name, 'type name used as variable name')) @statement_dispatcher def stmt_local(stmt, location, scope): @@ -2038,7 +2036,7 @@ def stmt_local(stmt, location, scope): and inits[0].args[0].kind == 'apply'): method_call_init = True elif len(decls) != len(inits): - raise ESYNTAX(stmt.site, None, + raise E.SYNTAX(stmt.site, None, 'wrong number of initializers:\n' + f'{len(decls)} variables declared\n' + f'{len(inits)} initializers specified') @@ -2052,11 +2050,11 @@ def convert_decl(decl_ast): and breaking_changes.dml12_remove_misc_quirks.enabled): check_varname(stmt.site, name) (struct_decls, etype) = eval_type(asttype, stmt.site, location, scope) - stmts.extend(mkStructDefinition(site, t) for (site, t) in struct_decls) + stmts.extend(c.mkStructDefinition(site, t) for (site, t) in struct_decls) etype = etype.resolve() - rt = safe_realtype_shallow(etype) - if isinstance(rt, TArray) and not rt.size.constant and deep_const(rt): - raise EVLACONST(stmt.site) + rt = tp.safe_realtype_shallow(etype) + if isinstance(rt, tp.Array) and not rt.size.constant and tp.deep_const(rt): + raise E.VLACONST(stmt.site) if name is not None: check_shadowing(scope, name, stmt.site) return (ident_ast.site, name, etype) @@ -2065,7 +2063,7 @@ def convert_decl(decl_ast): def mk_sym(name, typ, mkunique=not dml.globals.debuggable): cname = scope.unique_cname(name) if mkunique else name - return LocalSymbol(name, cname, type=typ, site=stmt.site, stmt=True) + return symtab.LocalSymbol(name, cname, type=typ, site=stmt.site, stmt=True) if method_call_init: syms_to_add = [] @@ -2075,35 +2073,35 @@ def mk_sym(name, typ, mkunique=not dml.globals.debuggable): for (ident_site, name, typ) in decls: if name is None: - tgts.append(mkDiscardRef(ident_site, - safe_realtype_unconst(typ))) + tgts.append(c.mkDiscardRef(ident_site, + tp.safe_realtype_unconst(typ))) continue sym = mk_sym(name, typ) - tgt_typ = safe_realtype_shallow(typ) - if shallow_const(tgt_typ): - nonconst_typ = safe_realtype_unconst(tgt_typ) + tgt_typ = tp.safe_realtype_shallow(typ) + if tp.shallow_const(tgt_typ): + nonconst_typ = tp.safe_realtype_unconst(tgt_typ) tgt_sym = mk_sym('_tmp_' + name, nonconst_typ, True) - sym.init = ExpressionInitializer(mkLocalVariable(ident_site, + sym.init = c.ExpressionInitializer(c.mkLocalVariable(ident_site, tgt_sym)) late_declared_syms.append(sym) else: tgt_sym = sym syms_to_add.append(sym) tgt_syms.append(tgt_sym) - tgts.append(mkLocalVariable(ident_site, tgt_sym)) + tgts.append(c.mkLocalVariable(ident_site, tgt_sym)) method_invocation = try_codegen_invocation(stmt.site, inits, tgts, location, scope) if method_invocation is not None and stmt.site.dml_version != (1, 2): for sym in syms_to_add: scope.add(sym) - stmts.extend(sym_declaration(sym) for sym in tgt_syms) + stmts.extend(c.sym_declaration(sym) for sym in tgt_syms) stmts.append(method_invocation) - stmts.extend(sym_declaration(sym) for sym in late_declared_syms) + stmts.extend(c.sym_declaration(sym) for sym in late_declared_syms) else: if len(decls) != 1: - report(ERETLVALS(stmt.site, 1, len(decls))) + report(E.RETLVALS(stmt.site, 1, len(decls))) else: (_, _, typ) = decls[0] init = eval_initializer( @@ -2113,13 +2111,13 @@ def mk_sym(name, typ, mkunique=not dml.globals.debuggable): sym = syms_to_add[0] sym.init = init scope.add(sym) - stmts.append(sym_declaration(sym)) + stmts.append(c.sym_declaration(sym)) else: # Discard identifier in play - stmts.append(mkExpressionStatement( + stmts.append(c.mkExpressionStatement( stmt.site, init.as_expr(typ), explicit_discard=True)) else: - # Initializer evaluation and variable declarations are done in separate + # c.Initializer evaluation and variable declarations are done in separate # passes in order to prevent the newly declared variables from being in # scope when the initializers are evaluated inits = [get_initializer(stmt.site, typ, init, location, scope) @@ -2130,15 +2128,15 @@ def mk_sym(name, typ, mkunique=not dml.globals.debuggable): sym = scope.add_variable( name, type = typ, site = ident_site, init = init, stmt = True, make_unique=not dml.globals.debuggable) - stmts.append(sym_declaration(sym)) + stmts.append(c.sym_declaration(sym)) elif init is None: # Corresponds to e.g. 'local int _;' # This would be pointless except for the niche case of # forcing an error if a type is invalid - check_named_types(typ) - stmts.append(mkNoop(ident_site)) + tp.check_named_types(typ) + stmts.append(c.mkNoop(ident_site)) else: - stmts.append(mkExpressionStatement( + stmts.append(c.mkExpressionStatement( init.site, init.as_expr(typ), explicit_discard=True)) return stmts @@ -2149,7 +2147,7 @@ def stmt_session(stmt, location, scope): if inits is None: inits = itertools.cycle([None]) elif len(decls) != len(inits): - raise ESYNTAX(stmt.site, None, + raise E.SYNTAX(stmt.site, None, 'wrong number of initializers:\n' + f'{len(decls)} variables declared\n' + f'{len(inits)} initializers specified') @@ -2164,13 +2162,13 @@ def stmt_session(stmt, location, scope): + "not yet allowed") elif (not dml.globals.dml_version == (1, 2) and not location.method().fully_typed): - raise ESTOREDINLINE(stmt.site, 'session') + raise E.STOREDINLINE(stmt.site, 'session') for (decl_ast, init) in zip(decls, inits): (name, asttype) = decl_ast.args (struct_decls, etype) = eval_type(asttype, stmt.site, location, global_scope) etype = etype.resolve() - add_late_global_struct_defs(struct_decls) + tp.add_late_global_struct_defs(struct_decls) if init: try: init = eval_initializer( @@ -2182,7 +2180,7 @@ def stmt_session(stmt, location, scope): static_var_expr = make_static_var(stmt.site, location, etype, name, init, stmt) - local_sym = ExpressionSymbol(name, static_var_expr, stmt.site) + local_sym = c.ExpressionSymbol(name, static_var_expr, stmt.site) scope.add(local_sym) return [] @@ -2192,30 +2190,30 @@ def make_static_var(site, location, static_sym_type, name, init=None, # generate a nested array of variables, indexed into by # the dimensions of the method dimensions for dimsize in reversed(location.method().dimsizes): - static_sym_type = TArray(static_sym_type, - mkIntegerConstant(site, dimsize, False)) + static_sym_type = tp.Array(static_sym_type, + c.mkIntegerConstant(site, dimsize, False)) # initializer in methods cannot currently depend on indices # so we can replicate the same initializer for all # slots in the array. # TODO: it should be possible to support # index-dependent initialization now, though if init is not None: - init = CompoundInitializer(site, [init] * dimsize) + init = c.CompoundInitializer(site, [init] * dimsize) static_sym_name = f'static{len(dml.globals.static_vars)}_{name}' - static_sym = StaticSymbol(static_sym_name, static_sym_name, + static_sym = symtab.StaticSymbol(static_sym_name, static_sym_name, static_sym_type, site, init, stmt) - static_var_expr = mkStaticVariable(site, static_sym) + static_var_expr = c.mkStaticVariable(site, static_sym) for idx in location.indices: - static_var_expr = mkIndex(site, static_var_expr, idx) + static_var_expr = c.mkIndex(site, static_var_expr, idx) if init is not None: - assert isinstance(init, Initializer) + assert isinstance(init, c.Initializer) init_code = output.StrOutput() with init_code: - if deep_const(static_sym_type): - coverity_marker('store_writes_const_field', 'FALSE') - out(init.assign_to(mkStaticVariable(site, static_sym).read(), + if tp.deep_const(static_sym_type): + output.coverity_marker('store_writes_const_field', 'FALSE') + out(init.assign_to(c.mkStaticVariable(site, static_sym).read(), static_sym_type) + ';\n') c_init = init_code.buf else: @@ -2232,7 +2230,7 @@ def stmt_saved(stmt, location, scope): if inits is None: inits = itertools.cycle([None]) elif len(decls) != len(inits): - raise ESYNTAX(stmt.site, None, + raise E.SYNTAX(stmt.site, None, 'wrong number of initializers:\n' + f'{len(decls)} variables declared\n' + f'{len(inits)} initializers specified') @@ -2250,12 +2248,12 @@ def stmt_saved(stmt, location, scope): raise ICE(stmt.site, "'saved' declaration inside a shared method is " + "not yet allowed") elif not location.method().fully_typed: - raise ESTOREDINLINE(stmt.site, 'saved') + raise E.STOREDINLINE(stmt.site, 'saved') for (decl_ast, init) in zip(decls, inits): (name, asttype) = decl_ast.args (struct_decls, etype) = eval_type(asttype, stmt.site, location, scope) - add_late_global_struct_defs(struct_decls) + tp.add_late_global_struct_defs(struct_decls) etype.resolve() if init: try: @@ -2277,19 +2275,19 @@ def stmt_saved(stmt, location, scope): static_var_expr = make_static_var(stmt.site, location, etype, name, init, stmt, True) - local_sym = ExpressionSymbol(name, static_var_expr, stmt.site) + local_sym = c.ExpressionSymbol(name, static_var_expr, stmt.site) scope.add(local_sym) return [] @statement_dispatcher def stmt_null(stmt, location, scope): - return [mkNull(stmt.site)] + return [c.mkNull(stmt.site)] @statement_dispatcher def stmt_if(stmt, location, scope): [cond_ast, truebranch, falsebranch, else_site] = stmt.args - cond = as_bool(codegen_expression(cond_ast, location, scope)) + cond = c.as_bool(codegen_expression(cond_ast, location, scope)) if cond.constant and stmt.site.dml_version() == (1, 2): if (logging.show_porting and not stmt.site.filename().endswith('dml-builtins.dml')): @@ -2301,16 +2299,16 @@ def stmt_if(stmt, location, scope): elif falsebranch: codegen_statement(falsebranch, location, scope) if errors: - report(PHASH(stmt.site)) + report(P.HASH(stmt.site)) if falsebranch: - report(PHASHELSE(else_site, 'else')) + report(P.HASHELSE(else_site, 'else')) if (not falsebranch and cond_ast.kind == 'binop' and cond_ast.args[1] == '&&'): - lh = as_bool(codegen_expression(cond_ast.args[0], location, scope)) + lh = c.as_bool(codegen_expression(cond_ast.args[0], location, scope)) with logging.suppress_errors() as errors: - as_bool(codegen_expression(cond_ast.args[2], location, scope)) + c.as_bool(codegen_expression(cond_ast.args[2], location, scope)) if lh.constant and not lh.value and errors: - report(PIFAND(cond_ast.site, stmt.site, dmlparse.end_site(truebranch.site))) + report(P.IFAND(cond_ast.site, stmt.site, dmlparse.end_site(truebranch.site))) if cond.value: return codegen_statements([truebranch], location, scope) elif falsebranch: @@ -2329,9 +2327,9 @@ def stmt_if(stmt, location, scope): @statement_dispatcher def stmt_hashif(stmt, location, scope): [cond_ast, truebranch, falsebranch] = stmt.args - cond = as_bool(codegen_expression(cond_ast, location, scope)) + cond = c.as_bool(codegen_expression(cond_ast, location, scope)) if not cond.constant: - raise ENCONST(cond_ast.site, cond) + raise E.NCONST(cond_ast.site, cond) if cond.value: return [codegen_statement(truebranch, location, scope)] elif falsebranch: @@ -2356,10 +2354,10 @@ def try_codegen_invocation(site, init_ast, outargs, location, scope): meth_expr = codegen_expression_maybe_nonvalue(meth_ast, location, scope) if (isinstance(meth_expr, NonValue) and not isinstance(meth_expr, ( - TraitMethodRef, NodeRef, InterfaceMethodRef, HookSendNowRef, - HookSendRef))): + c.TraitMethodRef, c.NodeRef, c.InterfaceMethodRef, c.HookSendNowRef, + c.HookSendRef))): raise meth_expr.exc() - if isinstance(meth_expr, TraitMethodRef): + if isinstance(meth_expr, c.TraitMethodRef): if not meth_expr.throws and len(meth_expr.outp) <= 1: # let the caller represent the method invocation as an # expression instead @@ -2368,12 +2366,12 @@ def try_codegen_invocation(site, init_ast, outargs, location, scope): and not in_try_block(location) and meth_expr.throws): # Shared methods marked as 'throws' count as # unconditionally throwing - EBADFAIL_dml12.throwing_methods[location.method()] = site + E.BADFAIL_dml12.throwing_methods[location.method()] = site inargs = typecheck_inarg_inits(meth_expr.site, inarg_asts, meth_expr.inp, location, scope, 'method') return codegen_call_traitmethod(site, meth_expr, inargs, outargs) - elif not isinstance(meth_expr, NodeRef): + elif not isinstance(meth_expr, c.NodeRef): return None # indeed a method invocation (meth_node, indices) = meth_expr.get_ref() @@ -2402,8 +2400,8 @@ def try_codegen_invocation(site, init_ast, outargs, location, scope): and meth_node.site.dml_version() == (1, 2) and meth_node.throws): if dml12_method_throws_in_dml14(meth_node): - report(EBADFAIL_dml12(site, [(meth_node.site, meth_node)], [])) - EBADFAIL_dml12.protected_calls.setdefault( + report(E.BADFAIL_dml12(site, [(meth_node.site, meth_node)], [])) + E.BADFAIL_dml12.protected_calls.setdefault( meth_node, []).append((site, location.method())) f = CatchFailure(scope, location.method()) with f: @@ -2412,8 +2410,8 @@ def try_codegen_invocation(site, init_ast, outargs, location, scope): if meth_node.fully_typed else common_inline(site, meth_node, indices, inargs, outargs)) - return mkTryCatch(site, f.label, call, - mkAssert(site, mkBoolConstant(site, False))) + return c.mkTryCatch(site, f.label, call, + c.mkAssert(site, c.mkBoolConstant(site, False))) else: inargs = typecheck_inarg_inits(meth_expr.site, inarg_asts, @@ -2426,14 +2424,14 @@ def try_codegen_invocation(site, init_ast, outargs, location, scope): def codegen_init_for_untyped_target(site, tgt, src_ast, location, scope): if not tgt.writable: - raise EASSIGN(site, tgt) + raise E.ASSIGN(site, tgt) if src_ast.kind != 'initializer_scalar': - raise EDATAINIT(tgt.site, + raise E.DATAINIT(tgt.site, f'{tgt} can only be used as the target ' + 'of an assignment if its initializer is a ' + 'simple expression or a return value of a ' + 'method call') - return ExpressionInitializer( + return c.ExpressionInitializer( codegen_expression(src_ast.args[0], location, scope)) @statement_dispatcher @@ -2443,8 +2441,8 @@ def stmt_assign(stmt, location, scope): tgts = [codegen_expression_maybe_nonvalue(ast, location, scope) for ast in tgt_ast.args[0]] for tgt in tgts: - if not isinstance(tgt, NonValue) and deep_const(tgt.ctype()): - raise ECONST(tgt.site) + if not isinstance(tgt, NonValue) and tp.deep_const(tgt.ctype()): + raise E.CONST(tgt.site) if tgt_ast.kind == 'assign_target_chain': method_tgts = [tgts[0]] else: @@ -2454,13 +2452,13 @@ def stmt_assign(stmt, location, scope): location, scope) if method_invocation: if tgt_ast.kind == 'assign_target_chain' and len(tgts) != 1: - report(ESYNTAX( + report(E.SYNTAX( tgt_ast.args[0][1].site, '=', 'assignment chain not allowed as method invocation target')) return [method_invocation] if tgt_ast.kind == 'assign_target_chain': if len(src_asts) > 1: - report(ESYNTAX(site, '(', + report(E.SYNTAX(site, '(', 'wrong number of simultaneous assign targets for ' + f'initializer: Expected {src_asts}, got 1')) return [] @@ -2479,30 +2477,30 @@ def stmt_assign(stmt, location, scope): location, scope)) if len(tgts) == 1: - return [mkAssignStatement(tgts[0].site, tgts[0], init)] + return [c.mkAssignStatement(tgts[0].site, tgts[0], init)] lscope = Symtab(scope) sym = lscope.add_variable( '_tmp', type=init_typ, site=init.site, init=init, stmt=True) - init_expr = mkLocalVariable(init.site, sym) - stmts = [sym_declaration(sym)] + init_expr = c.mkLocalVariable(init.site, sym) + stmts = [c.sym_declaration(sym)] for tgt in reversed(tgts[1:]): - stmts.append(mkCopyData(tgt.site, init_expr, tgt)) + stmts.append(c.mkCopyData(tgt.site, init_expr, tgt)) init_expr = (tgt if isinstance(tgt, NonValue) - else source_for_assignment(tgt.site, tgt.ctype(), + else c.source_for_assignment(tgt.site, tgt.ctype(), init_expr)) - stmts.append(mkCopyData(tgts[0].site, init_expr, tgts[0])) - return [mkCompound(site, stmts)] + stmts.append(c.mkCopyData(tgts[0].site, init_expr, tgts[0])) + return [c.mkCompound(site, stmts)] else: # Guaranteed by grammar assert tgt_ast.kind == 'assign_target_tuple' and len(tgts) > 1 if (len(src_asts) == 1 and src_asts[0].kind == 'initializer_scalar' and src_asts[0].args[0].kind == 'apply'): - report(ERETLVALS(site, 1, len(tgts))) + report(E.RETLVALS(site, 1, len(tgts))) return [] elif len(src_asts) != len(tgts): - report(ESYNTAX(site, '(', + report(E.SYNTAX(site, '(', 'wrong number of simultaneous assign targets for ' + f'initializer: Expected {src_asts}, got ' + str(tgts))) @@ -2518,7 +2516,7 @@ def stmt_assign(stmt, location, scope): if tgt.explicit_type else codegen_init_for_untyped_target(site, tgt, src_ast, location, scope)) - stmt_pairs.append((mkAssignStatement(tgt.site, tgt, init), + stmt_pairs.append((c.mkAssignStatement(tgt.site, tgt, init), None)) else: init = eval_initializer(site, tgt.ctype(), src_ast, location, @@ -2527,15 +2525,15 @@ def stmt_assign(stmt, location, scope): sym = lscope.add_variable( name, type=tgt.ctype(), site=tgt.site, init=init, stmt=True) - write = AssignStatement( + write = c.AssignStatement( tgt.site, tgt, - ExpressionInitializer(mkLocalVariable(tgt.site, sym))) - stmt_pairs.append((sym_declaration(sym), write)) + c.ExpressionInitializer(c.mkLocalVariable(tgt.site, sym))) + stmt_pairs.append((c.sym_declaration(sym), write)) stmts.extend(first for (first, _) in stmt_pairs) stmts.extend(second for (_, second) in stmt_pairs if second is not None) - return [mkCompound(site, stmts)] + return [c.mkCompound(site, stmts)] @statement_dispatcher def stmt_assignop(stmt, location, scope): @@ -2543,36 +2541,36 @@ def stmt_assignop(stmt, location, scope): tgt = codegen_expression(tgt_ast, location, scope) if isinstance(tgt, ctree.InlinedParam): - raise EASSINL(tgt.site, tgt.name) + raise E.ASSINL(tgt.site, tgt.name) if not tgt.writable: - raise EASSIGN(site, tgt) + raise E.ASSIGN(site, tgt) ttype = tgt.ctype() - if deep_const(ttype): - raise ECONST(tgt.site) + if tp.deep_const(ttype): + raise E.CONST(tgt.site) src = codegen_expression(src_ast, location, scope) - if tgt.addressable and not isinstance(tgt, Variable): + if tgt.addressable and not isinstance(tgt, c.Variable): lscope = Symtab(scope) tmp_tgt_sym = lscope.add_variable( - '_tmp_tgt', type = TPtr(ttype), site = tgt.site, - init = ExpressionInitializer(mkAddressOf(tgt.site, tgt)), + '_tmp_tgt', type = tp.Ptr(ttype), site = tgt.site, + init = c.ExpressionInitializer(c.mkAddressOf(tgt.site, tgt)), stmt=True) # Side-Effect Free representation of the tgt lvalue - tgt = mkDereference(site, mkLocalVariable(tgt.site, tmp_tgt_sym)) + tgt = c.mkDereference(site, c.mkLocalVariable(tgt.site, tmp_tgt_sym)) else: # TODO Not ideal. This path is needed to deal with writable # expressions that do not correspond to C lvalues, such as bit slices. # The incurred repeated evaluation is painful. tmp_tgt_sym = None - assign_src = source_for_assignment(site, ttype, + assign_src = c.source_for_assignment(site, ttype, arith_binops[op[:-1]](site, tgt, src)) - return [mkCompound(site, - ([sym_declaration(tmp_tgt_sym)] if tmp_tgt_sym else []) - + [mkExpressionStatement(site, + return [c.mkCompound(site, + ([c.sym_declaration(tmp_tgt_sym)] if tmp_tgt_sym else []) + + [c.mkExpressionStatement(site, ctree.AssignOp(site, tgt, assign_src))])] @statement_dispatcher def stmt_expression(stmt, location, scope): @@ -2585,28 +2583,28 @@ def stmt_expression(stmt, location, scope): [], location, scope) if invocation: return [invocation] - return [mkExpressionStatement(stmt.site, + return [c.mkExpressionStatement(stmt.site, codegen_expression(expr, location, scope))] @statement_dispatcher def stmt_throw(stmt, location, scope): handler = Failure.fail_stack[-1] if not handler.allowed: - raise EBADFAIL(stmt.site) + raise E.BADFAIL(stmt.site) if dml.globals.dml_version == (1, 2) and not in_try_block(location): - EBADFAIL_dml12.throwing_methods[location.method()] = stmt.site + E.BADFAIL_dml12.throwing_methods[location.method()] = stmt.site return [handler.fail(stmt.site)] @statement_dispatcher def stmt_error(stmt, location, scope): [msg] = stmt.args - raise EERRSTMT(stmt.site, "forced compilation error in source code" + raise E.ERRSTMT(stmt.site, "forced compilation error in source code" if msg is None else msg) @statement_dispatcher def stmt_warning(stmt, location, scope): [msg] = stmt.args - report(WWRNSTMT(stmt.site, msg)) + report(W.WRNSTMT(stmt.site, msg)) return [] @statement_dispatcher @@ -2614,7 +2612,7 @@ def stmt_return_dml12(stmt, location, scope): if logging.show_porting: m = location.method() if m and m.outp: - report(PRETURNARGS(stmt.site, [name for (name, _) in m.outp])) + report(P.RETURNARGS(stmt.site, [name for (name, _) in m.outp])) [args] = stmt.args assert not args # ensured by parser return [codegen_exit(stmt.site, None)] @@ -2636,9 +2634,9 @@ def stmt_return(stmt, location, scope): meth_expr = codegen_expression_maybe_nonvalue( inits[0].args[0].args[0], location, scope) site = meth_expr.site - if isinstance(meth_expr, TraitMethodRef): + if isinstance(meth_expr, c.TraitMethodRef): outp = meth_expr.outp - elif isinstance(meth_expr, NodeRef): + elif isinstance(meth_expr, c.NodeRef): (meth_node, indices) = meth_expr.get_ref() if meth_node.objtype == 'method': outp = meth_node.outp @@ -2647,24 +2645,24 @@ def stmt_return(stmt, location, scope): outarg_syms = [ lscope.add_variable(f'tmp{i}', type=typ, site=site, stmt=True) for (i, (_, typ)) in enumerate(outp)] - outargs = [mkLocalVariable(site, sym) for sym in outarg_syms] + outargs = [c.mkLocalVariable(site, sym) for sym in outarg_syms] method_invocation = try_codegen_invocation(site, inits, outargs, location, scope) if method_invocation is not None: if len(outargs) != len(outp_typs): - report(ERETARGS(stmt.site, len(outp_typs), len(outargs))) + report(E.RETARGS(stmt.site, len(outp_typs), len(outargs))) # avoid control flow errors by falling back to statement # with no fall-through - return [mkAssert(stmt.site, - mkBoolConstant(stmt.site, False))] + return [c.mkAssert(stmt.site, + c.mkBoolConstant(stmt.site, False))] - return ([sym_declaration(sym) for sym in outarg_syms] + return ([c.sym_declaration(sym) for sym in outarg_syms] + [method_invocation, codegen_exit(stmt.site, outargs)]) if len(inits) != len(outp_typs): - report(ERETARGS(stmt.site, len(outp_typs), len(inits))) - return [mkAssert(stmt.site, mkBoolConstant(stmt.site, False))] + report(E.RETARGS(stmt.site, len(outp_typs), len(inits))) + return [c.mkAssert(stmt.site, c.mkBoolConstant(stmt.site, False))] return [codegen_exit(stmt.site, [eval_initializer(stmt.site, typ, init, location, @@ -2675,62 +2673,62 @@ def stmt_return(stmt, location, scope): def stmt_assert(stmt, location, scope): [expr] = stmt.args expr = codegen_expression(expr, location, scope) - return [mkAssert(stmt.site, as_bool(expr))] + return [c.mkAssert(stmt.site, c.as_bool(expr))] @statement_dispatcher def stmt_goto(stmt, location, scope): [label] = stmt.args if breaking_changes.dml12_remove_goto.enabled: - report(ESYNTAX(stmt.site, 'goto', 'goto statement not allowed')) - return [mkGoto(stmt.site, label)] + report(E.SYNTAX(stmt.site, 'goto', 'goto statement not allowed')) + return [c.mkGoto(stmt.site, label)] @statement_dispatcher def stmt_label(stmt, location, scope): [label, statement] = stmt.args - return [mkLabel(stmt.site, label), + return [c.mkLabel(stmt.site, label), codegen_statement(statement, location, scope)] @statement_dispatcher def stmt_case_dml12(stmt, location, scope): [expr_ast, statement] = stmt.args expr = codegen_expression(expr_ast, location, scope) - return [mkCase(stmt.site, expr), + return [c.mkCase(stmt.site, expr), codegen_statement(statement, location, scope)] @statement_dispatcher def stmt_default_dml12(stmt, location, scope): [statement] = stmt.args - return [mkDefault(stmt.site), codegen_statement(statement, location, scope)] + return [c.mkDefault(stmt.site), codegen_statement(statement, location, scope)] @statement_dispatcher def stmt_case(stmt, location, scope): [expr_ast] = stmt.args expr = codegen_expression(expr_ast, location, scope) - return [mkCase(stmt.site, expr)] + return [c.mkCase(stmt.site, expr)] @statement_dispatcher def stmt_default(stmt, location, scope): assert not stmt.args - return [mkDefault(stmt.site)] + return [c.mkDefault(stmt.site)] @statement_dispatcher def stmt_delete(stmt, location, scope): [expr] = stmt.args expr = codegen_expression(expr, location, scope) - return [mkDelete(stmt.site, expr)] + return [c.mkDelete(stmt.site, expr)] def probable_loggroups_specification(expr): subexprs = [expr] while subexprs: expr = subexprs.pop() - if (isinstance(expr, LogGroup) + if (isinstance(expr, c.LogGroup) or (expr.constant and expr.value == 0)): return True - if isinstance(expr, Cast): + if isinstance(expr, c.Cast): subexprs.append(expr.expr) - elif isinstance(expr, (BitOr, BitOr_dml12)): + elif isinstance(expr, (c.BitOr, c.BitOr_dml12)): subexprs.extend((expr.lh, expr.rh)) - elif isinstance(expr, IfExpr): + elif isinstance(expr, c.IfExpr): subexprs.extend((expr.texpr, expr.fexpr)) return False @@ -2741,15 +2739,15 @@ def probable_loglevel_specification(expr): while subexprs: expr = subexprs.pop() - if (isinstance(expr, LogGroup) + if (isinstance(expr, c.LogGroup) or (expr.constant and expr.value == 0)): return False if expr.constant and 1 <= expr.value <= 5: probable = True - elif isinstance(expr, Cast): + elif isinstance(expr, c.Cast): subexprs.append(expr.expr) - elif isinstance(expr, IfExpr): + elif isinstance(expr, c.IfExpr): subexprs.extend((expr.texpr, expr.fexpr)) return probable @@ -2776,26 +2774,26 @@ def stmt_log(stmt, location, scope): # breaking_changes.dml_meaningless_log_levels, otherwise existing usages of # e.g. log error, 2: "..." will become noops if bad_error_level: - adjusted_level = mkIntegerLiteral(site, 1) + adjusted_level = c.mkIntegerLiteral(site, 1) if breaking_changes.restrict_log_levels.enabled: if bad_error_level: - report(ELLEV(level.site, "1")) + report(E.LLEV(level.site, "1")) elif level.constant and not (1 <= level.value <= 4): - report(ELLEV(level.site, "an integer between 1 and 4")) - adjusted_level = mkIntegerLiteral(site, 1) + report(E.LLEV(level.site, "an integer between 1 and 4")) + adjusted_level = c.mkIntegerLiteral(site, 1) else: warn_mixup = probable_loggroups_specification(level) # Acquire a subsequent log key and the logging object based on obj or trait # identity if location.method(): - identity = ObjIdentity(site, location.node.parent, location.indices) - logobj = log_object(site, location.node, location.indices) + identity = c.ObjIdentity(site, location.node.parent, location.indices) + logobj = c.log_object(site, location.node, location.indices) else: - identity = TraitObjIdentity(site, lookup_var(site, scope, "this")) - logobj = (PortObjectFromObjIdentity(site, identity) + identity = c.TraitObjIdentity(site, c.lookup_var(site, scope, "this")) + logobj = (c.PortObjectFromObjIdentity(site, identity) if breaking_changes.shared_logs_locally.enabled - else log_object(site, dml.globals.device, ())) + else c.log_object(site, dml.globals.device, ())) log_wrapper = lambda stmt: stmt @@ -2804,46 +2802,46 @@ def stmt_log(stmt, location, scope): later_level, location, scope)) if (later_level.constant and level.constant and later_level.value == level.value): - report(WREDUNDANTLEVEL(site)) + report(W.REDUNDANTLEVEL(site)) if (error_logkind and breaking_changes.restrict_log_levels.enabled): if not later_level.constant or later_level.value not in {1, 5}: - report(ELLEV(later_level.site, "a 1 or 5 constant")) - adjusted_later_level = mkIntegerLiteral(site, 1) + report(E.LLEV(later_level.site, "a 1 or 5 constant")) + adjusted_later_level = c.mkIntegerLiteral(site, 1) elif (later_level.constant and not (1 <= later_level.value <= 5)): - report(ELLEV(later_level.site, "an integer between 1 and 5")) - adjusted_later_level = mkIntegerLiteral(site, 4) + report(E.LLEV(later_level.site, "an integer between 1 and 5")) + adjusted_later_level = c.mkIntegerLiteral(site, 4) elif not warn_mixup: warn_mixup = probable_loggroups_specification(later_level) global log_index - table_ptr = TPtr(TNamed("ht_int_table_t")) + table_ptr = tp.Ptr(tp.Named("ht_int_table_t")) table = mkLit(site, '&(_dev->_subsequent_log_ht)', table_ptr) key = mkApply(site, mkLit(site, "_identity_to_key", - TFunction([TNamed('_identity_t')], - TInt(64, False))), + tp.Function([tp.Named('_identity_t')], + tp.Int(64, False))), [identity]) once_lookup = mkLit( site, "_select_log_level", - TFunction([table_ptr, TInt(64, False), TInt(64, False), - TInt(64, False), TInt(64, False)], - TInt(64, False))) + tp.Function([table_ptr, tp.Int(64, False), tp.Int(64, False), + tp.Int(64, False), tp.Int(64, False)], + tp.Int(64, False))) level_expr = mkApply(site, once_lookup, - [table, key, mkIntegerLiteral(site, log_index), + [table, key, c.mkIntegerLiteral(site, log_index), adjusted_level, adjusted_later_level]) log_index += 1 - pre_statements = [mkDeclaration(site, "_calculated_level", - TInt(64, False), - ExpressionInitializer(level_expr))] - adjusted_level = mkLocalVariable(site, LocalSymbol("_calculated_level", + pre_statements = [c.mkDeclaration(site, "_calculated_level", + tp.Int(64, False), + c.ExpressionInitializer(level_expr))] + adjusted_level = c.mkLocalVariable(site, symtab.LocalSymbol("_calculated_level", "_calculated_level", - TInt(64, False), + tp.Int(64, False), site=site)) if error_logkind: - log_wrapper = lambda stmt: mkIf( + log_wrapper = lambda stmt: c.mkIf( site, - mkEquals(site, adjusted_level, mkIntegerLiteral(site, 1)), + c.mkEquals(site, adjusted_level, c.mkIntegerLiteral(site, 1)), stmt) else: pre_statements = [] @@ -2851,10 +2849,10 @@ def stmt_log(stmt, location, scope): groups = ctree.as_int(codegen_expression(groups, location, scope)) warn_mixup = warn_mixup or probable_loglevel_specification(groups) if warn_mixup: - report(WLOGMIXUP(site, logkind, level, later_level, groups)) + report(W.LOGMIXUP(site, logkind, level, later_level, groups)) fmt, args = fix_printf(fmt, args, argsites, site) - return [mkCompound(site, pre_statements + [ - log_wrapper(log_statement(site, logobj, logkind, adjusted_level, + return [c.mkCompound(site, pre_statements + [ + log_wrapper(c.log_statement(site, logobj, logkind, adjusted_level, groups, fmt, *args))])] @statement_dispatcher def stmt_try(stmt, location, scope): @@ -2866,7 +2864,7 @@ def stmt_try(stmt, location, scope): if dml.globals.dml_version == (1, 2) and not f.label: return [tryblock] excblock = codegen_statement(excblock, location, scope) - return [mkTryCatch(stmt.site, f.label, tryblock, excblock)] + return [c.mkTryCatch(stmt.site, f.label, tryblock, excblock)] @statement_dispatcher def stmt_after(stmt, location, scope): @@ -2881,7 +2879,7 @@ def stmt_after(stmt, location, scope): method_ast = callexpr inargs = [] else: - raise ESYNTAX(site, None, + raise E.SYNTAX(site, None, 'callback expression to after statement must be a ' + 'function application') @@ -2890,55 +2888,55 @@ def stmt_after(stmt, location, scope): if unit == 's': clock = 'SIM_object_clock(&_dev->obj)' api_unit = 'time' - unit_type = TFloat('double') + unit_type = tp.Float('double') elif unit == 'cycles': clock = 'SIM_object_clock(&_dev->obj)' api_unit = 'cycle' - unit_type = TInt(64, True) + unit_type = tp.Int(64, True) elif unit == 'ps': clock = 'SIM_picosecond_clock(&_dev->obj)' api_unit = 'cycle' - unit_type = TInt(64, True) + unit_type = tp.Int(64, True) else: raise ICE(site, f"Unsupported unit of time: '{unit}'") try: - delay = source_for_assignment(site, unit_type, delay) - except EASTYPE: - raise EBTYPE(site, old_delay_type, unit_type) + delay = c.source_for_assignment(site, unit_type, delay) + except E.ASTYPE: + raise E.BTYPE(site, old_delay_type, unit_type) - if unit in {'cycles', 'ps'} and not safe_realtype(old_delay_type).is_int: - report(WTTYPEC(site, old_delay_type, unit_type, unit)) + if unit in {'cycles', 'ps'} and not tp.safe_realtype(old_delay_type).is_int: + report(W.TTYPEC(site, old_delay_type, unit_type, unit)) # TODO after statement should be extended to allow the user to explicitly # give the domains if location.method(): - domains = [ObjIdentity(site, location.node.parent, location.indices)] + domains = [c.ObjIdentity(site, location.node.parent, location.indices)] else: - domains = [TraitObjIdentity(site, lookup_var(site, scope, "this"))] + domains = [c.TraitObjIdentity(site, c.lookup_var(site, scope, "this"))] methodref = codegen_expression_maybe_nonvalue(method_ast, location, scope) - if isinstance(methodref, NodeRef) and methodref.node.objtype == 'method': + if isinstance(methodref, c.NodeRef) and methodref.node.objtype == 'method': method, indices = methodref.get_ref() if len(method.outp) > 0: - raise EAFTER(site, None, method, None) + raise E.AFTER(site, None, method, None) require_fully_typed(site, method) func = method_instance(method) inp = func.inp inp_types = [p.typ for p in inp] kind = 'method' - elif isinstance(methodref, HookSendNowRef): + elif isinstance(methodref, c.HookSendNowRef): indices = () send_now_hookref = methodref.hookref_expr - inp_types = msg_types = safe_realtype_shallow( + inp_types = msg_types = tp.safe_realtype_shallow( send_now_hookref.ctype()).msg_types inp = [(f'comp{i}', typ) for (i, typ) in enumerate(msg_types)] kind = 'send_now' else: - raise ENMETH(site, methodref) + raise E.NMETH(site, methodref) inargs = typecheck_inarg_inits(site, inargs, inp, location, scope, kind) @@ -2947,12 +2945,12 @@ def stmt_after(stmt, location, scope): for (i, typ) in enumerate(inp_types): try: serialize.mark_for_serialization(site, typ) - except ESERIALIZE: + except E.SERIALIZE: unserializable.append(i) if kind == 'method': if len(unserializable) > 0: - raise EAFTER(site, None, method, [inp[i] for i in unserializable]) + raise E.AFTER(site, None, method, [inp[i] for i in unserializable]) else: mark_method_referenced(func) after_info = get_after_delay(method) @@ -2960,7 +2958,7 @@ def stmt_after(stmt, location, scope): else: assert kind == 'send_now' if len(unserializable) > 0: - raise EAFTERSENDNOW(site, None, methodref.hookref_expr, + raise E.AFTERSENDNOW(site, None, methodref.hookref_expr, [(i, inp_types[i]) for i in unserializable]) else: typeseq_info = get_type_sequence_info(inp_types, create_new=True) @@ -2968,7 +2966,7 @@ def stmt_after(stmt, location, scope): args_init = AfterIntoSendNowArgsInit(inargs, methodref.hookref_expr) - return [mkAfter(site, clock, api_unit, delay, domains, after_info, indices, + return [c.mkAfter(site, clock, api_unit, delay, domains, after_info, indices, args_init)] @@ -2978,7 +2976,7 @@ def __init__(self, site, name): pass def __str__(self): return self.name def exc(self): - return EAFTERMSGCOMPPARAM(self.site, self.name) + return E.AFTERMSGCOMPPARAM(self.site, self.name) class MsgCompParam(Expression): @auto_init @@ -2996,7 +2994,7 @@ def stmt_afteronhook(stmt, location, scope): site = stmt.site if callexpr[0] != 'apply': - raise ESYNTAX(site, None, + raise E.SYNTAX(site, None, 'callback expression to after statement must be a ' + 'function application') @@ -3005,44 +3003,44 @@ def stmt_afteronhook(stmt, location, scope): hookref_expr = codegen_expression(hookref, location, scope) hooktype = hookref_expr.ctype() - real_hooktype = safe_realtype_shallow(hooktype) - if not isinstance(real_hooktype, THook): - raise EBTYPE(hookref_expr.site, hooktype, 'hook') + real_hooktype = tp.safe_realtype_shallow(hooktype) + if not isinstance(real_hooktype, tp.Hook): + raise E.BTYPE(hookref_expr.site, hooktype, 'hook') real_hooktype.validate(hooktype.declaration_site or hookref_expr.site) # TODO after statement should be extended to allow the user to explicitly # give the domains if location.method(): - domains = [ObjIdentity(site, location.node.parent, location.indices)] + domains = [c.ObjIdentity(site, location.node.parent, location.indices)] else: - domains = [TraitObjIdentity(site, lookup_var(site, scope, "this"))] + domains = [c.TraitObjIdentity(site, c.lookup_var(site, scope, "this"))] methodref = codegen_expression_maybe_nonvalue(method, location, scope) - if isinstance(methodref, NodeRef) and methodref.node.objtype == 'method': + if isinstance(methodref, c.NodeRef) and methodref.node.objtype == 'method': method, indices = methodref.get_ref() if len(method.outp) > 0: - raise EAFTER(site, None, method, None) + raise E.AFTER(site, None, method, None) require_fully_typed(site, method) func = method_instance(method) inp = func.inp inp_types = [p.typ for p in inp] kind = 'method' - elif isinstance(methodref, HookSendNowRef): + elif isinstance(methodref, c.HookSendNowRef): indices = () send_now_hookref = methodref.hookref_expr - inp_types = msg_types = safe_realtype_shallow( + inp_types = msg_types = tp.safe_realtype_shallow( send_now_hookref.ctype()).msg_types inp = [(f'comp{i}', typ) for (i, typ) in enumerate(msg_types)] kind = 'send_now' else: - raise ENMETH(site, methodref) + raise E.NMETH(site, methodref) if len(msg_comp_param_asts) != len(real_hooktype.msg_types): - raise EAFTERHOOK( + raise E.AFTERHOOK( site, hookref_expr, len(real_hooktype.msg_types), len(msg_comp_param_asts)) @@ -3053,7 +3051,7 @@ def stmt_afteronhook(stmt, location, scope): (_, mcp_site, mcp_name) = p if mcp_name in msg_comp_params: - raise EDVAR(mcp_site, msg_comp_params[mcp_name][1], + raise E.DVAR(mcp_site, msg_comp_params[mcp_name][1], mcp_name) else: msg_comp_params[mcp_name] = (idx, mcp_site) @@ -3073,13 +3071,13 @@ def stmt_afteronhook(stmt, location, scope): (name, param_idx, site) = arg_index_to_msg_comp_param[i] typ = real_hooktype.msg_types[param_idx] inarg_inits.append( - ExpressionInitializer(MsgCompParam(site, name, typ))) + c.ExpressionInitializer(MsgCompParam(site, name, typ))) else: inarg_inits.append(inarg_ast) args_scope = MethodParamScope(scope) for (name, (_, msg_param_site)) in msg_comp_params.items(): - args_scope.add(ExpressionSymbol( + args_scope.add(c.ExpressionSymbol( name, MsgCompParamRestrictedSymbol(msg_param_site, name), msg_param_site)) @@ -3093,12 +3091,12 @@ def stmt_afteronhook(stmt, location, scope): if idx not in arg_index_to_msg_comp_param: try: serialize.mark_for_serialization(site, typ) - except ESERIALIZE: + except E.SERIALIZE: unserializable.append(idx) if kind == 'method': if len(unserializable) > 0: - raise EAFTER(site, hookref_expr, method, + raise E.AFTER(site, hookref_expr, method, [inp[i] for i in unserializable]) else: mark_method_referenced(func) @@ -3107,7 +3105,7 @@ def stmt_afteronhook(stmt, location, scope): else: assert kind == 'send_now' if len(unserializable) > 0: - raise EAFTERSENDNOW(site, hookref_expr, methodref.hookref_expr, + raise E.AFTERSENDNOW(site, hookref_expr, methodref.hookref_expr, [(i, inp_types[i]) for i in unserializable]) else: aoh_key = get_type_sequence_info(inp_types, create_new=True) @@ -3123,7 +3121,7 @@ def stmt_afteronhook(stmt, location, scope): aoh_info = typeseq_info.get_after_on_hook( aoh_key, param_idx_to_msg_comp_idx, len(inp), create_new=True) - return [mkAfterOnHook(site, domains, hookref_expr, aoh_info, indices, + return [c.mkAfterOnHook(site, domains, hookref_expr, aoh_info, indices, args_init)] @statement_dispatcher @@ -3132,7 +3130,7 @@ def stmt_immediateafter(stmt, location, scope): site = stmt.site if callexpr[0] != 'apply': - raise ESYNTAX(site, None, + raise E.SYNTAX(site, None, 'callback expression to after statement must be a ' + 'function application') @@ -3142,34 +3140,34 @@ def stmt_immediateafter(stmt, location, scope): # TODO after statement should be extended to allow the user to explicitly # give the domains if location.method(): - domains = [ObjIdentity(site, location.node.parent, location.indices)] + domains = [c.ObjIdentity(site, location.node.parent, location.indices)] else: - domains = [TraitObjIdentity(site, lookup_var(site, scope, "this"))] + domains = [c.TraitObjIdentity(site, c.lookup_var(site, scope, "this"))] methodref = codegen_expression_maybe_nonvalue(method, location, scope) - if isinstance(methodref, NodeRef) and methodref.node.objtype == 'method': + if isinstance(methodref, c.NodeRef) and methodref.node.objtype == 'method': method, indices = methodref.get_ref() if len(method.outp) > 0: - raise EAFTER(site, None, method, None) + raise E.AFTER(site, None, method, None) require_fully_typed(site, method) func = method_instance(method) inp = func.inp kind = 'method' - elif isinstance(methodref, HookSendNowRef): + elif isinstance(methodref, c.HookSendNowRef): indices = () send_now_hookref = methodref.hookref_expr - msg_types = safe_realtype_shallow(send_now_hookref.ctype()).msg_types + msg_types = tp.safe_realtype_shallow(send_now_hookref.ctype()).msg_types inp = [(f'comp{i}', typ) for (i, typ) in enumerate(msg_types)] kind = 'send_now' else: - raise ENMETH(site, methodref) + raise E.NMETH(site, methodref) inargs = typecheck_inarg_inits( site, inarg_asts, inp, location, scope, kind, - on_ptr_to_stack=(lambda x: report(WIMMAFTER(x.site, x)))) + on_ptr_to_stack=(lambda x: report(W.IMMAFTER(x.site, x)))) if kind == 'method': @@ -3184,7 +3182,7 @@ def stmt_immediateafter(stmt, location, scope): args_init = AfterIntoSendNowArgsInit(inargs, methodref.hookref_expr) - return [mkImmediateAfter(site, domains, after_info, indices, args_init)] + return [c.mkImmediateAfter(site, domains, after_info, indices, args_init)] @statement_dispatcher def stmt_select(stmt, location, scope): @@ -3194,7 +3192,7 @@ def stmt_select(stmt, location, scope): lst = codegen_expression_maybe_nonvalue(lst, location, scope) # dbg('SELECT %s in %r' % (itername, lst)) if isinstance(lst, NonValue): - if isinstance(lst, AbstractList): + if isinstance(lst, c.AbstractList): l = lst.iter_flat() scope = Symtab(scope) else_dead = False @@ -3203,8 +3201,8 @@ def stmt_select(stmt, location, scope): for it in l: condscope = Symtab(scope) if itername is not None: - condscope.add(ExpressionSymbol(itername, it, stmt.site)) - cond = as_bool(codegen_expression( + condscope.add(c.ExpressionSymbol(itername, it, stmt.site)) + cond = c.as_bool(codegen_expression( cond_ast, location, condscope)) if cond.constant and not cond.value: continue @@ -3221,85 +3219,85 @@ def stmt_select(stmt, location, scope): else: if_chain = codegen_statement(else_ast, location, scope) for (cond, stmt) in reversed(clauses): - if_chain = mkIf(cond.site, cond, stmt, if_chain) + if_chain = c.mkIf(cond.site, cond, stmt, if_chain) return [if_chain] raise lst.exc() elif (not breaking_changes.dml12_remove_misc_quirks.enabled - and isinstance(lst.ctype(), TVector) + and isinstance(lst.ctype(), tp.Vector) and itername is not None): - itervar = lookup_var(stmt.site, scope, itername) + itervar = c.lookup_var(stmt.site, scope, itername) if not itervar: - raise EIDENT(stmt.site, itername) - return [mkVectorForeach(stmt.site, + raise E.IDENT(stmt.site, itername) + return [c.mkVectorForeach(stmt.site, lst, itervar, codegen_statement(stmt_ast, location, scope))] else: - raise ENLST(stmt.site, lst) + raise E.NLST(stmt.site, lst) def foreach_each_in(site, itername, trait, each_in, body_ast, location, scope): inner_scope = Symtab(scope) - trait_type = TTrait(trait) + trait_type = tp.Trait(trait) if itername is not None: inner_scope.add_variable( itername, type=trait_type, site=site, - init=ForeachSequence.itervar_initializer(site, trait)) + init=c.ForeachSequence.itervar_initializer(site, trait)) context = ForeachSequenceLoopContext() with context: - inner_body = mkCompound(site, declarations(inner_scope) + inner_body = c.mkCompound(site, declarations(inner_scope) + codegen_statements([body_ast], location, inner_scope)) break_label = context.label if context.used else None - return [mkForeachSequence(site, trait, each_in, inner_body, break_label)] + return [c.mkForeachSequence(site, trait, each_in, inner_body, break_label)] @expression_dispatcher def expr_each_in(ast, location, scope): (traitname, node_ast) = ast.args node_expr = codegen_expression_maybe_nonvalue(node_ast, location, scope) - if not isinstance(node_expr, NodeRef): - raise ENOBJ(node_expr.site, node_expr) + if not isinstance(node_expr, c.NodeRef): + raise E.NOBJ(node_expr.site, node_expr) (node, indices) = node_expr.get_ref() trait = dml.globals.traits.get(traitname) if trait is None: - raise ENTMPL(ast.site, traitname) - return mkEachIn(ast.site, trait, node, indices) + raise E.NTMPL(ast.site, traitname) + return c.mkEachIn(ast.site, trait, node, indices) @statement_dispatcher def stmt_foreach_dml12(stmt, location, scope): [itername, lst, statement] = stmt.args lst = codegen_expression_maybe_nonvalue(lst, location, scope) if isinstance(lst, NonValue): - if not isinstance(lst, AbstractList): + if not isinstance(lst, c.AbstractList): raise lst.exc() return foreach_constant_list(stmt.site, itername, lst, statement, location, scope) - list_type = safe_realtype(lst.ctype()) - if isinstance(list_type, TVector): - itervar = lookup_var(stmt.site, scope, itername) + list_type = tp.safe_realtype(lst.ctype()) + if isinstance(list_type, tp.Vector): + itervar = c.lookup_var(stmt.site, scope, itername) if not itervar: - raise EIDENT(lst, itername) + raise E.IDENT(lst, itername) with CLoopContext(): - res = mkVectorForeach(stmt.site, lst, itervar, + res = c.mkVectorForeach(stmt.site, lst, itervar, codegen_statement(statement, location, scope)) return [res] else: - raise ENLST(stmt.site, lst) + raise E.NLST(stmt.site, lst) @statement_dispatcher def stmt_foreach(stmt, location, scope): [iter_ident, lst, statement] = stmt.args itername = iter_ident.args[0] if iter_ident.kind == 'variable' else None lst = codegen_expression(lst, location, scope) - list_type = safe_realtype(lst.ctype()) - if isinstance(list_type, TTraitList): + list_type = tp.safe_realtype(lst.ctype()) + if isinstance(list_type, tp.TraitList): return foreach_each_in( stmt.site, itername, - # .traitname was validated by safe_realtype() + # .traitname was validated by tp.safe_realtype() dml.globals.traits[list_type.traitname], lst, statement, location, scope) else: - raise ENLST(stmt.site, lst) + raise E.NLST(stmt.site, lst) @statement_dispatcher def stmt_hashforeach(stmt, location, scope): @@ -3307,27 +3305,27 @@ def stmt_hashforeach(stmt, location, scope): itername = iter_ident.args[0] if iter_ident.kind == 'variable' else None lst = codegen_expression_maybe_nonvalue(lst, location, scope) if isinstance(lst, NonValue): - if not isinstance(lst, AbstractList): + if not isinstance(lst, c.AbstractList): raise lst.exc() return foreach_constant_list(stmt.site, itername, lst, statement, location, scope) elif not lst.constant: - raise ENCONST(stmt.site, lst) + raise E.NCONST(stmt.site, lst) else: - raise ENLST(stmt.site, lst) + raise E.NLST(stmt.site, lst) def foreach_constant_list(site, itername, lst, statement, location, scope): - assert isinstance(lst, AbstractList) + assert isinstance(lst, c.AbstractList) spec = [] context = GotoLoopContext() with context: for items in lst.iter(): loopvars = tuple(mkLit(site, '_ai%d_%d' % (context.id, dim), - TInt(32, True)) + tp.Int(32, True)) for dim in range(len(items.dimsizes))) loopscope = Symtab(scope) if itername is not None: - loopscope.add(ExpressionSymbol( + loopscope.add(c.ExpressionSymbol( itername, items.expr(loopvars), site)) stmt = codegen_statement(statement, location, loopscope) @@ -3336,32 +3334,32 @@ def foreach_constant_list(site, itername, lst, statement, location, scope): decls = [] for dim in reversed(range(len(items.dimsizes))): - decls.append(mkDeclaration(site, loopvars[dim].str, - TInt(32, True))) - stmt = mkFor( + decls.append(c.mkDeclaration(site, loopvars[dim].str, + tp.Int(32, True))) + stmt = c.mkFor( site, - [mkAssignOp(site, + [c.mkAssignOp(site, loopvars[dim], - mkIntegerLiteral(site, 0))], - mkLessThan(site, loopvars[dim], - mkIntegerLiteral(site, + c.mkIntegerLiteral(site, 0))], + c.mkLessThan(site, loopvars[dim], + c.mkIntegerLiteral(site, items.dimsizes[dim])), - [mkInline(site, '++%s;' % (loopvars[dim].str,))], + [c.mkInline(site, '++%s;' % (loopvars[dim].str,))], stmt) - spec.append(mkCompound(site, decls + [stmt])) + spec.append(c.mkCompound(site, decls + [stmt])) - return [mkUnrolledLoop(site, spec, + return [c.mkUnrolledLoop(site, spec, context.label if context.used else None)] @statement_dispatcher def stmt_while(stmt, location, scope): [cond, statement] = stmt.args - cond = as_bool(codegen_expression(cond, location, scope)) + cond = c.as_bool(codegen_expression(cond, location, scope)) if stmt.site.dml_version() == (1, 2) and cond.constant and not cond.value: - return [mkNoop(stmt.site)] + return [c.mkNoop(stmt.site)] else: with CLoopContext(): - res = mkWhile(stmt.site, cond, + res = c.mkWhile(stmt.site, cond, codegen_statement(statement, location, scope)) return [res] @@ -3371,21 +3369,21 @@ def stmt_for(stmt, location, scope): pres = [codegen_expression(pre, location, scope) for pre in pres] if cond is None: - cond = mkBoolConstant(stmt.site, 1) + cond = c.mkBoolConstant(stmt.site, 1) else: - cond = as_bool(codegen_expression(cond, location, scope)) + cond = c.as_bool(codegen_expression(cond, location, scope)) posts = codegen_statements(posts, location, scope) with CLoopContext(): - res = mkFor(stmt.site, pres, cond, posts, + res = c.mkFor(stmt.site, pres, cond, posts, codegen_statement(statement, location, scope)) return [res] @statement_dispatcher def stmt_dowhile(stmt, location, scope): [cond, statement] = stmt.args - cond = as_bool(codegen_expression(cond, location, scope)) + cond = c.as_bool(codegen_expression(cond, location, scope)) with CLoopContext(): - res = mkDoWhile(stmt.site, cond, + res = c.mkDoWhile(stmt.site, cond, codegen_statement(statement, location, scope)) return [res] @@ -3400,17 +3398,17 @@ def stmt_switch(stmt, location, scope): stmts = codegen_statements(stmt_asts, location, scope) if (not stmts or not isinstance(stmts[0], (ctree.Case, ctree.Default))): - raise ESWITCH( + raise E.SWITCH( body_ast.site, "statement before first case label") defaults = [i for (i, sub) in enumerate(stmts) if isinstance(sub, ctree.Default)] if len(defaults) > 1: - raise ESWITCH(stmts[defaults[1]].site, + raise E.SWITCH(stmts[defaults[1]].site, "duplicate default label") if defaults: for sub in stmts[defaults[0]:]: if isinstance(sub, ctree.Case): - raise ESWITCH(sub.site, + raise E.SWITCH(sub.site, "case label after default label") body_stmts = [] default_found = False @@ -3423,7 +3421,7 @@ def stmt_switch(stmt, location, scope): subsequent_cases.append(body_stmt) else: if subsequent_cases: - body_stmts.append(mkSubsequentCases( + body_stmts.append(c.mkSubsequentCases( subsequent_cases[0].site, subsequent_cases, default_found)) subsequent_cases = [] @@ -3431,27 +3429,27 @@ def stmt_switch(stmt, location, scope): body_stmts.append(body_stmt) if subsequent_cases: - body_stmts.append(mkSubsequentCases( + body_stmts.append(c.mkSubsequentCases( subsequent_cases[0].site, subsequent_cases, default_found)) body = ctree.Compound(body_ast.site, body_stmts, rbrace_site) else: body = codegen_statement(body_ast, location, scope) - res = mkSwitch(stmt.site, expr, body) + res = c.mkSwitch(stmt.site, expr, body) return [res] @statement_dispatcher def stmt_continue(stmt, location, scope): if LoopContext.current is None: - raise ECONT(stmt.site) + raise E.CONT(stmt.site) else: return LoopContext.current.continue_(stmt.site) @statement_dispatcher def stmt_break(stmt, location, scope): if LoopContext.current is None: - raise EBREAK(stmt.site) + raise E.BREAK(stmt.site) else: return LoopContext.current.break_(stmt.site) @@ -3460,7 +3458,7 @@ def eval_call_stmt(method_ast, location, scope): method reference and all parameters.''' expr = codegen_expression_maybe_nonvalue(method_ast, location, scope) if isinstance(expr, NonValue) and not isinstance( - expr, (TraitMethodRef, NodeRef)): + expr, (c.TraitMethodRef, c.NodeRef)): raise expr.exc() return expr @@ -3468,15 +3466,15 @@ def verify_args(site, inp, outp, inargs, outargs): '''Verify that the given arguments can be used when calling or inlining method''' if len(inargs) != len(inp): - raise EARG(site, 'input') + raise E.ARG(site, 'input') if len(outargs) != len(outp): if dml.globals.dml_version == (1, 2): - raise EARG(site, 'output') + raise E.ARG(site, 'output') else: - raise ERETLVALS(site, len(outp), len(outargs)) + raise E.RETLVALS(site, len(outp), len(outargs)) for arg in outargs: if not arg.writable: - report(EASSIGN(site, arg)) + report(E.ASSIGN(site, arg)) return False return True @@ -3486,17 +3484,17 @@ def mkcall_method(site, func, indices): raise i.exc() from .crep import dev if crep.TypedParamContext.active and func.independent: - raise ETYPEDPARAMVIOL(site) + raise E.TYPEDPARAMVIOL(site) devarg = ([] if func.independent else [mkLit(site, dev(site), - TDevice(crep.structtype(dml.globals.device)))]) + tp.Device(crep.structtype(dml.globals.device)))]) return lambda args: mkApply( site, func.cfunc_expr(site), devarg + list(indices) + args) def common_inline(site, method, indices, inargs, outargs): if not verify_args(site, method.inp, method.outp, inargs, outargs): - return mkNoop(site) + return c.mkNoop(site) if dml.globals.debuggable: if method.fully_typed and ( @@ -3569,17 +3567,17 @@ def mark_method_invocation(call_site, method, location): # some methods will be converted to 'throws' when moving # to 1.4; these will eventually need encapsulation in try # blocks, so we count them as throwing. - EBADFAIL_dml12.throwing_methods[location.method()] = call_site + E.BADFAIL_dml12.throwing_methods[location.method()] = call_site else: # ordinary 1.2 method: will count as throwing if it # actually throws, or (recursively) if it calls a method # that does. This analysis is done by EBADFAIL_dml12.all_errors(). - EBADFAIL_dml12.uncaught_method_calls.setdefault( + E.BADFAIL_dml12.uncaught_method_calls.setdefault( method, []).append((call_site, location.method())) else: # 1.4 methods marked as 'throws' count as throwing even if they don't, # because they will need a try block - EBADFAIL_dml12.throwing_methods[location.method()] = call_site + E.BADFAIL_dml12.throwing_methods[location.method()] = call_site @statement_dispatcher def stmt_inline(stmt, location, scope): @@ -3593,15 +3591,15 @@ def stmt_inline(stmt, location, scope): outargs = [codegen_expression(arg, location, scope) for arg in outarg_asts] expr = eval_call_stmt(method_ast, location, scope) - if isinstance(expr, NodeRef): + if isinstance(expr, c.NodeRef): (method, indices) = expr.get_ref() if method.objtype != 'method': - raise ENMETH(stmt.site, expr) + raise E.NMETH(stmt.site, expr) if not in_try_block(location) and method.throws: mark_method_invocation(expr.site, method, location) return [common_inline(stmt.site, method, indices, inargs, outargs)] else: - raise ENMETH(stmt.site, expr) + raise E.NMETH(stmt.site, expr) @statement_dispatcher def stmt_call(stmt, location, scope): @@ -3612,21 +3610,21 @@ def stmt_call(stmt, location, scope): outargs = [codegen_expression(arg, location, scope) for arg in outarg_asts] expr = eval_call_stmt(method_ast, location, scope) - if isinstance(expr, NodeRef): + if isinstance(expr, c.NodeRef): (method, indices) = expr.get_ref() if method.objtype != 'method': - raise ENMETH(stmt.site, expr) + raise E.NMETH(stmt.site, expr) if not in_try_block(location) and method.throws: mark_method_invocation(expr.site, method, location) return [codegen_call(stmt.site, method, indices, inargs, outargs)] - elif isinstance(expr, TraitMethodRef): + elif isinstance(expr, c.TraitMethodRef): if not in_try_block(location) and expr.throws: # Shared methods marked as 'throws' count as # unconditionally throwing - EBADFAIL_dml12.throwing_methods[location.method()] = expr.site + E.BADFAIL_dml12.throwing_methods[location.method()] = expr.site return [codegen_call_traitmethod(stmt.site, expr, inargs, outargs)] else: - raise ENMETH(stmt.site, expr) + raise E.NMETH(stmt.site, expr) # Context manager that protects from recursive inlining class RecursiveInlineGuard(object): @@ -3638,7 +3636,7 @@ def __init__(self, site, meth_node): self.meth_node = meth_node def __enter__(self): if self.meth_node in self.stack: - raise ERECUR(self.site, self.meth_node) + raise E.RECUR(self.site, self.meth_node) self.stack.add(self.meth_node) def __exit__(self, exc_type, exc_val, exc_tb): self.stack.remove(self.meth_node) @@ -3689,26 +3687,26 @@ def report_pevent_data_arg(meth_node, site, inargs): and meth_node.name in {'post', 'posted', 'next', 'remove'}): from . import structure if structure.method_is_std(meth_node.parent, 'get_event_info'): - report(PEVENT_NO_ARG(dmlparse.start_site(inargs[-1].site), + report(P.EVENT_NO_ARG(dmlparse.start_site(inargs[-1].site), dmlparse.end_site(site))) elif (isinstance(inargs[-1], ctree.Cast) - and safe_realtype(inargs[-1].expr.ctype()).is_int): - report(PEVENT_UINT64_ARG( + and tp.safe_realtype(inargs[-1].expr.ctype()).is_int): + report(P.EVENT_UINT64_ARG( inargs[-1].site, dmlparse.end_site(inargs[-1].site), meth_node.parent.site)) event_meth_node = meth_node.parent.get_component('event') argname = event_meth_node.inp[0].ident assert argname is not None - report(PCHANGE_INARGS(event_meth_node.site, + report(P.CHANGE_INARGS(event_meth_node.site, f'method event(uint64 {argname})')) for methname in ['get_event_info', 'set_event_info']: meth = meth_node.parent.get_component(methname) - report(PEVENT_REMOVE_INFO(meth.site, dmlparse.end_site(meth.site))) + report(P.EVENT_REMOVE_INFO(meth.site, dmlparse.end_site(meth.site))) def codegen_inline(site, meth_node, indices, inargs, outargs, inhibit_copyin = False): assert isinstance(meth_node, objects.DMLObject) - PWUNUSED.inlined_methods.add(meth_node.site) + P.WUNUSED.inlined_methods.add(meth_node.site) if len(inargs) != len(meth_node.inp): raise ICE(meth_node, "wrong number of inargs") @@ -3716,7 +3714,7 @@ def codegen_inline(site, meth_node, indices, inargs, outargs, raise ICE(meth_node, "wrong number of outargs") if meth_node.throws and not Failure.fail_stack[-1].allowed: - raise EBADFAIL(site) + raise E.BADFAIL(site) if (site.dml_version() == (1, 2) and logging.show_porting): report_pevent_data_arg(meth_node, site, inargs) @@ -3726,7 +3724,7 @@ def codegen_inline(site, meth_node, indices, inargs, outargs, # Open the scope # TODO: in python 3.10 we can use parentheses instead of \ with RecursiveInlineGuard(site, meth_node), \ - ErrorContext(meth_node, site), \ + logging.ErrorContext(meth_node, site), \ contextlib.nullcontext() if meth_node.throws else NoFailure(site): param_scope = MethodParamScope(global_scope) param_scope.add(meth_node.default_method.default_sym(indices)) @@ -3747,22 +3745,22 @@ def codegen_inline(site, meth_node, indices, inargs, outargs, argtype = arg.ctype() if not argtype: raise ICE(arg.site, "unknown expression type") - parmt = safe_realtype(p.typ) - argt = safe_realtype(argtype) + parmt = tp.safe_realtype(p.typ) + argt = tp.safe_realtype(argtype) (ok, trunc, constviol) = parmt.canstore(argt) if not ok: - raise EARGT(site, 'inline', meth_node.name, + raise E.ARGT(site, 'inline', meth_node.name, arg.ctype(), p.logref, p.typ, 'input') if constviol: - raise ECONSTP(site, p.logref, "method call") - arg = coerce_if_eint(arg) + raise E.CONSTP(site, p.logref, "method call") + arg = expr_util.coerce_if_eint(arg) if p.ident is None: - pre.append(mkExpressionStatement(arg.site, arg, + pre.append(c.mkExpressionStatement(arg.site, arg, explicit_discard=True)) elif inhibit_copyin or undefined(arg): - param_scope.add(ExpressionSymbol(p.ident, arg, arg.site)) + param_scope.add(c.ExpressionSymbol(p.ident, arg, arg.site)) elif arg.constant and ( p.inlined or not (breaking_changes @@ -3771,22 +3769,22 @@ def codegen_inline(site, meth_node, indices, inargs, outargs, # provide constant folding. Other values are stored in a # local variable to improve type checking and variable # scoping. - inlined_arg = mkInlinedParam(site, arg, p.ident, + inlined_arg = c.mkInlinedParam(site, arg, p.ident, p.typ or arg.ctype()) - param_scope.add(ExpressionSymbol( + param_scope.add(c.ExpressionSymbol( p.ident, inlined_arg, site)) else: param_scope.add_variable(p.ident, type = p.typ or arg.ctype(), site = arg.site, - init = ExpressionInitializer(arg)) + init = c.ExpressionInitializer(arg)) arg.decref() if meth_node.astcode.site.dml_version() == (1, 2): if inhibit_copyin: # inhibit_copyin also inhibits copyout for (arg, (parmname, parmtype)) in zip(outargs, meth_node.outp): - param_scope.add(ExpressionSymbol(parmname, arg, site)) + param_scope.add(c.ExpressionSymbol(parmname, arg, site)) copyout = [] else: outvars = [ @@ -3805,45 +3803,45 @@ def codegen_inline(site, meth_node, indices, inargs, outargs, exit_handler = GotoExit_dml12() with exit_handler: code = [codegen_statement(meth_node.astcode, - Location(meth_node, indices), + c.Location(meth_node, indices), param_scope)] - post = ([mkLabel(site, exit_handler.label)] + post = ([c.mkLabel(site, exit_handler.label)] if exit_handler.used else []) post.extend(copyout) - return mkInlinedMethod(site, meth_node, declarations(param_scope), + return c.mkInlinedMethod(site, meth_node, declarations(param_scope), code, post) else: assert meth_node.astcode.kind == 'compound' [subs, rbrace_site] = meth_node.astcode.args - location = Location(meth_node, indices) + location = c.Location(meth_node, indices) exit_handler = GotoExit_dml14(outargs) with exit_handler: code = codegen_statements(subs, location, param_scope) pre.extend(declarations(param_scope)) - post = ([mkLabel(site, exit_handler.label)] + post = ([c.mkLabel(site, exit_handler.label)] if exit_handler.used else []) - body = mkCompound(site, pre + code, rbrace_site) + body = c.mkCompound(site, pre + code, rbrace_site) if meth_node.outp and body.control_flow().fallthrough: - report(ENORET(meth_node.astcode.site)) - return mkInlinedMethod(site, meth_node, pre, code, post) + report(E.NORET(meth_node.astcode.site)) + return c.mkInlinedMethod(site, meth_node, pre, code, post) def c_rettype(outp, throws): if throws: - return TBool() + return tp.Bool() elif outp: (_, rettype) = outp[0] return rettype else: - return TVoid() + return tp.Void() def c_extra_inargs(outp, throws): '''Return required additional input parameters for a C function given output parameters and throws, through the form [arg1, ...]) where each arg is a pair (name, type).''' if throws: - return [(n, TPtr(t)) for (n, t) in outp] + return [(n, tp.Ptr(t)) for (n, t) in outp] elif outp: - return [(n, TPtr(t)) for (n, t) in outp[1:]] + return [(n, tp.Ptr(t)) for (n, t) in outp[1:]] else: return [] @@ -3897,7 +3895,7 @@ def cfunc_expr(self, site): @property def cfunc_type(self): - return TFunction([t for (_, t, _) in self.cparams], self.rettype) + return tp.Function([t for (_, t, _) in self.cparams], self.rettype) def get_name(self): '''textual description of method, used in comment''' @@ -3913,7 +3911,7 @@ def get_cname(self): def canonicalize_signature(signature): "Make a signature hashable" # The problem is that the same type can be represented by - # different DMLType objects. Use an ugly trick and canonicalize to + # different tp.DMLType objects. Use an ugly trick and canonicalize to # the string representation. (intypes, outtypes) = signature return (tuple(t.value if isinstance(t, Expression) and t.constant @@ -3922,7 +3920,7 @@ def canonicalize_signature(signature): def implicit_params(method): return (crep.maybe_dev_arg(method.independent) - + [('_idx%d' % i, TInt(32, False)) + + [('_idx%d' % i, tp.Int(32, False)) for i in range(method.dimensions)]) def untyped_method_instance(method, signature): @@ -3936,7 +3934,7 @@ def untyped_method_instance(method, signature): inp = [(p.with_expr if isinstance(stype, Expression) else p.with_type)(stype) for stype, p in zip(intypes, method.inp)] - assert all(isinstance(t, DMLType) for t in outtypes) + assert all(isinstance(t, tp.DMLType) for t in outtypes) outp = [(arg, stype) for stype, (arg, etype) in zip(outtypes, method.outp)] @@ -3964,8 +3962,8 @@ def codegen_method_func(func): specific instance of a method defined directly in the device tree""" method = func.method - indices = tuple(mkLit(method.site, '_idx%d' % i, TInt(32, False), - str=(dollar(method.site) + indices = tuple(mkLit(method.site, '_idx%d' % i, tp.Int(32, False), + str=(logging.dollar(method.site) + ("_" if idxvar is None else ""))) for (i, idxvar) in enumerate(method.parent.idxvars())) intercepted = intercepted_method(method) @@ -3976,7 +3974,7 @@ def codegen_method_func(func): method.parent, indices, [mkLit(method.site, p.c_ident, p.typ) for p in func.inp], [mkLit(method.site, "*%s" % n, t) for (n, t) in func.outp], - SimpleSite(method.site.loc())) + logging.SimpleSite(method.site.loc())) inline_scope = MethodParamScope(global_scope) for p in func.inp: e = p.expr @@ -3986,14 +3984,14 @@ def codegen_method_func(func): check_varname(p.site, p.ident) if e and p.ident is not None: inlined_arg = ( - mkInlinedParam(p.site, e, p.ident, e.ctype()) + c.mkInlinedParam(p.site, e, p.ident, e.ctype()) if defined(e) else e) - inline_scope.add(ExpressionSymbol( + inline_scope.add(c.ExpressionSymbol( p.ident, inlined_arg, p.site)) inp = [p for p in func.inp if not p.inlined] - with ErrorContext(method): - location = Location(method, indices) + with logging.ErrorContext(method): + location = c.Location(method, indices) if func.memoized: assert func.independent and func.startup memoization = IndependentMemoized(func) @@ -4010,17 +4008,17 @@ def codegen_return(site, outp, throws, retvals): '''Generate code for returning from a method with a given list of return values''' if len(outp) != len(retvals): - report(ERETARGS(site, len(outp), len(retvals))) + report(E.RETARGS(site, len(outp), len(retvals))) # avoid control flow errors by falling back to statement with # no fall-through - return mkAssert(site, mkBoolConstant(site, False)) + return c.mkAssert(site, c.mkBoolConstant(site, False)) if throws: - ret = mkReturn(site, mkBoolConstant(site, False)) + ret = c.mkReturn(site, c.mkBoolConstant(site, False)) elif outp: (_, t) = outp[0] - ret = mkReturn(site, retvals[0], t) + ret = c.mkReturn(site, retvals[0], t) else: - ret = mkReturn(site, None) + ret = c.mkReturn(site, None) stmts = [] return_first_outarg = bool(not throws and outp) for ((name, typ), val) in itertools.islice( @@ -4028,12 +4026,12 @@ def codegen_return(site, outp, throws, retvals): if (return_first_outarg and site.dml_version() == (1, 2)): # Avoid outputting "*x = *x" for nothrow methods in 1.2 assert isinstance(val, ctree.Dereference) - assert isinstance(val.rh, ctree.Lit) + assert isinstance(val.rh, expr.Lit) assert val.rh.str == name continue - stmts.append(mkCopyData(site, val, mkLit(site, "*%s" % (name,), typ))) + stmts.append(c.mkCopyData(site, val, mkLit(site, "*%s" % (name,), typ))) stmts.append(ret) - return mkCompound(site, stmts) + return c.mkCompound(site, stmts) def codegen_method(site, inp, outp, throws, independent, memoization, ast, default, location, fnscope, rbrace_site): @@ -4073,7 +4071,7 @@ def prelude(): varname, type=parmtype, init=init, make_unique=True, site=ast.site) sym.incref() - code.append(sym_declaration(sym)) + code.append(c.sym_declaration(sym)) else: if outp: # pass first out argument as return value @@ -4082,42 +4080,42 @@ def prelude(): init=initializers[0], make_unique=False) sym.incref() - code = [sym_declaration(sym)] + code = [c.sym_declaration(sym)] for ((name, typ), init) in zip(outp[1:], initializers[1:]): # remaining output arguments pass-by-pointer - param = mkDereference(site, - mkLit(site, name, TPtr(typ))) - fnscope.add(ExpressionSymbol(name, param, site)) - code.append(AssignStatement(site, param, init)) + param = c.mkDereference(site, + mkLit(site, name, tp.Ptr(typ))) + fnscope.add(c.ExpressionSymbol(name, param, site)) + code.append(c.AssignStatement(site, param, init)) else: code = [] with fail_handler, exit_handler: code.append(codegen_statement(ast, location, fnscope)) if exit_handler.used: - code.append(mkLabel(rbrace_site, exit_handler.label)) + code.append(c.mkLabel(rbrace_site, exit_handler.label)) code.append(codegen_return(rbrace_site, outp, throws, [ - lookup_var(site, fnscope, varname) for (varname, _) in outp])) - to_return = mkCompound(site, code) + c.lookup_var(site, fnscope, varname) for (varname, _) in outp])) + to_return = c.mkCompound(site, code) else: # manually deconstruct compound AST node, to make sure # top-level locals share scope with parameters assert ast.kind == 'compound' [subs, _] = ast.args with fail_handler, exit_handler: - body = ([mkIndicesAssert(site, location.node, + body = ([c.mkIndicesAssert(site, location.node, location.indices)] if (breaking_changes.range_check_method_indices.enabled and location.method() and location.node.dimsizes) else []) body.extend(prelude()) body.extend(codegen_statements(subs, location, fnscope)) - code = mkCompound(site, body) + code = c.mkCompound(site, body) if code.control_flow().fallthrough: if outp: - report(ENORET(site)) + report(E.NORET(site)) else: - code = mkCompound(site, + code = c.mkCompound(site, body + [codegen_exit(rbrace_site, [])], rbrace_site) @@ -4137,7 +4135,7 @@ def mark_method_exported(func, name, export_site): # name -> func instances -> export statement sites if name in exported_methods: (otherfunc, othersite) = exported_methods[name] - report(ENAMECOLL(export_site, othersite, name)) + report(E.NAMECOLL(export_site, othersite, name)) else: if (export_site.dml_version() != (1, 2) and not func.independent): @@ -4156,9 +4154,9 @@ def methfunc_param(ptype, arg): # Special case, normally endian integer inargs or outargs are not allowed, # so we pretend its a regular integer here and count on coercion # to handle the translation - realargtype = realtype(arg.ctype()) + realargtype = tp.realtype(arg.ctype()) if realargtype.is_int and realargtype.is_endian: - return TInt(realargtype.bits, realargtype.signed, + return tp.Int(realargtype.bits, realargtype.signed, realargtype.members, realargtype.const) return arg.ctype() @@ -4166,10 +4164,10 @@ def require_fully_typed(site, meth_node): if not meth_node.fully_typed: for p in meth_node.inp: if p.inlined: - raise ENARGT(meth_node.site, p.logref, 'input', site) + raise E.NARGT(meth_node.site, p.logref, 'input', site) for (parmname, parmtype) in meth_node.outp: if not parmtype: - raise ENARGT(meth_node.site, f"'{parmname}'", 'output', site) + raise E.NARGT(meth_node.site, f"'{parmname}'", 'output', site) raise ICE(site, "no missing parameter type") def codegen_call_expr(site, meth_node, indices, inits, location, scope): @@ -4181,14 +4179,14 @@ def codegen_call_expr(site, meth_node, indices, inits, location, scope): return mkcall_method(site, func, indices)(args) def codegen_call_traitmethod(site, expr, inargs, outargs): - if not isinstance(expr, TraitMethodRef): + if not isinstance(expr, c.TraitMethodRef): raise ICE(site, "cannot call %r: not a trait method" % (expr,)) if not verify_args(site, expr.inp, expr.outp, inargs, outargs): - return mkNoop(site) + return c.mkNoop(site) def mkcall(args): rettype = c_rettype(expr.outp, expr.throws) # implicitly convert endian int arguments to integers - args = [coerce_if_eint(arg) for arg in args] + args = [expr_util.coerce_if_eint(arg) for arg in args] return expr.call_expr(args, rettype) return codegen_call_stmt(site, str(expr), mkcall, expr.inp, expr.outp, expr.throws, inargs, outargs) @@ -4196,7 +4194,7 @@ def mkcall(args): def codegen_call(site, meth_node, indices, inargs, outargs): '''Generate a call using a direct reference to the method node''' if not verify_args(site, meth_node.inp, meth_node.outp, inargs, outargs): - return mkNoop(site) + return c.mkNoop(site) require_fully_typed(site, meth_node) func = method_instance(meth_node) @@ -4205,8 +4203,8 @@ def codegen_call(site, meth_node, indices, inargs, outargs): if not breaking_changes.dml12_remove_misc_quirks.enabled: # For backward compatibility. See bug 21367. - inargs = [mkCast(site, arg, TPtr(TNamed('char'))) - if isinstance(arg, StringConstant) else arg + inargs = [c.mkCast(site, arg, tp.Ptr(tp.Named('char'))) + if isinstance(arg, c.StringConstant) else arg for arg in inargs] mark_method_referenced(func) @@ -4245,19 +4243,19 @@ def copy_outarg(arg, var, parmname, parmtype, method_name): if not argtype: raise ICE(arg.site, "unknown expression type") else: - ok, trunc, constviol = realtype(parmtype).canstore( - realtype(argtype)) + ok, trunc, constviol = tp.realtype(parmtype).canstore( + tp.realtype(argtype)) if not ok: - raise EARGT(arg.site, 'call', method_name, + raise E.ARGT(arg.site, 'call', method_name, arg.ctype(), parmname, parmtype, 'output') - return mkCopyData(var.site, var, arg) + return c.mkCopyData(var.site, var, arg) def add_proxy_outvar(site, parmname, parmtype, callscope): varname = parmname varinit = get_initializer(site, parmtype, None, None, None) sym = callscope.add_variable(varname, type=parmtype, init=varinit, site=site) - return mkLocalVariable(site, sym) + return c.mkLocalVariable(site, sym) def codegen_call_stmt(site, name, mkcall, inp, outp, throws, inargs, outargs): '''Generate a statement for calling a method''' @@ -4278,28 +4276,28 @@ def codegen_call_stmt(site, name, mkcall, inp, outp, throws, inargs, outargs): # the mechanisms to detect whether this is safe are # broken. See SIMICS-9504. # if (isinstance(arg, ( - # Variable, ctree.Dereference, ctree.ArrayRef, ctree.SubRef)) - # and TPtr(parmtype).canstore(TPtr(arg.ctype()))): - # outargs_conv.append(mkAddressOf(arg.site, arg)) + # c.Variable, ctree.Dereference, ctree.ArrayRef, ctree.SubRef)) + # and tp.Ptr(parmtype).canstore(tp.Ptr(arg.ctype()))): + # outargs_conv.append(c.mkAddressOf(arg.site, arg)) # else: var = add_proxy_outvar(site, '_ret_' + parmname, parmtype, callscope) - outargs_conv.append(mkAddressOf(var.site, var)) + outargs_conv.append(c.mkAddressOf(var.site, var)) postcode.append(copy_outarg(arg, var, parmname, parmtype, name)) - typecheck_inargs(site, inargs, inp, 'method') + expr.typecheck_inargs(site, inargs, inp, 'method') call_expr = mkcall(list(inargs) + outargs_conv) if throws: if not Failure.fail_stack[-1].allowed: - raise EBADFAIL(site) - call_stmt = mkIf(site, call_expr, Failure.fail_stack[-1].fail(site)) + raise E.BADFAIL(site) + call_stmt = c.mkIf(site, call_expr, Failure.fail_stack[-1].fail(site)) else: if outargs: - call_stmt = mkCopyData(site, call_expr, outargs[0]) + call_stmt = c.mkCopyData(site, call_expr, outargs[0]) else: - call_stmt = mkExpressionStatement(site, call_expr) + call_stmt = c.mkExpressionStatement(site, call_expr) - return mkCompound(site, declarations(callscope) + [call_stmt] + postcode) + return c.mkCompound(site, declarations(callscope) + [call_stmt] + postcode) ctree.codegen_call_expr = codegen_call_expr diff --git a/py/dml/crep.py b/py/dml/crep.py index 2da3f58ac..6fd72d893 100644 --- a/py/dml/crep.py +++ b/py/dml/crep.py @@ -5,20 +5,18 @@ # encoding of device state in the C device structure. import dml.globals -from .objects import * -from .types import * -from .logging import * -from .expr_util import * -from .messages import * -from . import breaking_changes +from .objects import Method +from . import types as tp +from .logging import ICE, report +from .expr_util import param_expr, param_str +from . import errors as E, warnings as W +from . import breaking_changes, expr_util __all__ = ( 'cname', 'cref_method', 'cref_portobj', 'cref_session', - 'ctype', - 'conf_obj', 'cloggroup', 'dev', 'require_dev', @@ -59,11 +57,11 @@ def dev(site): def require_dev(site): if not DeviceInstanceContext.active: - raise EINDEPENDENTVIOL(site) + raise E.INDEPENDENTVIOL(site) def maybe_dev_arg(independent): return ([] if independent - else [('_dev', TDevice(structtype(dml.globals.device)))]) + else [('_dev', tp.Device(structtype(dml.globals.device)))]) @@ -75,7 +73,7 @@ def cname(node): # this is weird... kept for compatibility name = param_str(node, 'c_name').replace('-', '_') if name != node.name and breaking_changes.dml12_remove_misc_quirks.enabled: - report(WDEPRECATED(param_expr_site(node, 'c_name'), + report(W.DEPRECATED(expr_util.param_expr_site(node, 'c_name'), 'parameter c_name')) return name elif node.name: @@ -162,12 +160,12 @@ def node_storage_type(node, site = None): def node_storage_type_dml12(node, site): if node.objtype == 'attribute': - if param_defined(node, 'allocate_type'): + if expr_util.param_defined(node, 'allocate_type'): allocate_type = param_str(node, 'allocate_type') if allocate_type == "string": - return TPtr(TNamed('char')) + return tp.Ptr(tp.Named('char')) else: - return parse_type(allocate_type) + return tp.parse_type(allocate_type) else: return None elif node.objtype == 'method': @@ -179,23 +177,23 @@ def node_storage_type_dml12(node, site): elif node.objtype == 'implement': if not breaking_changes.dml12_remove_misc_quirks.enabled: typename = param_str(node, 'c_type') - t = TNamed(typename) + t = tp.Named(typename) t.declaration_site = node.site return t else: return None elif node.objtype == 'interface': typename = param_str(node, 'c_type') - return TPtr(TNamed(typename, const=True)) + return tp.Ptr(tp.Named(typename, const=True)) elif node.objtype == 'device': - return TDevice(structtype(node)) + return tp.Device(structtype(node)) elif node.objtype == 'register': # Preferably, this should never happen. But unfortunately, # we have to handle this case, which is triggered when someone (e.g. # method get from template register) writes 'typeof($reg)' where # '$reg' is a register with explicit fields. - signed = param_bool(node, 'signed') - return TInt(param_int(node, 'bitsize'), signed) + signed = expr_util.param_bool(node, 'signed') + return tp.Int(expr_util.param_int(node, 'bitsize'), signed) elif node.objtype == 'field': # TODO: this access to ctree is unholy. We should probably # make bitsize a property of the field object instead, but for @@ -205,10 +203,10 @@ def node_storage_type_dml12(node, site): # constant across register indices; it could however happen that # structure.register_fields(). indices = (ctree.mkIntegerLiteral(node.site, 0),) * node.dimensions - msb = expr_intval(param_expr(node, 'msb', indices)) - lsb = expr_intval(param_expr(node, 'lsb', indices)) - signed = param_bool(node, 'signed') - return TInt(msb - lsb + 1, signed) + msb = expr_util.expr_intval(param_expr(node, 'msb', indices)) + lsb = expr_util.expr_intval(param_expr(node, 'lsb', indices)) + signed = expr_util.param_bool(node, 'signed') + return tp.Int(msb - lsb + 1, signed) elif node.objtype in {'bank', 'group', 'event', 'port', 'connect', 'subdevice'}: return None diff --git a/py/dml/ctree.py b/py/dml/ctree.py index b33bfa284..aa249ec91 100644 --- a/py/dml/ctree.py +++ b/py/dml/ctree.py @@ -11,16 +11,19 @@ import math from functools import reduce -from dml import objects, symtab, logging, crep -from .logging import * -from .messages import * -from .output import * -from .types import * -from .expr import * -from .expr_util import * +from dml import objects, symtab, expr, logging, crep +from .logging import ICE, DMLError, report, binary_dump +from . import errors as E, warnings as W, porting as P +from . import output +from .output import linemark, out +from . import types as tp +from .expr import (Apply, Code, Expression, mkApply, mkLit, + NonValue, NonValueArrayRef, NullConstant, + StaticIndex, typecheck_inarg_inits) +from .expr_util import param_bool, param_str, undefined from .set import Set from .slotsmeta import auto_init -from . import dmlparse, output +from . import expr_util, dmlparse from . import breaking_changes import dml.globals # set from codegen.py @@ -194,14 +197,14 @@ def assert_type(site, expr, type): def comparable_types(expr1, expr2, equality): "Check if two expressions can be compared" - typ1 = realtype(expr1.ctype()) - typ2 = realtype(expr2.ctype()) + typ1 = tp.realtype(expr1.ctype()) + typ2 = tp.realtype(expr2.ctype()) if typ1.is_arith and typ2.is_arith: return True - if isinstance(typ1, (TPtr, TArray)) and isinstance(typ2, (TPtr, TArray)): + if isinstance(typ1, (tp.Ptr, tp.Array)) and isinstance(typ2, (tp.Ptr, tp.Array)): return True - if equality and isinstance(typ1, TBool) and isinstance(typ2, TBool): + if equality and isinstance(typ1, tp.Bool) and isinstance(typ2, tp.Bool): return True return False @@ -209,9 +212,9 @@ def comparable_types(expr1, expr2, equality): def assert_comparable_types(site, expr1, expr2, equality): "Assert that two expressions can be compared" if not comparable_types(expr1, expr2, equality): - typ1 = realtype(expr1.ctype()) - typ2 = realtype(expr2.ctype()) - raise EILLCOMP(site, expr1, typ1, expr2, typ2) + typ1 = tp.realtype(expr1.ctype()) + typ2 = tp.realtype(expr2.ctype()) + raise E.ILLCOMP(site, expr1, typ1, expr2, typ2) class SimpleParamExpr(objects.ParamExpr): @@ -282,9 +285,9 @@ def __init__(self, node, indices): self.node = node # Many functions take an 'indices' arg derived from # Location.indices; we generally allow such functions to assume - # that indices are either TInt or StaticIndex. + # that indices are either tp.Int or StaticIndex. assert all(isinstance(e, StaticIndex) - or isinstance(realtype(e.ctype()), TInt) + or isinstance(tp.realtype(e.ctype()), tp.Int) for e in indices) self.indices = indices def __repr__(self): @@ -345,7 +348,7 @@ class Statement(Code): is_empty = False def __init__(self, site): self.site = site - self.context = ErrorContext.current() + self.context = logging.ErrorContext.current() # Emit a single (labeled) C statement. @abc.abstractmethod @@ -392,7 +395,7 @@ def toc_stmt(self): self.linemark() out('{\n', postindent=1) self.toc_inline() - site_linemark(self.rbrace_site) + output.site_linemark(self.rbrace_site) out('}\n', preindent=-1) @property @@ -544,12 +547,12 @@ def toc(self): if (dml.globals.dml_version != (1, 2) and not self.tryblock.control_flow().fallthrough): - site_linemark(self.catchblock.site) + output.site_linemark(self.catchblock.site) out(f'{self.label}:;\n') self.catchblock.toc() else: # Our fallthrough analysis is more conservative than Coverity's - coverity_marker('unreachable', site=self.catchblock.site) + output.coverity_marker('unreachable', site=self.catchblock.site) out(f'if (false) {self.label}:\n') toc_under_if(self.catchblock) @@ -595,7 +598,7 @@ def toc(self): def toc_inline(self): for stmt in self.pre: stmt.toc() - with allow_linemarks(): + with output.allow_linemarks(): for stmt in self.body: stmt.toc() for stmt in self.post: @@ -639,7 +642,7 @@ def __init__(self, site, expr): pass def toc_stmt(self): self.linemark() out('DML_ASSERT("%s", %d, %s);\n' - % (quote_filename(self.site.filename()), + % (output.quote_filename(self.site.filename()), self.site.lineno, self.expr.read())) def control_flow(self): return ControlFlow( @@ -687,7 +690,7 @@ def mkExpressionStatement(site, expr, explicit_discard=False): def toc_constsafe_pointer_assignment(site, source, target, typ): target_val = mkDereference(site, - Cast(site, mkLit(site, target, TPtr(void)), TPtr(typ))) + Cast(site, mkLit(site, target, tp.Ptr(tp.void)), tp.Ptr(typ))) init = ExpressionInitializer( source_for_assignment(site, typ, mkLit(site, source, typ))) @@ -773,7 +776,7 @@ def toc_stmt(self): % (', '.join(i.read() for i in self.indices),) if self.indices else 'NULL') args = ('(%s){%s}' - % (TArray(self.info.args_type, + % (tp.Array(self.info.args_type, mkIntegerLiteral(self.site, 1)).declaration(''), self.args_init.args_init()) if self.info.args_type else 'NULL') @@ -799,7 +802,7 @@ def toc_stmt(self): if self.indices else 'NULL') if self.info.args_type is not None: args = ('(%s){%s}' - % (TArray(self.info.args_type, + % (tp.Array(self.info.args_type, mkIntegerLiteral(self.site, 1)).declaration(''), self.args_init.args_init())) args_size = f'sizeof({self.info.args_type.declaration("")})' @@ -834,7 +837,7 @@ def toc_under_if(stmt): class If(Statement): @auto_init def __init__(self, site, cond, truebranch, falsebranch, else_site): - assert_type(site, cond.ctype(), TBool) + assert_type(site, cond.ctype(), tp.Bool) assert_type(site, truebranch, Statement) assert_type(site, falsebranch, (Statement, type(None))) def toc_stmt(self): @@ -843,7 +846,7 @@ def toc_stmt(self): toc_under_if(self.truebranch) if self.falsebranch: - site_linemark(self.else_site) + output.site_linemark(self.else_site) out('else\n') self.falsebranch.toc_stmt() @@ -854,7 +857,7 @@ def control_flow(self): return a.union(b) def mkIf(site, cond, truebranch, falsebranch = None, else_site=None): - assert isinstance(cond.ctype(), TBool) + assert isinstance(cond.ctype(), tp.Bool) if cond.constant: if cond.value: return truebranch @@ -867,7 +870,7 @@ def mkIf(site, cond, truebranch, falsebranch = None, else_site=None): class While(Statement): @auto_init def __init__(self, site, cond, stmt): - assert_type(site, cond.ctype(), TBool) + assert_type(site, cond.ctype(), tp.Bool) assert_type(site, stmt, Statement) def toc_stmt(self): self.linemark() @@ -893,13 +896,13 @@ def mkWhile(site, expr, stmt): class DoWhile(Statement): @auto_init def __init__(self, site, cond, stmt): - assert_type(site, cond.ctype(), TBool) + assert_type(site, cond.ctype(), tp.Bool) assert_type(site, stmt, Statement) def toc_stmt(self): self.linemark() out('do\n') self.stmt.toc_stmt() - site_linemark(self.cond.site) + output.site_linemark(self.cond.site) out(f'while ({self.cond.read()});\n') def control_flow(self): bodyflow = self.stmt.control_flow() @@ -916,7 +919,7 @@ def mkDoWhile(site, expr, stmt): class For(Statement): @auto_init def __init__(self, site, pres, cond, posts, stmt): - assert_type(site, cond.ctype(), TBool) + assert_type(site, cond.ctype(), tp.Bool) assert_type(site, stmt, Statement) def toc_stmt(self): self.linemark() @@ -959,14 +962,14 @@ def mkFor(site, pres, expr, posts, stmt): class ForeachSequence(Statement): @staticmethod def itervar_initializer(site, trait): - trait_type = TTrait(trait) + trait_type = tp.Trait(trait) vtable_init = ExpressionInitializer(mkLit(site, '_list.vtable', trait_type)) list_id_init = ExpressionInitializer(mkLit(site, '_list.id', - TInt(32, False))) + tp.Int(32, False))) inner_idx_init = ExpressionInitializer(mkLit(site, '_inner_idx', - TInt(32, False))) + tp.Int(32, False))) obj_ref_init = CompoundInitializer(site, [list_id_init, inner_idx_init]) @@ -986,14 +989,14 @@ def lm_out(*args, **kwargs): self.linemark() out(*args, **kwargs) lm_out(f'_each_in_t __each_in_expr = {self.each_in_expr.read()};\n') - coverity_marker('unreachable', site=self.site) + output.coverity_marker('unreachable', site=self.site) out('for (uint32 _outer_idx = 0; _outer_idx < __each_in_expr.num; ' + '++_outer_idx) {\n', postindent=1) lm_out(f'_vtable_list_t _list = {EachIn.array_ident(self.trait)}' + '[__each_in_expr.base_idx + _outer_idx];\n') lm_out('uint32 _num = _list.num / __each_in_expr.array_size;\n') lm_out('uint32 _start = _num * __each_in_expr.array_idx;\n') - coverity_marker('unreachable', site=self.site) + output.coverity_marker('unreachable', site=self.site) out('for (uint32 _inner_idx = _start; _inner_idx < _start + _num; ' + '++_inner_idx)\n') self.body.toc_stmt() @@ -1052,7 +1055,7 @@ def __init__(self, site, cases, has_default): def toc_stmt(self): for (i, case) in enumerate(self.cases): assert isinstance(case, (Case, Default)) - site_linemark(case.site) + output.site_linemark(case.site) semi = ';' * (i == len(self.cases) - 1) if isinstance(case, Case): out(f'case {case.expr.read()}:{semi}\n', preindent = -1, @@ -1125,9 +1128,9 @@ def toc_stmt(self): def mkAssignStatement(site, target, init): if isinstance(target, InlinedParam): - raise EASSINL(target.site, target.name) + raise E.ASSINL(target.site, target.name) if not target.writable: - raise EASSIGN(site, target) + raise E.ASSIGN(site, target) if isinstance(target, NonValue): target_type = target.type if target.explicit_type else None @@ -1135,8 +1138,8 @@ def mkAssignStatement(site, target, init): target_type = target.ctype() - if target_type is not None and deep_const(target_type): - raise ECONST(site) + if target_type is not None and tp.deep_const(target_type): + raise E.CONST(site) return AssignStatement(site, target, init) @@ -1160,42 +1163,42 @@ def mkCopyData(site, source, target): def as_bool(e): "Change this expression to a boolean expression, if possible" t = e.ctype() - if isinstance(t, TBool): + if isinstance(t, tp.Bool): return e elif t.is_int and t.bits == 1: if logging.show_porting and (isinstance(e, NodeRef) or isinstance(e, LocalVariable)): - report(PBITNEQ(dmlparse.start_site(e.site), + report(P.BITNEQ(dmlparse.start_site(e.site), dmlparse.end_site(e.site))) return mkFlag(e.site, e) - elif isinstance(t, TPtr): + elif isinstance(t, tp.Ptr): return mkNotEquals(e.site, e, - Lit(None, 'NULL', TPtr(TVoid()), 1)) + expr.Lit(None, 'NULL', tp.Ptr(tp.Void()), 1)) else: - report(ENBOOL(e)) + report(E.NBOOL(e)) return mkBoolConstant(e.site, False) def as_int(e): - """Change this expression to a TInt type, if possible + """Change this expression to a tp.Int type, if possible - In dml 1.2-compat, TInt typed expressions are returned as-is + In dml 1.2-compat, tp.Int typed expressions are returned as-is Otherwise: Returns an unsigned 64-bit integer if the integer type of the expression is also unsigned 64-bit, for smaller or signed integer types returns a signed 64-bit integer """ - t = realtype(e.ctype()) - if isinstance(t, TInt) and dml.globals.compat_dml12_int(e.site): + t = tp.realtype(e.ctype()) + if isinstance(t, tp.Int) and dml.globals.compat_dml12_int(e.site): return e if not t.is_int: - raise EBTYPE(e.site, e.ctype(), "integer type") + raise E.BTYPE(e.site, e.ctype(), "integer type") if t.bits == 64 and not t.signed: - target_type = TInt(64, False) + target_type = tp.Int(64, False) else: - target_type = TInt(64, True) + target_type = tp.Int(64, True) if t.is_endian: (fun, funtype) = t.get_load_fun() e = dml.expr.Apply(e.site, mkLit(e.site, fun, funtype), (e,), funtype) - if not realtype(e.ctype()).eq(target_type): + if not tp.realtype(e.ctype()).eq(target_type): e = mkCast(e.site, e, target_type) return e else: @@ -1249,7 +1252,7 @@ def mkIfExpr(site, cond, texpr, fexpr): if ftype.is_int and ftype.is_endian: fexpr = as_int(fexpr) ftype = texpr.ctype() - utype = type_union(ttype, ftype) + utype = tp.type_union(ttype, ftype) if cond.constant: # Normally handled by expr_conditional; this only happens # in DMLC-internal mkIfExpr calls @@ -1259,8 +1262,8 @@ def mkIfExpr(site, cond, texpr, fexpr): return IfExpr(site, cond, texpr, fexpr, utype) else: cond = as_bool(cond) - ttype = safe_realtype(texpr.ctype()) - ftype = safe_realtype(fexpr.ctype()) + ttype = tp.safe_realtype(texpr.ctype()) + ftype = tp.safe_realtype(fexpr.ctype()) if ttype.is_arith or ftype.is_arith: ttype, texpr = arith_argument_conv(texpr) ftype, fexpr = arith_argument_conv(fexpr) @@ -1268,28 +1271,28 @@ def mkIfExpr(site, cond, texpr, fexpr): if ttype.is_float or ftype.is_float: texpr = promote_float(texpr, ttype) fexpr = promote_float(fexpr, ftype) - utype = TFloat('double') + utype = tp.Float('double') else: (texpr, fexpr, utype) = usual_int_conv( texpr, ttype, fexpr, ftype) else: - if (isinstance(ttype, (TPtr, TArray)) - and isinstance(ftype, (TPtr, TArray)) + if (isinstance(ttype, (tp.Ptr, tp.Array)) + and isinstance(ftype, (tp.Ptr, tp.Array)) and (ttype.base.void or ftype.base.void - or safe_realtype_unconst(ttype.base).eq( - safe_realtype_unconst(ftype.base)))): + or tp.safe_realtype_unconst(ttype.base).eq( + tp.safe_realtype_unconst(ftype.base)))): # if any branch is void, then the union is too base = (ftype if ftype.base.void else ttype).base.clone() # if any branch is const *, then the union is too - base.const = ((isinstance(ttype, TArray) and ttype.const) - or (isinstance(ftype, TArray) and ftype.const) - or shallow_const(ttype.base) - or shallow_const(ftype.base)) - utype = TPtr(base) - elif safe_realtype_unconst(ttype).eq(safe_realtype_unconst(ftype)): + base.const = ((isinstance(ttype, tp.Array) and ttype.const) + or (isinstance(ftype, tp.Array) and ftype.const) + or tp.shallow_const(ttype.base) + or tp.shallow_const(ftype.base)) + utype = tp.Ptr(base) + elif tp.safe_realtype_unconst(ttype).eq(tp.safe_realtype_unconst(ftype)): utype = ttype else: - raise EBINOP(site, ':', texpr, fexpr) + raise E.BINOP(site, ':', texpr, fexpr) if cond.constant: # should be safe: texpr and fexpr now have compatible types return texpr if cond.value else fexpr @@ -1326,10 +1329,10 @@ def make(cls, site, lh, rh): lhtype = lh.ctype() rhtype = rh.ctype() if (dml.globals.dml_version == (1, 2) - and (isinstance(lhtype, TUnknown) or isinstance(rhtype, TUnknown))): + and (isinstance(lhtype, tp.Unknown) or isinstance(rhtype, tp.Unknown))): # urgh, some classes take an extra constructor arg if issubclass(cls, (ArithBinOp, BitBinOp, BitShift)): - return cls(site, lh, rh, TUnknown) + return cls(site, lh, rh, tp.Unknown) else: return cls(site, lh, rh) @@ -1337,7 +1340,7 @@ def make(cls, site, lh, rh): class Test(Expression): "a boolean expression" - type = TBool() + type = tp.Bool() class Flag(Test): "a bit" @@ -1358,12 +1361,12 @@ def mkFlag(site, expr): return Flag(site, as_int(expr)) class Logical(BinOp): - type = TBool() + type = tp.Bool() @auto_init def __init__(self, site, lh, rh): - assert_type(site, lh.ctype(), TBool) - assert_type(site, rh.ctype(), TBool) + assert_type(site, lh.ctype(), tp.Bool) + assert_type(site, rh.ctype(), tp.Bool) class And(Logical): # gcc warns for priority = 50 @@ -1401,7 +1404,7 @@ def mkOr(site, lh, rh): return Or(site, lh, rh) class Compare(BinOp): - type = TBool() + type = tp.Bool() @abc.abstractproperty def cmp_functions(self): @@ -1416,8 +1419,8 @@ def eval_const(lh, rh): @classmethod def make(cls, site, lh, rh): - lhtype = realtype(lh.ctype()) - rhtype = realtype(rh.ctype()) + lhtype = tp.realtype(lh.ctype()) + rhtype = tp.realtype(rh.ctype()) if (lhtype.is_arith and rhtype.is_arith and lh.constant and rh.constant): @@ -1425,18 +1428,18 @@ def make(cls, site, lh, rh): if lhtype.is_int: lh_maybe_negative = lhtype.signed lh = as_int(lh) - lhtype = realtype(lh.ctype()) + lhtype = tp.realtype(lh.ctype()) if rhtype.is_int: rh_maybe_negative = rhtype.signed rh = as_int(rh) - rhtype = realtype(rh.ctype()) - if (isinstance(lhtype, TInt) - and isinstance(rhtype, TInt) + rhtype = tp.realtype(rh.ctype()) + if (isinstance(lhtype, tp.Int) + and isinstance(rhtype, tp.Int) and lh_maybe_negative != rh_maybe_negative): (signed_expr, unsigned_expr) = ((lh, rh) if lh_maybe_negative else (rh, lh)) if signed_expr.constant and signed_expr.value < 0: - report(WNEGCONSTCOMP(site, signed_expr, + report(W.NEGCONSTCOMP(site, signed_expr, unsigned_expr.ctype())) # we must convert (uint64)x < (int64)y to DML_lt(x, y), because # C:'s < would do an unsigned comparison. No need to do this if y @@ -1446,17 +1449,17 @@ def make(cls, site, lh, rh): return mkApply( site, mkLit( site, cls.cmp_functions[rh_maybe_negative], - TFunction([TInt(64, lh_maybe_negative), - TInt(64, rh_maybe_negative)], - TBool())), + tp.Function([tp.Int(64, lh_maybe_negative), + tp.Int(64, rh_maybe_negative)], + tp.Bool())), [lh, rh]) if ((lhtype.is_arith and rhtype.is_arith) - or (isinstance(lhtype, (TPtr, TArray)) - and isinstance(rhtype, (TPtr, TArray)) - and safe_realtype_unconst(lhtype.base).eq( - safe_realtype_unconst(rhtype.base)))): + or (isinstance(lhtype, (tp.Ptr, tp.Array)) + and isinstance(rhtype, (tp.Ptr, tp.Array)) + and tp.safe_realtype_unconst(lhtype.base).eq( + tp.safe_realtype_unconst(rhtype.base)))): return cls.make_simple(site, lh, rh) - raise EILLCOMP(site, lh, lhtype, rh, rhtype) + raise E.ILLCOMP(site, lh, lhtype, rh, rhtype) @classmethod def make_simple(cls, site, lh, rh): @@ -1486,9 +1489,9 @@ def read(self): @classmethod def make(cls, site, lh, rh): - if isinstance(realtype(lh.ctype()), IntegerType): + if isinstance(tp.realtype(lh.ctype()), tp.IntegerType): lh = as_int(lh) - if isinstance(realtype(rh.ctype()), IntegerType): + if isinstance(tp.realtype(rh.ctype()), tp.IntegerType): rh = as_int(rh) assert_comparable_types(site, lh, rh, cls.equality) # The assumption when calling Compare_dml12.make_simple is that lh @@ -1589,13 +1592,13 @@ def make_simple(site, lh, rh): class Equals(BinOp): priority = 70 - type = TBool() + type = tp.Bool() op = '==' @classmethod def make(cls, site, lh, rh): - lhtype = realtype(lh.ctype()) - rhtype = realtype(rh.ctype()) + lhtype = tp.realtype(lh.ctype()) + rhtype = tp.realtype(rh.ctype()) if lh.constant and rh.constant: (lhc, rhc) = tuple(e.expr if isinstance(e, InlinedParam) else e @@ -1626,8 +1629,8 @@ def make(cls, site, lh, rh): if (isinstance(lhc, NullConstant) and isinstance(rhc, NullConstant)): return mkBoolConstant(site, True) - elif (isinstance(lhtype, (TPtr, TArray)) - and isinstance(rhtype, (TPtr, TArray))): + elif (isinstance(lhtype, (tp.Ptr, tp.Array)) + and isinstance(rhtype, (tp.Ptr, tp.Array))): for expr in (lhc, rhc): assert isinstance(expr, (NullConstant, StringConstant, AddressOfMethod)) @@ -1635,13 +1638,13 @@ def make(cls, site, lh, rh): if lhtype.is_int: lh_maybe_negative = lhtype.signed lh = as_int(lh) - lhtype = realtype(lh.ctype()) + lhtype = tp.realtype(lh.ctype()) if rhtype.is_int: rh_maybe_negative = rhtype.signed rh = as_int(rh) - rhtype = realtype(rh.ctype()) + rhtype = tp.realtype(rh.ctype()) - if (isinstance(lhtype, TInt) and isinstance(rhtype, TInt) + if (isinstance(lhtype, tp.Int) and isinstance(rhtype, tp.Int) and lh_maybe_negative != rh_maybe_negative): # There is no primitive for signed/unsigned compare in C, # so use a lib function for it. However, we can fall back @@ -1650,32 +1653,32 @@ def make(cls, site, lh, rh): (signed_expr, unsigned_expr) = ((lh, rh) if lh_maybe_negative else (rh, lh)) if signed_expr.constant and signed_expr.value < 0: - report(WNEGCONSTCOMP(site, signed_expr, unsigned_expr.ctype())) + report(W.NEGCONSTCOMP(site, signed_expr, unsigned_expr.ctype())) if not (signed_expr.constant and 0 <= signed_expr.value < 1 << 63): return mkApply( site, mkLit( site, 'DML_eq', - TFunction([TInt(64, False), TInt(64, False)], TBool())), + tp.Function([tp.Int(64, False), tp.Int(64, False)], tp.Bool())), [lh, rh]) if ((lhtype.is_arith and rhtype.is_arith) - or (isinstance(lhtype, (TPtr, TArray)) - and isinstance(rhtype, (TPtr, TArray)) + or (isinstance(lhtype, (tp.Ptr, tp.Array)) + and isinstance(rhtype, (tp.Ptr, tp.Array)) and (lhtype.base.void or rhtype.base.void - or safe_realtype_unconst(lhtype.base).eq( - safe_realtype_unconst(rhtype.base)))) - or (isinstance(lhtype, TBool) and isinstance(rhtype, TBool))): + or tp.safe_realtype_unconst(lhtype.base).eq( + tp.safe_realtype_unconst(rhtype.base)))) + or (isinstance(lhtype, tp.Bool) and isinstance(rhtype, tp.Bool))): return Equals(site, lh, rh) - if (isinstance(lhtype, TTrait) and isinstance(rhtype, TTrait) + if (isinstance(lhtype, tp.Trait) and isinstance(rhtype, tp.Trait) and lhtype.trait is rhtype.trait): return IdentityEq(site, TraitObjIdentity(lh.site, lh), TraitObjIdentity(rh.site, rh)) - if (isinstance(lhtype, THook) and isinstance(rhtype, THook) + if (isinstance(lhtype, tp.Hook) and isinstance(rhtype, tp.Hook) and lhtype.eq(rhtype)): return IdentityEq(site, lh, rh) - raise EILLCOMP(site, lh, lhtype, rh, rhtype) + raise E.ILLCOMP(site, lh, lhtype, rh, rhtype) def mkEquals(site, lh, rh): if dml.globals.compat_dml12_int(site): @@ -1685,7 +1688,7 @@ def mkEquals(site, lh, rh): class IdentityEq(Expression): priority = dml.expr.Apply.priority - type = TBool() + type = tp.Bool() @auto_init def __init__(self, site, lh, rh): pass @@ -1704,7 +1707,7 @@ def read(self): return f'_identity_eq({self.lh.read()}, {self.rh.read()})' else: return (f'_identity_eq_at_site({self.lh.read()}, {self.rh.read()}' - + f', "{quote_filename(self.site.filename())}", ' + + f', "{output.quote_filename(self.site.filename())}", ' + f'{self.site.lineno})') @@ -1739,7 +1742,7 @@ def usual_int_conv(lh, lhtype, rh, rhtype): return (lh, mkCast(rh.site, rh, lhtype), lhtype) if rh_is_uint64: return (mkCast(lh.site, lh, rhtype), rh, rhtype) - int64 = TInt(64, True) + int64 = tp.Int(64, True) if lhtype.bits != 64: lh = mkCast(lh.site, lh, int64) if rhtype.bits != 64: @@ -1756,7 +1759,7 @@ def __init__(self, site, lh, rh): def detect_type(lh, rh): ltype = lh.ctype() rtype = rh.ctype() - return type_union(ltype, rtype) + return tp.type_union(ltype, rtype) def __str__(self): lh = str(self.lh) rh = str(self.rh) @@ -1820,14 +1823,14 @@ def detect_type(lh, rh): def make_simple(site, lh, rh): lh = as_int(lh) rh = as_int(rh) - ltype = realtype(lh.ctype()) - rtype = realtype(rh.ctype()) + ltype = tp.realtype(lh.ctype()) + rtype = tp.realtype(rh.ctype()) if lh.constant and rh.constant: return IntegerConstant_dml12(site, lh.value & rh.value) expr = BitAnd_dml12(site, lh, rh) - etype = realtype(expr.ctype()) + etype = tp.realtype(expr.ctype()) if not etype.is_int: raise ICE(site, "Strange! ANDed to non-integer ('%s' & '%s' -> '%s')" @@ -1922,7 +1925,7 @@ class ShL_dml12(BitShift_dml12): @staticmethod def detect_type(lh, rh): - return TInt(64, False) + return tp.Int(64, False) @staticmethod def make_simple(site, lh, rh): @@ -1933,7 +1936,7 @@ def make_simple(site, lh, rh): if rh.value < 0: # it's an error in Python to shift a negative number of bits # (better raise an error instead of e.g. substituting 0) - raise ESHNEG(site, rh) + raise E.SHNEG(site, rh) elif rh.value == 0: return lh @@ -1966,9 +1969,9 @@ def make_simple(site, lh, rh): shiftval.value = -shiftval.value return mkShR(site, lh, shiftval) - lhtype = safe_realtype(lh.ctype()) + lhtype = tp.safe_realtype(lh.ctype()) if lhtype.bits < 64 or lhtype.signed: - lh = mkCast(site, lh, TInt(64, False)) + lh = mkCast(site, lh, tp.Int(64, False)) return ShL_dml12(site, lh, rh) @@ -1989,7 +1992,7 @@ def make_simple(cls, site, lh, rh): (lh, rh, common_type) = usual_int_conv(lh, ltype, rh, rtype) if rh.constant and rh.value < 0: - raise ESHNEG(site, rh) + raise E.SHNEG(site, rh) if lh.constant and rh.constant: return mkIntegerConstant(site, cls.eval_const(lh.value, rh.value), common_type.signed) @@ -2008,7 +2011,7 @@ def read(self): if self.type.signed: return ('DML_shl(%s, %s, "%s", %s)' % (self.lh.read(), self.rh.read(), - quote_filename(self.site.filename()), + output.quote_filename(self.site.filename()), self.site.lineno)) else: return 'DML_shlu(%s, %s)' % (self.lh.read(), self.rh.read()) @@ -2024,7 +2027,7 @@ class ShR_dml12(BitShift_dml12): @staticmethod def type_shift(site, etype, shift): - etype = realtype(etype) + etype = tp.realtype(etype) if not etype.is_int: raise ICE(site, "Shifting a non-integer") bits = etype.bits + shift @@ -2032,17 +2035,17 @@ def type_shift(site, etype, shift): bits = 0 if bits > 64: bits = 64 - return TInt(bits, etype.signed if etype.is_int else False) + return tp.Int(bits, etype.signed if etype.is_int else False) @staticmethod def detect_type(lh, rh): if rh.constant: ltype = lh.ctype() - if isinstance(ltype, TUnknown): + if isinstance(ltype, tp.Unknown): return ltype return ShR_dml12.type_shift(lh.site, ltype, -rh.value) else: - return TInt(64, False) + return tp.Int(64, False) @staticmethod def make_simple(site, lh, rh): @@ -2053,7 +2056,7 @@ def make_simple(site, lh, rh): if rh.value < 0: # it's an error in Python to shift a negative number of bits # (better raise an error instead of e.g. substituting 0) - raise ESHNEG(site, rh) + raise E.SHNEG(site, rh) elif rh.value == 0: return lh @@ -2061,11 +2064,11 @@ def make_simple(site, lh, rh): return IntegerConstant_dml12(site, lh.value >> rh.value) expr = ShR_dml12(site, lh, rh) - etype = realtype(expr.ctype()) + etype = tp.realtype(expr.ctype()) assert etype.is_int - ltype = realtype(lh.ctype()) + ltype = tp.realtype(lh.ctype()) if etype.bits < 1: - report(WSHALL(site, lh, rh)) + report(W.SHALL(site, lh, rh)) elif ltype.bits > 32 and etype.bits <= 32: expr = mkCast(site, expr, etype) return expr @@ -2083,7 +2086,7 @@ def read(self): if self.type.signed: return ('DML_shr(%s, %s, "%s", %s)' % (self.lh.read(), self.rh.read(), - quote_filename(self.site.filename()), + output.quote_filename(self.site.filename()), self.site.lineno)) else: return 'DML_shru(%s, %s)' % (self.lh.read(), self.rh.read()) @@ -2103,23 +2106,23 @@ def __init__(self, site, lh, rh): @staticmethod def detect_type(lh, rh): - ltype = safe_realtype(lh.ctype()) - rtype = safe_realtype(rh.ctype()) - if isinstance(ltype, TUnknown) or isinstance(rtype, TUnknown): - return TUnknown() + ltype = tp.safe_realtype(lh.ctype()) + rtype = tp.safe_realtype(rh.ctype()) + if isinstance(ltype, tp.Unknown) or isinstance(rtype, tp.Unknown): + return tp.Unknown() # This is actually only valid for add/sub, but put it here for # convenience - if (isinstance(ltype, (TPtr, TArray)) - and isinstance(rtype, (TPtr, TArray))): - return TNamed('int') # actually ptrdiff_t - if isinstance(ltype, (TPtr, TArray)) and rtype.is_int: + if (isinstance(ltype, (tp.Ptr, tp.Array)) + and isinstance(rtype, (tp.Ptr, tp.Array))): + return tp.Named('int') # actually ptrdiff_t + if isinstance(ltype, (tp.Ptr, tp.Array)) and rtype.is_int: return ltype - if isinstance(rtype, (TPtr, TArray)) and ltype.is_int: + if isinstance(rtype, (tp.Ptr, tp.Array)) and ltype.is_int: return rtype if ltype.is_float or rtype.is_float: - return TFloat('double') + return tp.Float('double') assert ltype.is_int and rtype.is_int if ltype.bits > rtype.bits: return ltype @@ -2173,23 +2176,23 @@ def make_simple(cls, site, lh, rh): if ltype.is_float or rtype.is_float: lh = promote_float(lh, ltype) rh = promote_float(rh, rtype) - return cls(site, lh, rh, TFloat('double')) + return cls(site, lh, rh, tp.Float('double')) int64_result = ((ltype.bits < 64 or ltype.signed) and (rtype.bits < 64 or rtype.signed)) if lh.constant and rh.constant: return mkIntegerConstant(site, cls.eval_const(lh.value, rh.value), int64_result) - uint64 = TInt(64, False) + uint64 = tp.Int(64, False) result = cls(site, mkCast(site, lh, uint64), mkCast(site, rh, uint64), uint64) if int64_result: - result = mkCast(site, result, TInt(64, True)) + result = mkCast(site, result, tp.Int(64, True)) return result @property def is_pointer_to_stack_allocation(self): - return (isinstance(safe_realtype_shallow(self.ctype()), (TPtr, TArray)) + return (isinstance(tp.safe_realtype_shallow(self.ctype()), (tp.Ptr, tp.Array)) and (self.lh.is_pointer_to_stack_allocation or self.rh.is_pointer_to_stack_allocation)) @@ -2244,7 +2247,7 @@ def make_simple(site, lh, rh): if rh.constant and rhtype.is_int: if rh.value == 0: - raise EDIVZ(rh, '/') + raise E.DIVZ(rh, '/') elif rh.value == 1: return lh elif lh.constant and lhtype.is_int: @@ -2260,7 +2263,7 @@ def make_simple(cls, site, lh, rh): if lhtype.is_float or rhtype.is_float: lh = promote_float(lh, lhtype) rh = promote_float(rh, rhtype) - return cls(site, lh, rh, TFloat('double')) + return cls(site, lh, rh, tp.Float('double')) (lh, rh, common_type) = usual_int_conv(lh, lhtype, rh, rhtype) if lh.constant and rh.constant: @@ -2274,7 +2277,7 @@ class Div(DivModOp): @staticmethod def eval_const(left, right): if right == 0: - raise EDIVZ(right, '/') + raise E.DIVZ(right, '/') if (left < 0) == (right < 0): return left // right else: @@ -2285,7 +2288,7 @@ def read(self): return ('%s(%s, %s, "%s", %s)' % ('DML_div' if self.type.signed else 'DML_divu', self.lh.read(), self.rh.read(), - quote_filename(self.site.filename()), + output.quote_filename(self.site.filename()), self.site.lineno)) def mkDiv(site, lh, rh): @@ -2305,7 +2308,7 @@ def make_simple(site, lh, rh): if rh.constant: if rh.value == 0: - raise EDIVZ(rh, '%') + raise E.DIVZ(rh, '%') elif lh.constant: return IntegerConstant_dml12(site, lh.value % rh.value) @@ -2318,7 +2321,7 @@ class Mod(DivModOp): @staticmethod def eval_const(lh, rh): if rh == 0: - raise EDIVZ(rh, '%') + raise E.DIVZ(rh, '%') if lh < 0: return -(abs(lh) % abs(rh)) else: @@ -2328,7 +2331,7 @@ def read(self): return ('%s(%s, %s, "%s", %s)' % ('DML_mod' if self.type.signed else 'DML_modu', self.lh.read(), self.rh.read(), - quote_filename(self.site.filename()), + output.quote_filename(self.site.filename()), self.site.lineno)) def mkMod(site, lh, rh): @@ -2349,18 +2352,18 @@ def make_simple(site, lh, rh): if (isinstance(lh, StringConstant) and isinstance(rh, StringConstant)): return mkStringConstant(site, lh.value + rh.value) - lhtype = realtype(lh.ctype()) - rhtype = realtype(rh.ctype()) + lhtype = tp.realtype(lh.ctype()) + rhtype = tp.realtype(rh.ctype()) # Type check if lhtype.is_arith and rhtype.is_arith: pass - elif lhtype.is_int and isinstance(rhtype, (TPtr, TArray)): + elif lhtype.is_int and isinstance(rhtype, (tp.Ptr, tp.Array)): pass - elif isinstance(lhtype, (TPtr, TArray)) and rhtype.is_int: + elif isinstance(lhtype, (tp.Ptr, tp.Array)) and rhtype.is_int: pass else: - raise EBINOP(site, '+', lh, rh) + raise E.BINOP(site, '+', lh, rh) # Constant folding if lh.constant and rh.constant and lhtype.is_int and rhtype.is_int: @@ -2381,9 +2384,9 @@ def make_simple(site, lh, rh): if rh.constant and isinstance(lh, Subtract) and lh.rh.constant: return mkAdd(site, lh.lh, mkSubtract(site, rh, lh.rh)) - if not isinstance(lhtype, (TPtr, TArray)): + if not isinstance(lhtype, (tp.Ptr, tp.Array)): _, lh = arith_argument_conv(lh) - if not isinstance(rhtype, (TPtr, TArray)): + if not isinstance(rhtype, (tp.Ptr, tp.Array)): _, rh = arith_argument_conv(rh) return Add_dml12(site, lh, rh) @@ -2400,22 +2403,22 @@ def eval_const(left, right): def make_simple(site, lh, rh): if isinstance(lh, StringConstant) and isinstance(rh, StringConstant): return StringConstant(site, lh.value + rh.value) - lhtype = realtype(lh.ctype()) - rhtype = realtype(rh.ctype()) + lhtype = tp.realtype(lh.ctype()) + rhtype = tp.realtype(rh.ctype()) # ECSADD should always be emitted when the operand types are equivalent # to char pointers/arrays -- even including when the operands are # explicitly typed as int8 pointers/arrays - if (isinstance(lhtype, (TArray, TPtr)) - and isinstance(rhtype, (TArray, TPtr)) - and isinstance(lhtype.base, TInt) and isinstance(rhtype.base, TInt) + if (isinstance(lhtype, (tp.Array, tp.Ptr)) + and isinstance(rhtype, (tp.Array, tp.Ptr)) + and isinstance(lhtype.base, tp.Int) and isinstance(rhtype.base, tp.Int) and lhtype.base.bits == 8 and rhtype.base.bits == 8 and lhtype.base.signed and rhtype.base.signed): - raise ECSADD(site) - if (isinstance(lhtype, (TArray, TPtr)) + raise E.CSADD(site) + if (isinstance(lhtype, (tp.Array, tp.Ptr)) and not lhtype.base.void): rtype, rh = arith_argument_conv(rh) return Add(site, lh, rh, lhtype) - elif (isinstance(rhtype, (TArray, TPtr)) + elif (isinstance(rhtype, (tp.Array, tp.Ptr)) and not rhtype.base.void): ltype, lh = arith_argument_conv(lh) return Add(site, lh, rh, rhtype) @@ -2434,19 +2437,19 @@ class Subtract_dml12(ArithBinOp_dml12): @staticmethod def make_simple(site, lh, rh): - lhtype = realtype(lh.ctype()) - rhtype = realtype(rh.ctype()) + lhtype = tp.realtype(lh.ctype()) + rhtype = tp.realtype(rh.ctype()) # Type check - if (isinstance(lhtype, (TPtr, TArray)) - and isinstance(rhtype, (TPtr, TArray, IntegerType))): + if (isinstance(lhtype, (tp.Ptr, tp.Array)) + and isinstance(rhtype, (tp.Ptr, tp.Array, tp.IntegerType))): pass - elif lhtype.is_int and isinstance(rhtype, (TPtr, TArray)): + elif lhtype.is_int and isinstance(rhtype, (tp.Ptr, tp.Array)): pass elif lhtype.is_arith and rhtype.is_arith: pass else: - raise EBINOP(site, '-', lh, rh) + raise E.BINOP(site, '-', lh, rh) # Constant folding if (lh.constant and rh.constant @@ -2474,9 +2477,9 @@ def make_simple(site, lh, rh): if isinstance(lh, Subtract) and lh.rh.constant: return mkSubtract(site, mkSubtract(site, lh.lh, rh), lh.rh) - if not isinstance(lhtype, (TPtr, TArray)): + if not isinstance(lhtype, (tp.Ptr, tp.Array)): _, lh = arith_argument_conv(lh) - if not isinstance(rhtype, (TPtr, TArray)): + if not isinstance(rhtype, (tp.Ptr, tp.Array)): _, rh = arith_argument_conv(rh) return Subtract_dml12(site, lh, rh) @@ -2489,18 +2492,18 @@ def eval_const(left, right): return left - right @staticmethod def make_simple(site, lh, rh): - lhtype = realtype(lh.ctype()) - rhtype = realtype(rh.ctype()) - if (isinstance(lhtype, (TArray, TPtr)) + lhtype = tp.realtype(lh.ctype()) + rhtype = tp.realtype(rh.ctype()) + if (isinstance(lhtype, (tp.Array, tp.Ptr)) and not lhtype.base.void): - if (isinstance(rhtype, (TArray, TPtr)) + if (isinstance(rhtype, (tp.Array, tp.Ptr)) and not rhtype.base.void): # ptrdiff case - return Subtract(site, lh, rh, TInt(64, True)) + return Subtract(site, lh, rh, tp.Int(64, True)) else: rh = as_int(rh) return Subtract(site, lh, rh, lhtype) - elif (isinstance(rhtype, (TArray, TPtr)) + elif (isinstance(rhtype, (tp.Array, tp.Ptr)) and not rhtype.base.void): lh = as_int(lh) return Subtract(site, lh, rh, rhtype) @@ -2519,18 +2522,18 @@ def source_for_assignment(site, target_type, source): and return the source expression, maybe updated.""" try: source_type = source.ctype() - if isinstance(source_type, TUnknown): - raise ENTYPE(site) - real_target_type = realtype(target_type) - real_source_type = realtype(source_type) + if isinstance(source_type, tp.Unknown): + raise E.NTYPE(site) + real_target_type = tp.realtype(target_type) + real_source_type = tp.realtype(source_type) ok, trunc, constviol = real_target_type.canstore(real_source_type) if constviol: - raise EDISCONST(site) + raise E.DISCONST(site) if not ok: # Assigning boolean values to one-bit targets is ok - if (isinstance(real_target_type, TInt) + if (isinstance(real_target_type, tp.Int) and real_target_type.bits == 1 - and isinstance(real_source_type, TBool)): + and isinstance(real_source_type, tp.Bool)): # Using IfExpr is a little overhead, but probably # not a problem if isinstance(source, Not): @@ -2542,17 +2545,17 @@ def source_for_assignment(site, target_type, source): mkIntegerLiteral(site, 1), mkIntegerLiteral(site, 0)) else: - raise EASTYPE(site, target_type, source) - if ((isinstance(real_target_type, TInt) + raise E.ASTYPE(site, target_type, source) + if ((isinstance(real_target_type, tp.Int) and not dml.globals.compat_dml12_int(site)) or (real_target_type.is_int and real_target_type.is_endian) or (real_source_type.is_int and real_source_type.is_endian)): - # For TInt, possibly truncate upper bits or coerce to endianint + # For tp.Int, possibly truncate upper bits or coerce to endianint # For endian type, coerce to endianint struct source = mkCast(site, source, target_type) - except DMLUnknownType as e: - raise ETYPE(site, e.type) + except tp.DMLUnknownType as e: + raise E.TYPE(site, e.type) return source class AssignOp(BinOp): @@ -2577,15 +2580,15 @@ def is_pointer_to_stack_allocation(self): def mkAssignOp(site, target, source): if isinstance(target, InlinedParam): - raise EASSINL(target.site, target.name) + raise E.ASSINL(target.site, target.name) if not target.writable: - raise EASSIGN(site, target) + raise E.ASSIGN(site, target) target_type = target.ctype() source = source_for_assignment(site, target_type, source) - if deep_const(target_type): - raise ECONST(site) + if tp.deep_const(target_type): + raise E.CONST(site) return AssignOp(site, target, source) class UnaryOp(Expression): @@ -2622,7 +2625,7 @@ class AddressOf(UnaryOp): op = '&' @auto_init def __init__(self, site, rh): - self.type = TPtr(rh.ctype()) + self.type = tp.Ptr(rh.ctype()) def read(self): if hasattr(self.rh, 'read_pointer'): return self.rh.read_pointer() @@ -2638,12 +2641,12 @@ def make_simple(cls, site, rh): and node.parent.objtype == 'event': return AddressOf(site, mkLit( site, '_DML_EV_'+crep.cref_method(node), - TFunction([TPtr(TNamed('conf_object_t')), - TPtr(TVoid())], - TVoid()))) + tp.Function([tp.Ptr(tp.Named('conf_object_t')), + tp.Ptr(tp.Void())], + tp.Void()))) if (breaking_changes.dml12_remove_misc_quirks.enabled and not rh.addressable): - raise ERVAL(rh.site, '&') + raise E.RVAL(rh.site, '&') return AddressOf(site, rh) @property @@ -2652,10 +2655,10 @@ def is_pointer_to_stack_allocation(self): def mkAddressOf(site, rh): if dml.globals.compat_dml12_int(site): - t = safe_realtype(rh.ctype()) + t = tp.safe_realtype(rh.ctype()) if t.is_int and t.is_endian: return mkCast(site, AddressOf.make(site, rh), - TPtr(TInt(t.bits, t.signed, t.members))) + tp.Ptr(tp.Int(t.bits, t.signed, t.members))) return AddressOf.make(site, rh) class Dereference(UnaryOp, LValue): @@ -2664,20 +2667,20 @@ class Dereference(UnaryOp, LValue): explicit_type = True def __init__(self, site, rh): super(Dereference, self).__init__(site, rh) - typ = realtype_shallow(self.rh.ctype()) - if isinstance(typ, TPtr): + typ = tp.realtype_shallow(self.rh.ctype()) + if isinstance(typ, tp.Ptr): self.type = typ.base - elif isinstance(typ, TUnknown): + elif isinstance(typ, tp.Unknown): self.type = typ else: raise ICE(self.site, "unknown expression type") @staticmethod def make_simple(site, rh): - etype = realtype(rh.ctype()) + etype = tp.realtype(rh.ctype()) - if etype and not isinstance(etype, TPtr): - raise ENOPTR(site, rh) + if etype and not isinstance(etype, tp.Ptr): + raise E.NOPTR(site, rh) return Dereference(site, rh) @property @@ -2686,14 +2689,14 @@ def is_stack_allocated(self): @property def is_pointer_to_stack_allocation(self): - return (isinstance(safe_realtype_shallow(self.type), TArray) + return (isinstance(tp.safe_realtype_shallow(self.type), tp.Array) and self.is_stack_allocated) mkDereference = Dereference.make class Not(UnaryOp): op = '!' - type = TBool() + type = tp.Bool() @staticmethod def make_simple(site, rh): @@ -2718,12 +2721,12 @@ class BitNot(ArithUnaryOp): def __init__(self, site, rh, signed): pass def ctype(self): - return TInt(64, self.signed) + return tp.Int(64, self.signed) @staticmethod def make_simple(site, rh): rh = as_int(rh) - rhtype = realtype(rh.ctype()) + rhtype = tp.realtype(rh.ctype()) if rh.constant: return mkIntegerConstant(site, ~rh.value, rhtype.signed) return BitNot(site, rh, rhtype.signed) @@ -2737,21 +2740,21 @@ def mkBitNot(site, rh): def arith_argument_conv(expr): """Expect argument to be an integer, float, or double return (type, expr) where expr is potentially modified""" - etype = safe_realtype(expr.ctype()) + etype = tp.safe_realtype(expr.ctype()) if etype.is_float: return (etype, expr) else: try: new_expr = as_int(expr) - except EBTYPE: + except E.BTYPE: # This translation result in slightly more informative errors - raise EBTYPE(expr.site, expr.ctype(), "float or integer") - return (safe_realtype(new_expr.ctype()), new_expr) + raise E.BTYPE(expr.site, expr.ctype(), "float or integer") + return (tp.safe_realtype(new_expr.ctype()), new_expr) def promote_integer(expr, etype): assert etype.is_int signed = etype.bits < 64 or etype.signed - return (mkCast(expr.site, expr, TInt(64, signed)), signed) + return (mkCast(expr.site, expr, tp.Int(64, signed)), signed) def promote_float(expr, etype): assert etype.is_arith @@ -2760,16 +2763,16 @@ def promote_float(expr, etype): if expr.constant: return FloatConstant(expr.site, float(expr.value)) else: - return mkCast(expr.site, expr, TFloat('double')) + return mkCast(expr.site, expr, tp.Float('double')) class UnaryMinus(ArithUnaryOp): op = '-' def ctype(self): origtype = self.rh.ctype() - t = safe_realtype(origtype) + t = tp.safe_realtype(origtype) if t.is_int: if dml.globals.compat_dml12_int(self.site): - return TInt(t.bits, True) + return tp.Int(t.bits, True) else: assert t.bits == 64 return t @@ -2779,12 +2782,12 @@ def ctype(self): @staticmethod def make_simple(site, rh): - rhtype = safe_realtype(rh.ctype()) + rhtype = tp.safe_realtype(rh.ctype()) if rhtype.is_float: if not dml.globals.compat_dml12_int(site): rh = promote_float(rh, rhtype) - elif not isinstance(rhtype, TInt): + elif not isinstance(rhtype, tp.Int): raise ICE(site, "Unexpected wrong type of argument to unary minus") if rh.constant: @@ -2819,30 +2822,30 @@ class IncDec(UnaryOp): def read(self): raise ICE(self, "unimplemented operation") def ctype(self): - t = realtype(self.rh.ctype()) + t = tp.realtype(self.rh.ctype()) if t.is_int: if t.is_endian: return t.access_type elif dml.globals.compat_dml12_int(self.site): - return TInt(t.bits, True) + return tp.Int(t.bits, True) else: return t else: - assert isinstance(t, TPtr) + assert isinstance(t, tp.Ptr) return t @classmethod def make_simple(cls, site, rh): - rhtype = safe_realtype(rh.ctype()) - if not isinstance(rhtype, (IntegerType, TPtr)): - raise EINCTYPE(site, cls.op) + rhtype = tp.safe_realtype(rh.ctype()) + if not isinstance(rhtype, (tp.IntegerType, tp.Ptr)): + raise E.INCTYPE(site, cls.op) if not rh.addressable: if isinstance(rh, BitSlice): hint = 'try %s= 1' % (cls.base_op[0],) else: hint = None - raise EINC(site, hint) + raise E.INC(site, hint) result = cls(site, rh) - if dml.globals.compat_dml12_int(site) or isinstance(rhtype, TPtr): + if dml.globals.compat_dml12_int(site) or isinstance(rhtype, tp.Ptr): return result else: (result, signed) = promote_integer(result, rhtype) @@ -2860,7 +2863,7 @@ class PreIncDec(IncDec): def __str__(self): return '%s(%s)' % (self.base_op, self.rh) def read(self): - rh_type = safe_realtype(self.rh.ctype()) + rh_type = tp.safe_realtype(self.rh.ctype()) if rh_type.is_int and rh_type.is_endian: return '%s(%s, %s, false)' % ( rh_type.dmllib_fun("prechange"), @@ -2883,7 +2886,7 @@ class PostIncDec(IncDec): def __str__(self): return '(%s)%s' % (self.rh, self.base_op) def read(self): - rh_type = safe_realtype(self.rh.ctype()) + rh_type = tp.safe_realtype(self.rh.ctype()) if rh_type.is_int and rh_type.is_endian: return '%s(%s, %s, true)' % ( rh_type.dmllib_fun("prechange"), @@ -2923,11 +2926,11 @@ def read_iface_struct(iface_noderef): return mkCast(iface_noderef.site, mkSubRef(iface_noderef.site, iface_noderef, 'val', '.'), - TPtr(TNamed(struct_name, const=True))).read() + tp.Ptr(tp.Named(struct_name, const=True))).read() class MethodPresent(Expression): '''Whether a method in an interface object is NULL''' - type = TBool() + type = tp.Bool() @auto_init def __init__(self, site, expr): assert isinstance(expr, InterfaceMethodRef) @@ -2972,33 +2975,33 @@ def apply(self, inits, location, scope): self.site, self.node_expr, self.method_name, [self.obj_arg] + args, self.ftype.output_type) def exc(self): - return EIFREF(self.site, self) + return E.IFREF(self.site, self) def mkInterfaceMethodRef(site, iface_node, indices, method_name): struct_name = param_str(iface_node, 'c_type' if dml.globals.dml_version == (1, 2) else '_c_type') - stype = typedefs.get(struct_name) + stype = tp.typedefs.get(struct_name) if not stype: # should never happen: If interface does not exist, # then EIFTYPE is signalled and creation of interface # node is suppressed raise ICE(site, "unknown type %r" % (struct_name,)) - stype = safe_realtype(stype) - if not isinstance(stype, StructType): - raise ENOSTRUCT(site, mkNodeRef(site, iface_node, indices), stype) + stype = tp.safe_realtype(stype) + if not isinstance(stype, tp.StructType): + raise E.NOSTRUCT(site, mkNodeRef(site, iface_node, indices), stype) ftype = stype.get_member_qualified(method_name) if not ftype: - raise EMEMBER(site, struct_name, method_name) - ftype = safe_realtype(ftype) + raise E.MEMBER(site, struct_name, method_name) + ftype = tp.safe_realtype(ftype) - if (not isinstance(ftype, TPtr) - or not isinstance(ftype.base, TFunction) + if (not isinstance(ftype, tp.Ptr) + or not isinstance(ftype.base, tp.Function) or not ftype.base.input_types - or not TPtr(safe_realtype_unconst(TNamed('conf_object_t'))).eq( - safe_realtype_unconst(ftype.base.input_types[0]))): + or not tp.Ptr(tp.safe_realtype_unconst(tp.Named('conf_object_t'))).eq( + tp.safe_realtype_unconst(ftype.base.input_types[0]))): # non-method members are not accessible - raise EMEMBER(site, struct_name, method_name) + raise E.MEMBER(site, struct_name, method_name) obj_node = iface_node.parent.get_component('obj') if not obj_node or not obj_node.objtype == 'session': @@ -3017,11 +3020,11 @@ class BitSlice(Expression): def __init__(self, site, expr, msb, lsb, size, mask): # lsb is None if i[bitnum] (as opposed to i[msb:lsb]) notation was used if size: - const = deep_const(self.expr.ctype()) + const = tp.deep_const(self.expr.ctype()) if size.constant: - self.type = TInt(size.value, False, const=const) + self.type = tp.Int(size.value, False, const=const) else: - self.type = TInt(64, False, const=const) + self.type = tp.Int(64, False, const=const) self.read_expr = mkBitAnd(site, mkShR(site, expr, lsb or msb), mask) @@ -3057,11 +3060,11 @@ def write(self, source): expr = mkApply(self.site, mkLit(self.site, 'DML_combine_bits', - TFunction([TInt(64, False), TInt(64, False), - TInt(64, False)], - TInt(64, False))), + tp.Function([tp.Int(64, False), tp.Int(64, False), + tp.Int(64, False)], + tp.Int(64, False))), (self.expr, source_expr, mask)) - target_type = realtype(self.expr.ctype()) + target_type = tp.realtype(self.expr.ctype()) if target_type.is_int and target_type.is_endian: expr = mkCast(self.site, expr, target_type) return self.expr.write(ExpressionInitializer(expr)) @@ -3072,9 +3075,9 @@ def mkBitSlice(site, expr, msb, lsb, bitorder): # that the expression may be used as a bool even if the bit number # is not a constant. - t = realtype(expr.ctype()) + t = tp.realtype(expr.ctype()) if not t.is_int: - report(EBSLICE(site)) + report(E.BSLICE(site)) return expr if not bitorder: @@ -3083,7 +3086,7 @@ def mkBitSlice(site, expr, msb, lsb, bitorder): if bitorder != 'le': if not expr.explicit_type: #dbg('BITSLICE %r : %r' % (expr, t)) - raise EBSBE(site) + raise E.BSBE(site) # Normalize to le bitorder expr_bits = mkIntegerLiteral(site, t.bits) @@ -3100,7 +3103,7 @@ def mkBitSlice(site, expr, msb, lsb, bitorder): if size.constant: if size.value <= 0 or size.value > 64: - raise EBSSIZE(site, size) + raise E.BSSIZE(site, size) mask = mkIntegerConstant(site, (1 << size.value) - 1, False) else: mask = mkSubtract(site, @@ -3126,7 +3129,7 @@ def read(self): macro = f'CALL_{infix_independent}TRAIT_METHOD{suffix_noarg}' args = (['_dev'] * (not self.independent) + [arg.read() for arg in [self.traitref] + self.inargs]) - trait_name = cident(realtype(self.traitref.ctype()).trait.name) + trait_name = tp.cident(tp.realtype(self.traitref.ctype()).trait.name) return f"{macro}({trait_name}, {self.methname}, {', '.join(args)})" class TraitMethodApplyDirect(Expression): @@ -3134,7 +3137,7 @@ class TraitMethodApplyDirect(Expression): @auto_init def __init__(self, site, traitref, methodref, inargs, type): # traitref is a reference to method's vtable trait - assert realtype(traitref.ctype()).trait == methodref.vtable_trait + assert tp.realtype(traitref.ctype()).trait == methodref.vtable_trait assert methodref.__class__.__name__ == 'TraitMethod' if not methodref.independent: crep.require_dev(site) @@ -3153,7 +3156,7 @@ class New(Expression): slots = ('type',) @auto_init def __init__(self, site, newtype, count): - self.type = TPtr(newtype) + self.type = tp.Ptr(newtype) def __str__(self): if self.count: return 'new %s[%s]' % (self.newtype, self.count) @@ -3285,7 +3288,7 @@ def __str__(self): self.trait.name, self.node.logname(self.indices)) def ctype(self): - return TTraitList(self.trait.name) + return tp.TraitList(self.trait.name) @staticmethod def index_ident(node, trait): @@ -3346,7 +3349,7 @@ def read(self): class SequenceLength(Expression): '''The length of a sequence''' - type = TInt(64, False) + type = tp.Int(64, False) @auto_init def __init__(self, site, expr, trait): pass @@ -3408,7 +3411,7 @@ def mkIntegerConstant(site, value, signed): if dml.globals.compat_dml12_int(site): return IntegerConstant_dml12(site, value) return IntegerConstant(site, truncate_int_bits(value, signed), - TInt(64, signed)) + tp.Int(64, signed)) def mkIntegerLiteral(site, value): '''Convenience for a nonnegative integer constant with natural sign''' @@ -3470,26 +3473,26 @@ def read(self): def _detect_ctype(value): if value < 0: if value >= -128: - return TInt(8, True) + return tp.Int(8, True) elif value >= -(2**15): - return TInt(16, True) + return tp.Int(16, True) elif value >= -(2**31): - return TInt(32, True) + return tp.Int(32, True) elif value >= -(2**63): - return TInt(64, True) + return tp.Int(64, True) else: if value < 2: - return TInt(1, False) + return tp.Int(1, False) if value < 256: - return TInt(8, False) + return tp.Int(8, False) elif value < (2**16): - return TInt(16, False) + return tp.Int(16, False) elif value < (2**32): - return TInt(32, False) + return tp.Int(32, False) elif value < (2**64): - return TInt(64, False) + return tp.Int(64, False) elif value < (2**128): - return TInt(128, False) + return tp.Int(128, False) return None def all_index_exprs(node): @@ -3498,7 +3501,7 @@ def all_index_exprs(node): for dimsize in node.dimsizes)) class FloatConstant(Constant): - type = TFloat('double') + type = tp.Float('double') def __init__(self, site, value): assert_type(site, value, float) Constant.__init__(self, site, value) @@ -3521,8 +3524,8 @@ class AddressOfMethod(Constant): def ctype(self): types = [t for (_, t, _) in self.value.cparams] if not self.value.independent: - types[0] = TPtr(TNamed("conf_object_t")) - return TPtr(TFunction(types, self.value.rettype)) + types[0] = tp.Ptr(tp.Named("conf_object_t")) + return tp.Ptr(tp.Function(types, self.value.rettype)) def read(self): prefix = '_trampoline' * (not self.value.independent) @@ -3541,7 +3544,7 @@ def string_escape(s): return char_escape_re.sub(char_escape, s).decode('utf-8') class StringConstant(Constant): - type = TPtr(TNamed('char', const=True)) + type = tp.Ptr(tp.Named('char', const=True)) def __init__(self, site, value): # Store the value in UTF-8 (to permit both unicode and byte strings) if isinstance(value, str): @@ -3561,7 +3564,7 @@ def unicode_value(self): mkStringConstant = StringConstant class BoolConstant(Constant): - type = TBool() + type = tp.Bool() def __str__(self): if self.value: return 'true' @@ -3582,7 +3585,7 @@ class Undefined(NonValue): def __str__(self): return 'undefined' def exc(self): - return EUNDEF(self) + return E.UNDEF(self) mkUndefined = Undefined @@ -3598,7 +3601,7 @@ def __str__(self): return '_' def exc(self): - return EDISCARDREF(self.site) + return E.DISCARDREF(self.site) def write(self, source): if self.explicit_type: @@ -3658,7 +3661,7 @@ def __str__(self): return "%s.%s" % (self.node.logname(self.indices), self.trait.name) def ctype(self): - return TTrait(self.trait) + return tp.Trait(self.trait) def read(self): self.node.traits.mark_referenced(self.trait) @@ -3671,14 +3674,14 @@ def read(self): indices_decl = ('uint32 __indices[] = {%s}' % (', '.join(i.read() for i in self.indices))) indices = tuple(mkLit(self.site, '__indices[%d]' % (i,), - TInt(32, False)) + tp.Int(32, False)) for i in range(self.node.dimensions)) structref = self.node.traits.vtable_cname(self.ancestry_path[0]) pointer = '(&%s)' % ('.'.join([structref] + [ - cident(t.name) for t in self.ancestry_path[1:]])) + tp.cident(t.name) for t in self.ancestry_path[1:]])) id = ObjIdentity(self.site, self.node, indices).read() traitref_expr = ('((%s) {%s, %s})' - % (cident(self.trait.name), pointer, id)) + % (tp.cident(self.trait.name), pointer, id)) if indices_decl: return '({%s; %s;})' % (indices_decl, traitref_expr) else: @@ -3707,7 +3710,7 @@ def __str__(self): return "%s" % (self.node.logname(self.indices),) def ctype(self): - return TNamed('_identity_t') + return tp.Named('_identity_t') def read(self): if self.constant: @@ -3734,7 +3737,7 @@ def __str__(self): return "%s" % (self.traitref,) def ctype(self): - return TNamed('_identity_t') + return tp.Named('_identity_t') def read(self): return "(%s).id" % (self.traitref.read(),) @@ -3746,7 +3749,7 @@ def __init__(self, site, identity): crep.require_dev(site) def ctype(self): - return TNamed('conf_object_t *') + return tp.Named('conf_object_t *') def read(self): return ('_identity_to_portobj(_port_object_assocs, &_dev->obj, ' @@ -3760,18 +3763,18 @@ def __str__(self): return "cast(%s, %s)" % (self.sub, self.parent.name) def ctype(self): - return TTrait(self.parent) + return tp.Trait(self.parent) def read(self): - typ = safe_realtype(self.sub.ctype()) - assert isinstance(typ, TTrait) + typ = tp.safe_realtype(self.sub.ctype()) + assert isinstance(typ, tp.Trait) if self.parent not in typ.trait.ancestors: raise ICE(self.site, 'cannot upcast %s to %s' % (typ.trait.name, self.parent.name)) return ("UPCAST(%s, %s, %s)" - % (self.sub.read(), cident(typ.trait.name), - ".".join(cident(t.name) for t in + % (self.sub.read(), tp.cident(typ.trait.name), + ".".join(tp.cident(t.name) for t in typ.trait.ancestry_paths[self.parent][0]))) class TraitObjectCast(Expression): @@ -3782,7 +3785,7 @@ def __str__(self): return f'cast({self.sub}, object)' def ctype(self): - return TTrait(dml.globals.object_trait) + return tp.Trait(dml.globals.object_trait) def read(self): return (f'({{_identity_t __id = ({self.sub.read()}).id; ' @@ -3791,21 +3794,21 @@ def read(self): def mkTraitUpcast(site, sub, parent): if isinstance(sub, NonValue): raise sub.exc() - typ = safe_realtype(sub.ctype()) + typ = tp.safe_realtype(sub.ctype()) assert dml.globals.object_trait - if isinstance(typ, TTrait): + if isinstance(typ, tp.Trait): if typ.trait is parent: return sub elif parent in typ.trait.ancestors: return TraitUpcast(site, sub, parent) elif parent is dml.globals.object_trait: return TraitObjectCast(site, sub) - raise ETEMPLATEUPCAST(site, typ, parent.type()) + raise E.TEMPLATEUPCAST(site, typ, parent.type()) def vtable_read(expr): - typ = realtype(expr.ctype()) - assert isinstance(typ, TTrait) - return '((struct _%s *) (%s).trait)' % (cident(typ.trait.name), + typ = tp.realtype(expr.ctype()) + assert isinstance(typ, tp.Trait) + return '((struct _%s *) (%s).trait)' % (tp.cident(typ.trait.name), expr.read()) class TraitParameter(Expression): @@ -3817,10 +3820,10 @@ def __str__(self): return "%s.%s" % (self.traitref, self.name) def read(self): - t = realtype(self.traitref.ctype()) - assert isinstance(t, TTrait) - vtable_type = f'struct _{cident(t.trait.name)}' - if isinstance(realtype(self.type), TTraitList): + t = tp.realtype(self.traitref.ctype()) + assert isinstance(t, tp.Trait) + vtable_type = f'struct _{tp.cident(t.trait.name)}' + if isinstance(tp.realtype(self.type), tp.TraitList): return (f'_vtable_sequence_param({self.traitref.read()},' f' offsetof({vtable_type}, {self.name}))') else: @@ -3842,12 +3845,12 @@ def __str__(self): return "&%s.%s" % (self.traitref, self.name) def ctype(self): - return TPtr(self.type_) + return tp.Ptr(self.type_) def read(self): - t = realtype(self.traitref.ctype()) - assert isinstance(t, TTrait) - vtable_type = f'struct _{cident(t.trait.name)}' + t = tp.realtype(self.traitref.ctype()) + assert isinstance(t, tp.Trait) + vtable_type = f'struct _{tp.cident(t.trait.name)}' return (f'VTABLE_SESSION(_dev, {self.traitref.read()}, {vtable_type}' f', {self.name}, {self.ctype().declaration("")})') @@ -3877,15 +3880,15 @@ def independent(self): pass def apply(self, inits, location, scope): '''Return expression for application as a function''' if self.throws or len(self.outp) > 1: - raise EAPPLYMETH(self.site, self) + raise E.APPLYMETH(self.site, self) if crep.TypedParamContext.active and self.independent: - raise ETYPEDPARAMVIOL(self.site) + raise E.TYPEDPARAMVIOL(self.site) args = typecheck_inarg_inits(self.site, inits, self.inp, location, scope, 'method') if self.outp: [(_, rettype)] = self.outp else: - rettype = TVoid() + rettype = tp.Void() return self.call_expr(args, rettype) class TraitMethodDirect(TraitMethodRef): @@ -3899,7 +3902,7 @@ def __init__(self, site, traitref, methodref): pass def __str__(self): return "%s.templates.%s.%s" % ( - self.traitref, str(realtype(self.traitref.ctype()).trait.name), + self.traitref, str(tp.realtype(self.traitref.ctype()).trait.name), self.methodref.name) @property @@ -3970,9 +3973,9 @@ def ctype(self): return self.hooktyp def read(self): - t = realtype(self.traitref.ctype()) - assert isinstance(t, TTrait) - vtable_type = f'struct _{cident(t.trait.name)}' + t = tp.realtype(self.traitref.ctype()) + assert isinstance(t, tp.Trait) + vtable_type = f'struct _{tp.cident(t.trait.name)}' coeff = math.prod(self.dimsizes) if all(idx.constant for idx in self.indices): @@ -4051,7 +4054,7 @@ def __init__(self, site, node, indices): def __str__(self): name = self.node.logname(self.indices) if name: - return dollar(self.site)+name + return logging.dollar(self.site)+name else: assert dml.globals.dml_version == (1, 2) return '$' % self.node.objtype @@ -4061,10 +4064,10 @@ def apply(self, inits, location, scope): '''Apply as an expression''' if self.node.objtype == 'method': if self.node.throws or len(self.node.outp) > 1: - raise EAPPLYMETH(self.site, self.node.name) + raise E.APPLYMETH(self.site, self.node.name) return codegen_call_expr(self.site, self.node, self.indices, inits, location, scope) - raise EAPPLY(self, self.node.objtype + " object") + raise E.APPLY(self, self.node.objtype + " object") class NodeRefWithStorage(NodeRef, LValue): '''Reference to node that also contains storage, such as allocated @@ -4088,7 +4091,7 @@ def read(self): # some DML-generated expressions, like 'parent', use # object's site and self.site is not self.node.site): - report(PVAL(dmlparse.end_site(self.site))) + report(P.VAL(dmlparse.end_site(self.site))) node = self.node if node.objtype == 'method': @@ -4108,9 +4111,9 @@ def read(self): def apply(self, inits, location, scope): if self.node.objtype == 'method': assert dml.globals.dml_version == (1, 2) - raise EAPPLYMETH(self.site, self.node.name) + raise E.APPLYMETH(self.site, self.node.name) # storage might be a function pointer - return mkApplyInits(self.site, self, inits, location, scope) + return expr.mkApplyInits(self.site, self, inits, location, scope) class SessionVariableRef(LValue): "A reference to a session variable" @@ -4140,7 +4143,7 @@ def __init__(self, site, hook, indices): assert isinstance(hook, objects.DMLObject) assert isinstance(indices, tuple) assert hook.objtype == 'hook' - self.type = THook(hook.msg_types, validated=True) + self.type = tp.Hook(hook.msg_types, validated=True) if all(idx.constant for idx in indices): self.constant = True @@ -4172,17 +4175,17 @@ class NoallocNodeRef(PlainNodeRef): @auto_init def __init__(self, site, node, indices, node_type): pass def exc(self): - return ENALLOC(self.site, self.node) + return E.NALLOC(self.site, self.node) class RegisterWithFields(PlainNodeRef): @auto_init def __init__(self, site, node, indices, node_type): pass def exc(self): - return EREGVAL(self.site, self.node) + return E.REGVAL(self.site, self.node) # This one can happen in both 1.2 and 1.4, for data members. class IncompleteNodeRefWithStorage(PlainNodeRef): - '''NodeRefWithStorage where not all indices are defined''' + '''NodeRefWithStorage where not all indices are expr_util.defined''' @auto_init def __init__(self, site, node, indices, node_type, static_index): assert isinstance(static_index, NonValue) @@ -4276,15 +4279,15 @@ def local_dimsizes(self): def __str__(self): name = self.node.logname(self.indices) - return dollar(self.site) + name + return logging.dollar(self.site) + name def exc(self): - return EARRAY(self.site, self.node.identity()) + return E.ARRAY(self.site, self.node.identity()) class HookSuspended(Expression): '''Reference to the suspended member of a hook''' priority = 160 - type = TInt(64, False) + type = tp.Int(64, False) @auto_init def __init__(self, site, hookref_expr): pass @@ -4306,7 +4309,7 @@ def __init__(self, site, hookref_expr): pass def __str__(self): return "%s.send_now" % (self.hookref_expr,) def apply(self, inits, location, scope): - msg_types = safe_realtype_shallow(self.hookref_expr.ctype()).msg_types + msg_types = tp.safe_realtype_shallow(self.hookref_expr.ctype()).msg_types args = typecheck_inarg_inits( self.site, inits, [(f'comp{i}', t) @@ -4319,12 +4322,12 @@ def apply(self, inits, location, scope): class HookSendNowApply(Expression): '''Application of the send_now pseudomethod with valid arguments''' slots = ('msg_struct',) - type = TInt(64, False) + type = tp.Int(64, False) priority = dml.expr.Apply.priority @auto_init def __init__(self, site, hookref_expr, args): crep.require_dev(site) - msg_types = safe_realtype(hookref_expr.ctype()).msg_types + msg_types = tp.safe_realtype(hookref_expr.ctype()).msg_types from .codegen import get_type_sequence_info self.msg_struct = get_type_sequence_info(msg_types, create_new=True).struct @@ -4352,13 +4355,13 @@ def __init__(self, site, hookref_expr): pass def __str__(self): return "%s.send" % (self.hookref_expr,) def apply(self, inits, location, scope): - msg_types = safe_realtype_shallow(self.hookref_expr.ctype()).msg_types + msg_types = tp.safe_realtype_shallow(self.hookref_expr.ctype()).msg_types args = typecheck_inarg_inits( self.site, inits, [(f'comp{i}', t) for (i, t) in enumerate(msg_types)], location, scope, 'send', - on_ptr_to_stack=(lambda x: report(WHOOKSEND(x.site, x)))) + on_ptr_to_stack=(lambda x: report(W.HOOKSEND(x.site, x)))) from .codegen import get_type_sequence_info, get_immediate_after typeseq_info = get_type_sequence_info(msg_types, create_new=True) after_info = get_immediate_after(typeseq_info) @@ -4368,7 +4371,7 @@ def apply(self, inits, location, scope): class HookSendApply(Expression): '''Application of the send pseudomethod with valid arguments''' - type = void + type = tp.void priority = dml.expr.Apply.priority @auto_init def __init__(self, site, hookref_expr, args, info): @@ -4385,7 +4388,7 @@ def read(self): ', '.join(arg.read() for arg in self.args))) else: args = ('(%s){%s}' - % (TArray(self.info.args_type, + % (tp.Array(self.info.args_type, mkIntegerLiteral(self.site, 1)).declaration(''), self.hookref_expr.read())) args_size = f'sizeof({self.info.args_type.declaration("")})' @@ -4419,9 +4422,9 @@ def __str__(self): def mkTemplatesSubRef(site, templates_ref, template_name): tmpl = dml.globals.templates.get(template_name) if tmpl is None: - raise ENTMPL(site, template_name) + raise E.NTMPL(site, template_name) if tmpl not in templates_ref.node.templates: - raise ETQMIC(site, templates_ref.node.identity(), template_name) + raise E.TQMIC(site, templates_ref.node.identity(), template_name) return TemplatesSubRef(site, templates_ref, template_name) def mkTemplateQualifiedMethodRef(site, templates_subref, method_name): @@ -4485,11 +4488,11 @@ def mkTemplateQualifiedMethodRef(site, templates_subref, method_name): abstract = (trait is not None and trait.member_declaration(method_name) is not None and trait.member_kind(method_name) == 'method') - raise EMEMBERTQMIC(site, template, method_name, abstract, + raise E.MEMBERTQMIC(site, template, method_name, abstract, node if some_spec_eliminated else None) if len(candidates) > 1: - raise EAMBTQMIC(site, template_name, method_name, some_spec_eliminated, + raise E.AMBTQMIC(site, template_name, method_name, some_spec_eliminated, candidates) (tmpl, method) = candidates[0] @@ -4529,10 +4532,10 @@ def __str__(self): def mkTraitTemplatesSubRef(site, templates_ref, template_name): trait = dml.globals.traits.get(template_name) if trait is None: - raise ENTMPL(site, template_name) + raise E.NTMPL(site, template_name) if not (templates_ref.trait.implements(trait) or trait is dml.globals.object_trait): - raise ETTQMIC(site, trait.name, templates_ref.trait.name) + raise E.TTQMIC(site, trait.name, templates_ref.trait.name) return TraitTemplatesSubRef(site, templates_ref, trait) @@ -4547,11 +4550,11 @@ def mkTraitTemplateQualifiedMethodRef(site, templates_subref, method_name): impl_traits = trait.method_impl_traits.get(method_name) if not impl_traits: if impl_tmpls: - raise ENSHAREDTQMIC(site, trait, method_name) + raise E.NSHAREDTQMIC(site, trait, method_name) else: abstract = (trait.member_declaration(method_name) is not None and trait.member_kind(method_name) == 'method') - raise EMEMBERTQMIC(site, trait, method_name, abstract, None) + raise E.MEMBERTQMIC(site, trait, method_name, abstract, None) # If there is any non-shared method specification not lower in rank than # some shared method implementation, then it could be a potential @@ -4560,10 +4563,10 @@ def mkTraitTemplateQualifiedMethodRef(site, templates_subref, method_name): if all(impl_tmpl.spec.rank not in dml.globals.templates[impl_trait.name].spec.rank.inferior for impl_trait in impl_traits): - raise ENSHAREDTQMIC(site, trait, method_name) + raise E.NSHAREDTQMIC(site, trait, method_name) if len(impl_traits) > 1: - raise EAMBTQMIC(site, trait.name, method_name, False, + raise E.AMBTQMIC(site, trait.name, method_name, False, [(impl_trait, impl_trait.method_impls[method_name]) for impl_trait in impl_traits]) @@ -4612,7 +4615,7 @@ def is_stack_allocated(self): @property def is_pointer_to_stack_allocation(self): - return isinstance(safe_realtype_shallow(self.ctype()), TArray) + return isinstance(tp.safe_realtype_shallow(self.ctype()), tp.Array) mkLocalVariable = LocalVariable @@ -4667,7 +4670,7 @@ def is_stack_allocated(self): @property def is_pointer_to_stack_allocation(self): - return (isinstance(safe_realtype_shallow(self.type), TArray) + return (isinstance(tp.safe_realtype_shallow(self.type), tp.Array) and self.is_stack_allocated) def try_resolve_len(site, lh): @@ -4693,10 +4696,10 @@ def mkSubRef(site, expr, sub, op): (node, indices) = expr.get_ref() if node.objtype == 'interface': if op == "->": - raise ENOPTR(site, expr) + raise E.NOPTR(site, expr) return mkInterfaceMethodRef(site, node, indices, sub) else: - raise EREF(site, sub, expr) + raise E.REF(site, sub, expr) if isinstance(expr, NonValue): if op == '.': @@ -4724,55 +4727,55 @@ def mkSubRef(site, expr, sub, op): op = '->' etype = expr.ctype() - real_etype = safe_realtype_shallow(etype) + real_etype = tp.safe_realtype_shallow(etype) - if isinstance(real_etype, TPtr): + if isinstance(real_etype, tp.Ptr): if op == '.': - raise ENOSTRUCT(site, expr) + raise E.NOSTRUCT(site, expr) basetype = real_etype.base - real_basetype = safe_realtype(basetype) + real_basetype = tp.safe_realtype(basetype) baseexpr = mkDereference(site, expr) else: if op == '->': - raise ENOPTR(site, expr) + raise E.NOPTR(site, expr) basetype = etype - real_basetype = safe_realtype(etype) + real_basetype = tp.safe_realtype(etype) baseexpr = expr real_basetype = real_basetype.resolve() - if isinstance(real_basetype, StructType): + if isinstance(real_basetype, tp.StructType): typ = real_basetype.get_member_qualified(sub) if not typ: - raise EMEMBER(site, baseexpr, sub) + raise E.MEMBER(site, baseexpr, sub) return StructMember(site, expr, sub, typ, op) elif real_basetype.is_int and real_basetype.is_bitfields: member = real_basetype.members.get(sub) if member is None: - raise EMEMBER(site, expr, sub) + raise E.MEMBER(site, expr, sub) (_, msb, lsb) = member return mkBitSlice(site, baseexpr, mkIntegerLiteral(site, msb), mkIntegerLiteral(site, lsb), 'le') - elif isinstance(real_basetype, TTrait): + elif isinstance(real_basetype, tp.Trait): m = real_basetype.trait.lookup(sub, baseexpr, site) if not m: - raise EMEMBER(site, expr, sub) + raise E.MEMBER(site, expr, sub) return m - elif isinstance(real_basetype, TArray) and sub == 'len': + elif isinstance(real_basetype, tp.Array) and sub == 'len': if real_basetype.size.constant: return mkIntegerConstant(site, real_basetype.size.value, False) else: - raise EVLALEN(site) - elif isinstance(real_basetype, TTraitList) and sub == 'len': + raise E.VLALEN(site) + elif isinstance(real_basetype, tp.TraitList) and sub == 'len': try: trait = dml.globals.traits[real_basetype.traitname] except KeyError: - raise ETYPE(basetype.declaration_site or site, basetype) + raise E.TYPE(basetype.declaration_site or site, basetype) return mkSequenceLength(site, baseexpr, trait) - elif isinstance(real_basetype, THook): + elif isinstance(real_basetype, tp.Hook): real_basetype.validate(basetype.declaration_site or site) if sub == 'send': return mkHookSendRef(site, baseexpr) @@ -4781,7 +4784,7 @@ def mkSubRef(site, expr, sub, op): elif sub == 'suspended': return mkHookSuspended(site, baseexpr) - raise ENOSTRUCT(site, expr) + raise E.NOSTRUCT(site, expr) class ArrayRef(LValue): slots = ('type',) @@ -4789,9 +4792,9 @@ class ArrayRef(LValue): explicit_type = True @auto_init def __init__(self, site, expr, idx): - expr_type = realtype_shallow(expr.ctype()) - self.type = conv_const(expr_type.const - and isinstance(expr_type, TArray), + expr_type = tp.realtype_shallow(expr.ctype()) + self.type = tp.conv_const(expr_type.const + and isinstance(expr_type, tp.Array), expr_type.base) def __str__(self): return '%s[%s]' % (self.expr, self.idx) @@ -4807,7 +4810,7 @@ def is_stack_allocated(self): @property def is_pointer_to_stack_allocation(self): - return (isinstance(safe_realtype_shallow(self.type), TArray) + return (isinstance(tp.safe_realtype_shallow(self.type), tp.Array) and self.is_stack_allocated) class VectorRef(Expression): @@ -4815,7 +4818,7 @@ class VectorRef(Expression): @auto_init def __init__(self, site, expr, idx): assert not expr.writable or expr.c_lval - self.type = realtype(self.expr.ctype()).base + self.type = tp.realtype(self.expr.ctype()).base def __str__(self): return f'{self.expr}[{self.idx}]' def read(self): @@ -4848,7 +4851,7 @@ def mkIndex(site, expr, idx): if idx.constant: if (idx.value < 0 or idx.value >= expr.local_dimsizes[len(local_indices)]): - raise EOOB(idx) + raise E.OOB(idx) if len(expr.local_dimsizes) > len(local_indices) + 1: if isinstance(expr, NodeArrayRef): return NodeArrayRef(site, expr.node, expr.indices + (idx,)) @@ -4867,26 +4870,26 @@ def mkIndex(site, expr, idx): if isinstance(expr, AbstractList): if idx.constant: if idx.value < 0 or idx.value >= len(expr.value): - raise EOOB(expr) + raise E.OOB(expr) assert isinstance(expr.value[idx.value], Expression) return expr.value[idx.value] - raise EAVAR(idx.site) + raise E.AVAR(idx.site) raise expr.exc() - typ = safe_realtype(expr.ctype()) + typ = tp.safe_realtype(expr.ctype()) if typ.is_int: return mkBitSlice(site, expr, idx, None, None) - if isinstance(typ, (TArray, TPtr)): + if isinstance(typ, (tp.Array, tp.Ptr)): return ArrayRef(site, expr, idx) - if isinstance(typ, (TVector)): + if isinstance(typ, (tp.Vector)): return VectorRef(site, expr, idx) - raise ENARRAY(expr) + raise E.NARRAY(expr) class Cast(Expression): "A C type cast" @@ -4904,17 +4907,17 @@ def read(self): @property def is_pointer_to_stack_allocation(self): - return (isinstance(safe_realtype_shallow(self.type), TPtr) + return (isinstance(tp.safe_realtype_shallow(self.type), tp.Ptr) and self.expr.is_pointer_to_stack_allocation) def mkCast(site, expr, new_type): - real = safe_realtype(new_type) - if isinstance(real, TTrait): + real = tp.safe_realtype(new_type) + if isinstance(real, tp.Trait): if isinstance(expr, NodeRef): (node, indices) = expr.get_ref() if real.trait in node.traits.ancestors: return ObjTraitRef(site, node, real.trait, indices) - raise ETEMPLATEUPCAST(site, "object", new_type) + raise E.TEMPLATEUPCAST(site, "object", new_type) else: return mkTraitUpcast(site, expr, real.trait) @@ -4926,15 +4929,15 @@ def mkCast(site, expr, new_type): if isinstance(expr, NonValue): raise expr.exc() - old_type = safe_realtype(expr.ctype()) + old_type = tp.safe_realtype(expr.ctype()) if (dml.globals.compat_dml12_int(site) - and (isinstance(old_type, (TStruct, TVector)) - or isinstance(real, (TStruct, TVector)))): + and (isinstance(old_type, (tp.Struct, tp.Vector)) + or isinstance(real, (tp.Struct, tp.Vector)))): # these casts are permitted by C only if old and new are # the same type, which is useless return Cast(site, expr, new_type) - if isinstance(real, (TVoid, TArray, TFunction)): - raise ECAST(site, expr, new_type) + if isinstance(real, (tp.Void, tp.Array, tp.Function)): + raise E.CAST(site, expr, new_type) if old_type.eq(real): if (dml.globals.compat_dml12_int(expr.site) and old_type.is_int @@ -4949,13 +4952,13 @@ def mkCast(site, expr, new_type): real) return Cast(site, expr, new_type) return mkRValue(expr) - if isinstance(real, (TStruct, TExternStruct, TVector, TTraitList)): - raise ECAST(site, expr, new_type) - if isinstance(old_type, (TVoid, TStruct, TVector, TTraitList, TTrait)): - raise ECAST(site, expr, new_type) + if isinstance(real, (tp.Struct, tp.ExternStruct, tp.Vector, tp.TraitList)): + raise E.CAST(site, expr, new_type) + if isinstance(old_type, (tp.Void, tp.Struct, tp.Vector, tp.TraitList, tp.Trait)): + raise E.CAST(site, expr, new_type) if old_type.is_int and old_type.is_endian: expr = as_int(expr) - old_type = safe_realtype(expr.ctype()) + old_type = tp.safe_realtype(expr.ctype()) if real.is_int and not real.is_endian: if old_type.is_int and expr.constant: value = truncate_int_bits(expr.value, real.signed, real.bits) @@ -4968,23 +4971,23 @@ def mkCast(site, expr, new_type): # Shorten redundant chains of integer casts. Avoids insane C # output for expressions like a+b+c+d. if (isinstance(expr, Cast) - and isinstance(old_type, TInt) + and isinstance(old_type, tp.Int) and old_type.bits >= real.bits): # (uint64)(int64)x -> (uint64)x expr = expr.expr - old_type = safe_realtype(expr.ctype()) - if isinstance(old_type, (TFloat, TBool, TUnknown)): - old_type = TInt(64, True) + old_type = tp.safe_realtype(expr.ctype()) + if isinstance(old_type, (tp.Float, tp.Bool, tp.Unknown)): + old_type = tp.Int(64, True) expr = Cast(site, expr, old_type) - elif isinstance(old_type, (TPtr, TArray, TFunction)): - old_type = TInt(64, False) + elif isinstance(old_type, (tp.Ptr, tp.Array, tp.Function)): + old_type = tp.Int(64, False) expr = Cast(site, expr, old_type) elif not old_type.is_int: - raise ECAST(site, expr, new_type) + raise E.CAST(site, expr, new_type) if not dml.globals.compat_dml12_int(site): # (uint64)x -> x if x is already uint64 - if (isinstance(old_type, TInt) - and isinstance(real, TInt) + if (isinstance(old_type, tp.Int) + and isinstance(real, tp.Int) and old_type.bits == real.bits and old_type.signed == real.signed): return expr @@ -5004,44 +5007,44 @@ def mkCast(site, expr, new_type): expr = Cast(site, expr, new_type) return expr elif real.is_int and real.is_endian: - old_type = safe_realtype(expr.ctype()) - if old_type.is_arith or isinstance(old_type, TPtr): + old_type = tp.safe_realtype(expr.ctype()) + if old_type.is_arith or isinstance(old_type, tp.Ptr): return mkApply( expr.site, mkLit(expr.site, *real.get_store_fun()), - (mkCast(expr.site, expr, TInt(64, False)),)) + (mkCast(expr.site, expr, tp.Int(64, False)),)) else: - raise ECAST(site, expr, new_type) - if ((real.is_arith or isinstance(real, TBool)) - and (old_type.is_arith or isinstance(old_type, TBool))): + raise E.CAST(site, expr, new_type) + if ((real.is_arith or isinstance(real, tp.Bool)) + and (old_type.is_arith or isinstance(old_type, tp.Bool))): assert (not (real.is_int and real.is_endian) and not (old_type.is_int and old_type.is_endian)) return Cast(site, expr, new_type) - if ((isinstance(real, (TBool, TPtr)) or real.is_int) - and (isinstance(old_type, (TBool, TPtr, TArray, TFunction)) + if ((isinstance(real, (tp.Bool, tp.Ptr)) or real.is_int) + and (isinstance(old_type, (tp.Bool, tp.Ptr, tp.Array, tp.Function)) or old_type.is_int)): assert (not (real.is_int and real.is_endian) and not (old_type.is_int and old_type.is_endian)) - if isinstance(old_type, (TPtr, TArray)) and isinstance(real, TPtr): + if isinstance(old_type, (tp.Ptr, tp.Array)) and isinstance(real, tp.Ptr): old_base = old_type.base new_base = real.base old_base_deep = old_base - while isinstance(old_base_deep, TArray): + while isinstance(old_base_deep, tp.Array): old_base_deep = old_base_deep.base if (not dml.globals.compat_dml12_int(site) - and isinstance(old_base_deep, (TLayout, TEndianInt)) + and isinstance(old_base_deep, (tp.Layout, tp.EndianInt)) and new_base.is_int and not new_base.is_endian and not new_base.bits == 8 and not (old_base_deep.is_int and old_base_deep.bits == 8)): byte_order = (old_base_deep.byte_order if old_base_deep.is_int else old_base_deep.endian) - likely_intended = TEndianInt(new_base.bits, + likely_intended = tp.EndianInt(new_base.bits, new_base.signed, byte_order, const=new_base.const) - report(WPCAST(site, old_base, new_base, likely_intended)) + report(W.PCAST(site, old_base, new_base, likely_intended)) return Cast(site, expr, new_type) @@ -5049,15 +5052,15 @@ def mkCast(site, expr, new_type): # for compatibility reasons if (dml.globals.dml_version == (1, 2) and isinstance(expr, NodeRef) and expr.get_ref()[0].objtype == 'method' - and isinstance(real, TPtr) and isinstance(real.base, TFunction)): + and isinstance(real, tp.Ptr) and isinstance(real.base, tp.Function)): return Cast(site, expr, new_type) # Allow casts from dev to pointer types in DML 1.2 for compatibility # reasons if (dml.globals.dml_version == (1, 2) and isinstance(expr, NodeRef) - and expr.get_ref()[0].objtype == 'device' and isinstance(real, TPtr)): + and expr.get_ref()[0].objtype == 'device' and isinstance(real, tp.Ptr)): return Cast(site, expr, new_type) - raise ECAST(site, expr, new_type) + raise E.CAST(site, expr, new_type) class RValue(Expression): '''Wraps an lvalue to prohibit write. Useful when a composite @@ -5110,14 +5113,14 @@ def value(self): return self.expr.value def mkInlinedParam(site, expr, name, type): - if not defined(expr): + if not expr_util.defined(expr): raise ICE(site, 'undefined parameter') if isinstance(expr, InlinedParam): expr = expr.expr if isinstance(expr, IntegerConstant): value = expr.value - type = realtype(type) - etype = realtype(expr.ctype()) + type = tp.realtype(type) + etype = tp.realtype(expr.ctype()) # Checking type.canstore(etype) isn't good enough here if not type.signed and value < 0: value += (1 << etype.bits) @@ -5129,17 +5132,17 @@ def mkInlinedParam(site, expr, name, type): return InlinedParam(site, expr, name) class QName(Expression): - type = TPtr(TNamed('char', const = True)) + type = tp.Ptr(tp.Named('char', const = True)) @auto_init def __init__(self, site, node, relative, indices): if self.indices and not all(x.constant for x in self.indices): crep.require_dev(site) def __str__(self): - return dollar(self.site) + '%s.qname' % (self.node) + return logging.dollar(self.site) + '%s.qname' % (self.node) def read(self): if (dml.globals.dml_version == (1, 2) and self.node.logname() != self.node.logname_anonymized()): - report(WCONFIDENTIAL(self.site)) + report(W.CONFIDENTIAL(self.site)) if self.indices and not all(x.constant for x in self.indices): idx_args = [", (int)" + idx.read() for idx in self.indices] @@ -5160,7 +5163,7 @@ def fmt(self): def get_anonymized_name(obj): if obj.objtype == 'register': - offset = param_expr(obj, 'offset', + offset = expr_util.param_expr(obj, 'offset', (mkIntegerLiteral(obj.site, 0),) * obj.dimensions) if undefined(offset): # acquire a unique name, based on this banks unmapped registers @@ -5173,7 +5176,7 @@ def get_anonymized_name(obj): else: assert(obj.objtype == 'field') [msb, lsb] = [ - param_int( + expr_util.param_int( obj, name, indices=(mkIntegerLiteral(obj.site, 0),) * obj.dimensions) for name in ['msb', 'lsb']] @@ -5182,14 +5185,14 @@ def get_anonymized_name(obj): class HiddenName(StringConstant): "Name of the object that will be anonymized in log statements" slots = ('node',) - type = TPtr(TNamed('char', const=True)) + type = tp.Ptr(tp.Named('char', const=True)) @auto_init def __init__(self, site, value, node): assert(node.objtype in {'register', 'field'}) def __str__(self): - return dollar(self.site) + '%s.name' % (self.node,) + return logging.dollar(self.site) + '%s.name' % (self.node,) def read(self): - report(WCONFIDENTIAL(self.site)) + report(W.CONFIDENTIAL(self.site)) return self.quoted def fmt(self): return (get_anonymized_name(self.node), ()) @@ -5198,12 +5201,12 @@ def fmt(self): class HiddenQName(Expression): "QName of the object that will be anonymised in log statements" - type = TPtr(TNamed('char', const = True)) + type = tp.Ptr(tp.Named('char', const = True)) @auto_init def __init__(self, site, node, indices): assert(node.objtype in {'register', 'field'}) def __str__(self): - return dollar(self.site) + '%s.qname' % (self.node) + return logging.dollar(self.site) + '%s.qname' % (self.node) def read(self): return QName(self.site, self.node, 'device', self.indices).read() def fmt(self): @@ -5217,7 +5220,7 @@ def fmt(self): mkHiddenQName = HiddenQName class DeviceObject(Expression): - type = TPtr(TNamed('conf_object_t')) + type = tp.Ptr(tp.Named('conf_object_t')) @auto_init def __init__(self, site): crep.require_dev(site) @@ -5228,7 +5231,7 @@ def read(self): mkDeviceObject = DeviceObject class LogGroup(Expression): - type = TInt(64, False, const=True) + type = tp.Int(64, False, const=True) slots = ('name',) priority = 1000 @auto_init @@ -5275,19 +5278,19 @@ def assign_to(self, dest, typ): # be UB as long as the session variable hasn't been initialized # previously. site = self.expr.site - rt = safe_realtype_shallow(typ) + rt = tp.safe_realtype_shallow(typ) # There is a reasonable implementation for this case (memcpy), but it # never occurs today - assert not isinstance(rt, TArray) - if isinstance(rt, TEndianInt): + assert not isinstance(rt, tp.Array) + if isinstance(rt, tp.EndianInt): return (f'{rt.dmllib_fun("copy")}((void *)&{dest},' + f' {self.expr.read()})') - elif deep_const(typ): - shallow_deconst_typ = safe_realtype_unconst(typ) + elif tp.deep_const(typ): + shallow_deconst_typ = tp.safe_realtype_unconst(typ) # a const-qualified ExternStruct can be leveraged by the user as a # sign that there is some const-qualified member unknown to DMLC - if (isinstance(shallow_deconst_typ, TExternStruct) - or deep_const(shallow_deconst_typ)): + if (isinstance(shallow_deconst_typ, tp.ExternStruct) + or tp.deep_const(shallow_deconst_typ)): # Expression statement to delimit lifetime of compound literal # TODO it's possible to improve the efficiency of this by not # using a compound literal if self.expr is c_lval. @@ -5296,12 +5299,12 @@ def assign_to(self, dest, typ): # and it's unclear if that path could ever be taken. return ('({ memcpy((void *)&%s, (%s){%s}, sizeof(%s)); })' % (dest, - TArray(typ, + tp.Array(typ, mkIntegerLiteral(site, 1)).declaration(''), mkCast(site, self.expr, typ).read(), dest)) else: - return (f'*({TPtr(shallow_deconst_typ).declaration("")})' + return (f'*({tp.Ptr(shallow_deconst_typ).declaration("")})' + f'&{dest} = {self.expr.read()}') else: return f'{dest} = {self.expr.read()}' @@ -5332,7 +5335,7 @@ def assign_to(self, dest, typ): '''output C statements to assign an lvalue''' # (void *) cast to avoid GCC erroring if the target type is (partially) # const-qualified. See ExpressionInitializer.assign_to - if isinstance(typ, (TNamed, TArray, TStruct)): + if isinstance(typ, (tp.Named, tp.Array, tp.Struct)): # Expression statement to delimit lifetime of compound literal return ('({ memcpy((void *)&%s, &(%s)%s, sizeof(%s)); })' % (dest, typ.declaration(''), self.read(), dest)) @@ -5373,13 +5376,13 @@ def as_expr(self, typ): return CompoundLiteral(self.site, self, typ) def assign_to(self, dest, typ): '''output C statements to assign an lvalue''' - typ = safe_realtype(typ) - if isinstance(typ, StructType): + typ = tp.safe_realtype(typ) + if isinstance(typ, tp.StructType): # (void *) cast to avoid GCC erroring if the target type is # (partially) const-qualified. See ExpressionInitializer.assign_to return ('({ memcpy((void *)&%s, (%s){%s}, sizeof(%s)); })' % (dest, - TArray(typ, + tp.Array(typ, mkIntegerLiteral(self.site, 1)).declaration(''), self.read(), dest)) else: @@ -5415,9 +5418,9 @@ def as_expr(self, typ): return CompoundLiteral(self.site, self, typ) def assign_to(self, dest, typ): '''output C statements to assign an lvalue''' - assert isinstance(safe_realtype(typ), - (TExternStruct, TStruct, TArray, TEndianInt, TTrait, - THook)) + assert isinstance(tp.safe_realtype(typ), + (tp.ExternStruct, tp.Struct, tp.Array, tp.EndianInt, tp.Trait, + tp.Hook)) # (void *) cast to avoid GCC erroring if the target type is # (partially) const-qualified. See ExpressionInitializer.assign_to return f'memset((void *)&{dest}, 0, sizeof({typ.declaration("")}))' @@ -5474,11 +5477,11 @@ def toc(self): self.linemark() if (isinstance(self.init, MemsetInitializer) - and not deep_const(self.type)): + and not tp.deep_const(self.type)): # ducks a potential GCC warning, and also serves to # zero-initialize VLAs self.type.print_declaration(self.name, unused = self.unused) - site_linemark(self.init.site) + output.site_linemark(self.init.site) out(self.init.assign_to(self.name, self.type) + ';\n') else: self.type.print_declaration( @@ -5552,14 +5555,14 @@ def __init__(self, site, text, impl_header = None): def toc(self): path = self.site.filename() (ident, h_path) = dmldir_macro(path) - out('#define %s "%s"\n' % (ident, quote_filename(h_path))) + out('#define %s "%s"\n' % (ident, output.quote_filename(h_path))) if dml.globals.linemarks: linemark(self.site.lineno, path) out(self.text) if not output.current().bol: out('\n') if dml.globals.linemarks: - reset_line_directive() + output.reset_line_directive() out('#undef %s\n' % (ident,)) mkCText = CText @@ -5583,7 +5586,7 @@ def lookup_var(site, scope, name): def log_object(site, node, indices): return mkLit(site, crep.conf_object(site, node, indices), - TPtr(TNamed("conf_object_t"))) + tp.Ptr(tp.Named("conf_object_t"))) def log_statement(site, logobj, logtype, level, groups, fmt, *args): if logtype in {'warning', 'error', 'critical'}: @@ -5596,10 +5599,10 @@ def log_statement(site, logobj, logtype, level, groups, fmt, *args): if groups is None: groups = mkIntegerLiteral(site, 0) - inargtypes = (([TInt(32, True)] if lvl else []) - + [TPtr(TNamed("conf_object_t")), TInt(64, False), - TPtr(TInt(8, True, const=True))]) - fun = mkLit(site, logfunc, TFunction(inargtypes, TVoid(), varargs=True)) + inargtypes = (([tp.Int(32, True)] if lvl else []) + + [tp.Ptr(tp.Named("conf_object_t")), tp.Int(64, False), + tp.Ptr(tp.Int(8, True, const=True))]) + fun = mkLit(site, logfunc, tp.Function(inargtypes, tp.Void(), varargs=True)) x = Apply(site, fun, lvl + diff --git a/py/dml/ctree_test.py b/py/dml/ctree_test.py index a5b505cc6..421b4be67 100644 --- a/py/dml/ctree_test.py +++ b/py/dml/ctree_test.py @@ -10,9 +10,11 @@ import shlex from pathlib import Path -from dml import ctree, types, logging, messages, output, symtab, traits +from dml import ctree, types, logging, output, symtab, traits +from dml import errors as E from dml.ctree import string_escape, mkCompound, dmldir_macro from dml.env import is_windows +from dml.expr import mkNullConstant def apply(f): return f() @@ -87,8 +89,8 @@ class s(logging.SimpleSite): def __init__(self): logging.SimpleSite.__init__(self, 'nowhere') def dml_version(self): return (1, 4) - cond = ctree.mkLit(s, '', types.TBool()) - intval = ctree.mkLit(s, '', types.TInt(8, True)) + cond = ctree.mkLit(s, '', types.Bool()) + intval = ctree.mkLit(s, '', types.Int(8, True)) true_const = ctree.mkBoolConstant(s, True) false_const = ctree.mkBoolConstant(s, False) break_ = ctree.mkBreak(s) @@ -225,7 +227,7 @@ def float_const(val): def variable(name, t): return ctree.mkDereference(site, ctree.mkLit(site, '&' + name, - types.TPtr(t))) + types.Ptr(t))) def lit(t): return ctree.mkLit(site, '', t) @@ -240,7 +242,7 @@ def expect_int_type(self, type, signed, bits=64): self.assertEqual((type.bits, type.signed), (bits, signed)) def expect_double(self, type): - self.assertIsInstance(type, types.TFloat) + self.assertIsInstance(type, types.Float) self.assertEqual(type.name, 'double') def expect_assert_error(self, line): @@ -288,14 +290,14 @@ def tcmp(t1, t2): right = t2.eq(t1) self.assertEqual(left, right) return left - u = types.TLong(False) - s = types.TLong(True) - z = types.TSize(False) - sz = types.TSize(True) - u64t = types.TInt64_t(False) - s64t = types.TInt64_t(True) + u = types.Long(False) + s = types.Long(True) + z = types.Size(False) + sz = types.Size(True) + u64t = types.Int64_t(False) + s64t = types.Int64_t(True) int_types = [u, s, z, sz, u64t, s64t, - types.TInt(64, False), types.TInt(32, False)] + types.Int(64, False), types.Int(32, False)] # all alternative spellings of integer types are potentially # incompatible in C, and therefore defensively considered by DML as # incompatible @@ -368,16 +370,16 @@ def float_nan(self): return ['EXPECT(IS_DOUBLE(%s));' % (expr.read(),), 'EXPECT(isnan(%s));' % (expr.read(),)] - @subtest([(0xdeadbeef, types.TInt(16, False), 0xbeef, 2), - (0xaaaaaa, types.TInt(15, True), 0x2aaa, 2), - (0xaaaaaa, types.TInt(14, True), -0x2000 | 0xaaa, 2), + @subtest([(0xdeadbeef, types.Int(16, False), 0xbeef, 2), + (0xaaaaaa, types.Int(15, True), 0x2aaa, 2), + (0xaaaaaa, types.Int(14, True), -0x2000 | 0xaaa, 2), ]) def int_cast(self, value, new_type, trunc_val, new_size): const_expr = ctree.mkCast( site, ctree.mkIntegerConstant(site, value, True), new_type) var_expr = ctree.mkCast( - site, variable('x', types.TInt(64, True)), new_type) + site, variable('x', types.Int(64, True)), new_type) self.assertEqual(const_expr.value, trunc_val) self.expect_int_type(const_expr.ctype(), new_type.signed, new_type.bits) self.expect_int_type(var_expr.ctype(), new_type.signed, new_type.bits) @@ -389,12 +391,12 @@ def int_cast(self, value, new_type, trunc_val, new_size): @subtest() def int_cast_sequence(self): """Checks that sequences of casts are collapsed correctly""" - for cast_sequence in [(types.TInt(64, False), types.TInt(64, False)), - (types.TInt(32, False), types.TInt(32, False)), - (types.TInt(64, False), types.TInt(64, True)), - (types.TInt(64, True), types.TInt(64, False)), - (types.TInt(64, False), types.TInt(32, False))]: - base = variable('b', types.TInt(1, True)) + for cast_sequence in [(types.Int(64, False), types.Int(64, False)), + (types.Int(32, False), types.Int(32, False)), + (types.Int(64, False), types.Int(64, True)), + (types.Int(64, True), types.Int(64, False)), + (types.Int(64, False), types.Int(32, False))]: + base = variable('b', types.Int(1, True)) curr_expr = base for t in cast_sequence: curr_expr = ctree.mkCast(site, curr_expr, t) @@ -403,15 +405,15 @@ def int_cast_sequence(self): @subtest() def int_cast_sequence_bit_increase(self): - base = variable('b', types.TInt(1, True)) - cast1 = ctree.mkCast(site, base, types.TInt(32, True)) - cast2 = ctree.mkCast(site, cast1, types.TInt(64, False)) + base = variable('b', types.Int(1, True)) + cast1 = ctree.mkCast(site, base, types.Int(32, True)) + cast2 = ctree.mkCast(site, cast1, types.Int(64, False)) self.assertEqual(cast2.expr, cast1) - @subtest([(types.TFloat('double'), '1.2', types.TInt(32, False), '1'), - (types.TBool(), 'true', types.TInt(32, False), '1'), - (types.TFunction([], types.TVoid()), - 'printf', types.TInt(64, False), + @subtest([(types.Float('double'), '1.2', types.Int(32, False), '1'), + (types.Bool(), 'true', types.Int(32, False), '1'), + (types.Function([], types.Void()), + 'printf', types.Int(64, False), '(uintptr_t)printf')]) def cast_to_int(self, old_type, old_value, new_type, new_value): cast = ctree.mkCast(site, ctree.mkLit(site, old_value, old_type), @@ -420,7 +422,7 @@ def cast_to_int(self, old_type, old_value, new_type, new_value): return ['EXPECT(%s == %s);' % (cast.read(), new_value)] def unendianed_type(self, endian_type): - return types.TInt(endian_type.bits, endian_type.signed) + return types.Int(endian_type.bits, endian_type.signed) @subtest([(ctree.mkIntegerConstant(site, 5, True), 5), (ctree.mkIntegerConstant(site, -5, True), -5), @@ -429,9 +431,9 @@ def unendianed_type(self, endian_type): ctree.mkIntegerConstant(site, 5, False), ctree.mkIntegerConstant(site, 2, False), 'le'), 0xF), (ctree.mkCast(site, ctree.mkIntegerConstant(site, 5, True), - types.TEndianInt(32, True, 'big-endian')), 5), + types.EndianInt(32, True, 'big-endian')), 5), (ctree.mkCast(site, ctree.mkIntegerConstant(site, 5, True), - types.TEndianInt(8, False, 'little-endian')), 5), + types.EndianInt(8, False, 'little-endian')), 5), ]) def as_int(self, expr, value): """Test that as_int correctly converts various types to integers""" @@ -452,10 +454,10 @@ def as_int(self, expr, value): ctree.mkIntegerConstant(site, 5, False), ctree.mkIntegerConstant(site, 2, False), 'le')) for endiantype in ( - types.TEndianInt(8, False, 'little-endian'), - types.TEndianInt(8, True, 'little-endian'), - types.TEndianInt(64, False, 'little-endian'), - types.TEndianInt(64, True, 'big-endian')) + types.EndianInt(8, False, 'little-endian'), + types.EndianInt(8, True, 'little-endian'), + types.EndianInt(64, False, 'little-endian'), + types.EndianInt(64, True, 'big-endian')) ]) def endian_int_cast(self, expr, endiantype): """Check that casting to endianint results in the right type""" @@ -464,17 +466,17 @@ def endian_int_cast(self, expr, endiantype): @subtest([(targettype, endiantype) for targettype in ( - types.TInt(8, False), - types.TInt(8, False, - {"a": (types.TInt(4, False), 5, 2)}, - {"b": (types.TInt(2, False), 7, 5)}), - types.TPtr(types.TVoid()), + types.Int(8, False), + types.Int(8, False, + {"a": (types.Int(4, False), 5, 2)}, + {"b": (types.Int(2, False), 7, 5)}), + types.Ptr(types.Void()), ) for endiantype in ( - types.TEndianInt(8, False, 'little-endian'), - types.TEndianInt(8, True, 'little-endian'), - types.TEndianInt(64, False, 'little-endian'), - types.TEndianInt(64, True, 'big-endian')) + types.EndianInt(8, False, 'little-endian'), + types.EndianInt(8, True, 'little-endian'), + types.EndianInt(64, False, 'little-endian'), + types.EndianInt(64, True, 'big-endian')) ]) def endian_int_cast_from(self, targettype, endiantype): """Check that casting from an endianint results in the right type""" @@ -494,7 +496,7 @@ def endian_int_cast_from(self, targettype, endiantype): ) for iv in (ctree.mkCast( site, ctree.mkIntegerConstant(site, 5, True), - types.TEndianInt(32, True, 'big-endian')), + types.EndianInt(32, True, 'big-endian')), ctree.mkBitSlice( site, ctree.mkIntegerConstant(site, 0x80FF, False), ctree.mkIntegerConstant(site, 20, False), @@ -513,27 +515,27 @@ def as_int_binop_coverage(self, op, lh, rh): ctree.mkIntegerConstant(site, 1, False), 'le'), ctree.mkCast( site, ctree.mkIntegerConstant(site, 3, True), - types.TEndianInt(32, True, 'big-endian')), - types.TInt(64, True)), + types.EndianInt(32, True, 'big-endian')), + types.Int(64, True)), (ctree.mkIntegerConstant(site, 5, True), ctree.mkCast( site, ctree.mkIntegerConstant(site, 3, True), - types.TEndianInt(32, True, 'big-endian')), - types.TInt(64, True)), + types.EndianInt(32, True, 'big-endian')), + types.Int(64, True)), (ctree.mkCast( site, ctree.mkIntegerConstant(site, 3, True), - types.TEndianInt(32, True, 'big-endian')), + types.EndianInt(32, True, 'big-endian')), ctree.mkIntegerConstant(site, 5, True), - types.TInt(64, True)), + types.Int(64, True)), (ctree.mkCast( site, ctree.mkIntegerConstant(site, 3, True), - types.TEndianInt(32, True, 'big-endian')), + types.EndianInt(32, True, 'big-endian')), ctree.mkCast( site, ctree.mkIntegerConstant(site, 5, True), - types.TEndianInt(32, True, 'big-endian')), - types.TInt(64, True))]) + types.EndianInt(32, True, 'big-endian')), + types.Int(64, True))]) def as_int_ifexpr(self, lh, rh, expected_type): - expr = ctree.mkIfExpr(site, variable('b', types.TBool()), lh, rh) + expr = ctree.mkIfExpr(site, variable('b', types.Bool()), lh, rh) self.assertTrue(expr.type.eq(expected_type)) return ["bool b = false;", "EXPECT(%s == %s);" % ( @@ -544,11 +546,11 @@ def as_int_ifexpr(self, lh, rh, expected_type): ctree.mkUnaryMinus, ctree.mkUnaryPlus, lambda site, x : - ctree.mkCast(site, x, types.TInt(64, True))) + ctree.mkCast(site, x, types.Int(64, True))) for lh in (ctree.mkIntegerConstant(site, 5, True), ctree.mkCast( site, ctree.mkIntegerConstant(site, 5, True), - types.TEndianInt(32, True, 'big-endian')), + types.EndianInt(32, True, 'big-endian')), ctree.mkBitSlice( site, ctree.mkIntegerConstant(site, 0x80FF, False), ctree.mkIntegerConstant(site, 20, False), @@ -563,15 +565,15 @@ def as_int_unop_coverage(self, op, lh): @subtest([(ctree.mkIntegerConstant(site, 3, True),), (ctree.mkCast( site, ctree.mkIntegerConstant(site, 3, True), - types.TEndianInt(32, True, 'big-endian')),), + types.EndianInt(32, True, 'big-endian')),), (ctree.mkBitSlice( site, ctree.mkIntegerConstant(site, 0xF, False), ctree.mkIntegerConstant(site, 2, False), ctree.mkIntegerConstant(site, 1, False), 'le'),)]) def as_int_new_coverage(self, count): """Checks for as_int coverage""" - expr = ctree.mkNew(site, types.TInt(8, False), count) - self.assertTrue(expr.type.eq(types.TPtr(types.TInt(8, False)))) + expr = ctree.mkNew(site, types.Int(8, False), count) + self.assertTrue(expr.type.eq(types.Ptr(types.Int(8, False)))) return ["EXPECT(%s == 3);" % expr.count.read()] def expect_int_unop(self, const, unop, expected): @@ -584,7 +586,7 @@ def expect_int_unop(self, const, unop, expected): # value fits in 8 bits, so we can test with 8-bit # non-constant operands, to cover sign extension var8_op = unop(site, variable( - 'y', ctree.TInt(8, const.type.signed))) + 'y', types.Int(8, const.type.signed))) test_8bit = ['%sint8 y = %s;' % ('' if const.type.signed else 'u', const.read()), 'EXPECT(%s == %s);' % (var8_op.read(), expected,)] @@ -613,7 +615,7 @@ def int_unop_types_lvalue(self, op, bits, signed): of the right type, which generates a C expression of the right type''' expect_int64 = (bits, signed) != (64, False) - t = types.TInt(bits, signed) + t = types.Int(bits, signed) expr = op(site, variable('i', t)) self.expect_int_type(expr.ctype(), expect_int64) return [t.declaration('i') + ' = 1;', @@ -651,11 +653,11 @@ def unary_plus(self, val, expect, signed): @subtest() def unary_plus_rval(self): - i = ctree.mkUnaryPlus(site, variable('i', types.TInt(64, False))) - with self.assertRaises(messages.ERVAL): + i = ctree.mkUnaryPlus(site, variable('i', types.Int(64, False))) + with self.assertRaises(E.RVAL): ctree.mkAddressOf(site, i) - f = ctree.mkUnaryPlus(site, variable('f', types.TFloat('double'))) - with self.assertRaises(messages.ERVAL): + f = ctree.mkUnaryPlus(site, variable('f', types.Float('double'))) + with self.assertRaises(E.RVAL): ctree.mkAddressOf(site, f) return None @@ -680,14 +682,14 @@ def unary_minus(self, val, expect, signed): def unray_minus_float(self): c = ctree.mkUnaryMinus(site, float_const(0.3)) self.assertTrue(c.constant) - v = ctree.mkUnaryMinus(site, variable('f', types.TFloat('float'))) + v = ctree.mkUnaryMinus(site, variable('f', types.Float('float'))) return ['EXPECT(%s == -0.3);' % (c.read(),), 'float f = 1234.25;', 'EXPECT(%s == -1234.25);' % (v.read(),)] @subtest([(ctree.mkUnaryPlus,), (ctree.mkUnaryMinus,)]) def unary_float_promotion(self, op): - f = op(site, variable('f', types.TFloat('float'))) + f = op(site, variable('f', types.Float('float'))) self.assertEqual(f.ctype().name, 'double') return ['float f = 1.0;', 'EXPECT(IS_DOUBLE(%s));' % (f.read(),)] @@ -716,7 +718,7 @@ def pre_post_inc_dec_int(self, bits, signed, less, more): '''test that ++x, --x, x++ and x-- produces correct values''' # TODO: today we inherit the undefined behaviour of (a++ - ++a) from C # Would be better to make this well-defined - t = types.TInt(bits, signed) + t = types.Int(bits, signed) yield t.declaration('x') + ';' for (before, after, pre_op, post_op) in [ (less, more, ctree.PreInc, ctree.PostInc), @@ -758,7 +760,7 @@ def pre_post_inc_dec_endian_int(self, size, signed, byte_order, value, op, res_expected, var_expected): '''test that ++x, --x, x++ and x-- on an endian variable correctly modify the variable and return the correct values''' - endian_type = types.TEndianInt(size*8, signed, byte_order) + endian_type = types.EndianInt(size*8, signed, byte_order) initializer = ctree.ExpressionInitializer( ctree.mkCast(site, ctree.mkIntegerConstant(site, value, True), @@ -804,8 +806,8 @@ def int_binop_types(self, op, lbits, lsigned, rbits, rsigned): C expression of the right type''' expect_int64 = ((lbits, lsigned) != (64, False) and (rbits, rsigned) != (64, False)) - ltype = types.TInt(lbits, lsigned) - rtype = types.TInt(rbits, rsigned) + ltype = types.Int(lbits, lsigned) + rtype = types.Int(rbits, rsigned) expr = op(site, variable('l', ltype), variable('r', rtype)) self.expect_int_type(expr.ctype(), expect_int64) const_expr = op( @@ -829,7 +831,7 @@ def expect_int_binop(self, lhconst, rhconst, binop, expected): variable('y', lhconst.type)) self.expect_int_type(var_op.ctype(), expect_signed) [lh8type, rh8type] = [ - ctree.TInt(8, const.value < 0) + types.Int(8, const.value < 0) if -128 <= const.value < 256 and const.type.signed else const.type for const in [lhconst, rhconst]] @@ -932,7 +934,7 @@ def shl(self, lh, lhsigned, rh, rhsigned, expect): def sh_neg(self, op, lh, rh): lhconst = int_const(lh, True) rhconst = int_const(rh, True) - with self.assertRaises(messages.ESHNEG): + with self.assertRaises(E.SHNEG): op(site, lhconst, rhconst) var_op = op(site, variable('a', lhconst.type), variable('b', rhconst.type)) @@ -952,7 +954,7 @@ def sh_neg(self, op, lh, rh): else '0xdead0000') for lhsigned in [False, True] for rhsigned in [False, True]]) - def shl(self, lh, lhsigned, rh, rhsigned, expect): + def shr(self, lh, lhsigned, rh, rhsigned, expect): return self.expect_int_binop(int_const(lh, lhsigned), int_const(rh, rhsigned), ctree.mkShR, @@ -1007,13 +1009,13 @@ def add_sub_int(self, lh, lhsigned, rh, rhsigned, expect, sub): expect) @subtest([ - (types.TInt(8, True),), - (types.TPtr(types.TVoid()),), + (types.Int(8, True),), + (types.Ptr(types.Void()),), ]) def add_sub_ptr(self, ptype): - p = variable('p', types.TPtr(ptype, const=True)) - a = variable('a', types.TArray(ptype, int_const(10, True), const=True)) - i = variable('i', types.TInt(64, True)) + p = variable('p', types.Ptr(ptype, const=True)) + a = variable('a', types.Array(ptype, int_const(10, True), const=True)) + i = variable('i', types.Int(64, True)) stmts = ['%s = {};' % (ptype.declaration('a[8]'),), 'int64 i = 5;', '%s = a;' % (ptype.declaration('*p'),), @@ -1036,13 +1038,13 @@ def add_sub_ptr(self, ptype): @subtest() def add_sub_voidptr(self): - p = variable('p', types.TPtr(types.TVoid())) - i = variable('i', types.TInt(64, True)) + p = variable('p', types.Ptr(types.Void())) + i = variable('i', types.Int(64, True)) for (op, lh, rh) in [(ctree.mkAdd, p, i), (ctree.mkAdd, i, p), (ctree.mkSubtract, p, i), (ctree.mkSubtract, p, p)]: - with self.assertRaises(messages.EBTYPE): + with self.assertRaises(E.BTYPE): op(site, lh, rh) return None @@ -1147,7 +1149,7 @@ def nan_binops(self, lh, rh, op): for lhsigned in [True, False]]) def divmod_by_zero(self, lh, op): rh = int_const(0, True) - with self.assertRaises(messages.EDIVZ): + with self.assertRaises(E.DIVZ): op(site, lh, rh) var_op = op(site, variable('a', lh.type), variable('b', rh.type)) @@ -1161,7 +1163,7 @@ def divmod_by_zero(self, lh, op): (int_const(0, True), int_const(0, True), (0, 1, 0, 1, 0, 1)), (int_const(-1, True), int_const(0, False), (1, 1, 0, 0, 1, 0)), (int_const(0, False), int_const(-1, True), (0, 0, 1, 1, 1, 0)), - (ctree.TypedIntegerConstant(site, 0, types.TInt(8, False)), + (ctree.TypedIntegerConstant(site, 0, types.Int(8, False)), int_const(-1, True), (0, 0, 1, 1, 1, 0)), (int_const(-1, False), int_const(-1, True), (0, 0, 1, 1, 1, 0)), (int_const(-1, True), int_const(-1, False), (1, 1, 0, 0, 1, 0)), @@ -1189,8 +1191,8 @@ def compare_numeric(self, lh, rh, op, result): logging.ignore_warning('WNEGCONSTCOMP') mix_cond = op(site, lh, rh_var) logging.enable_warning('WNEGCONSTCOMP') - self.assertIsInstance(var_cond.ctype(), types.TBool) - self.assertIsInstance(mix_cond.ctype(), types.TBool) + self.assertIsInstance(var_cond.ctype(), types.Bool) + self.assertIsInstance(mix_cond.ctype(), types.Bool) return ['%s = %s;' % (lh.ctype().declaration('lh'), lh.read()), '%s = %s;' % (rh.ctype().declaration('rh'), rh.read()), 'EXPECT(%s(%s));' % ('' if result else '!', var_cond.read()), @@ -1199,16 +1201,16 @@ def compare_numeric(self, lh, rh, op, result): @subtest([ (lh, rh, op, bool(result)) for (lh, rh, results) in [ - (ctree.mkLit(site, 'arr', types.TArray(types.TInt(32, True), + (ctree.mkLit(site, 'arr', types.Array(types.Int(32, True), int_const(0, True))), - ctree.mkLit(site, '&arr[1]', types.TPtr(types.TInt(32, True))), + ctree.mkLit(site, '&arr[1]', types.Ptr(types.Int(32, True))), (1, 1, 0, 0, 1, 0)), - (ctree.mkLit(site, '&arr[1]', types.TPtr(types.TInt(32, True))), - ctree.mkLit(site, 'arr', types.TArray(types.TInt(32, True), + (ctree.mkLit(site, '&arr[1]', types.Ptr(types.Int(32, True))), + ctree.mkLit(site, 'arr', types.Array(types.Int(32, True), int_const(0, True))), (0, 0, 1, 1, 1, 0)), - (ctree.mkLit(site, '&arr[1]', types.TPtr(types.TInt(32, True))), - ctree.mkLit(site, '&arr[1]', types.TPtr(types.TInt(32, True))), + (ctree.mkLit(site, '&arr[1]', types.Ptr(types.Int(32, True))), + ctree.mkLit(site, '&arr[1]', types.Ptr(types.Int(32, True))), (0, 1, 0, 1, 0, 1))] for (result, op) in zip(results, [ctree.mkLessThan, @@ -1219,7 +1221,7 @@ def compare_numeric(self, lh, rh, op, result): ctree.mkEquals])]) def compare_pointers(self, lh, rh, op, result): cond = op(site, lh, rh) - self.assertIsInstance(cond.ctype(), types.TBool) + self.assertIsInstance(cond.ctype(), types.Bool) return ['int32 arr[4] = {};' 'EXPECT(%s(%s));' % ('' if result else '!', cond.read())] @@ -1237,16 +1239,16 @@ def report(error): raise error site, rh, int_const(0), int_const(0))]: for cond in [int_const(0), float_const(0.3)]: - with self.assertRaises(messages.ENBOOL): + with self.assertRaises(E.NBOOL): op(site, cond) finally: ctree.report = logging.report - with self.assertRaises(messages.EBINOP): + with self.assertRaises(E.BINOP): ctree.mkIfExpr( site, ctree.mkBoolConstant(site, True), - ctree.mkLit(site, '', types.TPtr(types.TInt(8, False))), - ctree.mkLit(site, '', types.TPtr(types.TInt(8, True)))) + ctree.mkLit(site, '', types.Ptr(types.Int(8, False))), + ctree.mkLit(site, '', types.Ptr(types.Int(8, True)))) @subtest([(cond, tbits, tsigned, fbits, fsigned, rsigned) for (tbits, tsigned, fbits, fsigned, rsigned) in [ @@ -1256,9 +1258,9 @@ def report(error): raise error ]) def int_cond(self, cond, tbits, tsigned, fbits, fsigned, rsigned): cond_const = ctree.mkBoolConstant(site, cond) - cond_var = variable('cond', types.TBool()) - tconst = ctree.mkCast(site, int_const(-128), types.TInt(tbits, tsigned)) - fconst = ctree.mkCast(site, int_const(-127), types.TInt(fbits, fsigned)) + cond_var = variable('cond', types.Bool()) + tconst = ctree.mkCast(site, int_const(-128), types.Int(tbits, tsigned)) + fconst = ctree.mkCast(site, int_const(-127), types.Int(fbits, fsigned)) tvar = variable('t', tconst.ctype()) fvar = variable('f', fconst.ctype()) const_const = ctree.mkIfExpr(site, cond_const, tconst, fconst) @@ -1287,17 +1289,17 @@ def int_cond(self, cond, tbits, tsigned, fbits, fsigned, rsigned): @subtest() def ptr_cond(self): - cond = lit(types.TBool()) + cond = lit(types.Bool()) t = ctree.mkIfExpr( - site, cond, lit(types.TPtr(types.TInt(8, True))), - lit(types.TPtr(types.TInt(8, True, const=True)))).ctype() - self.assertIsInstance(t, types.TPtr) + site, cond, lit(types.Ptr(types.Int(8, True))), + lit(types.Ptr(types.Int(8, True, const=True)))).ctype() + self.assertIsInstance(t, types.Ptr) self.expect_int_type(t.base, True, 8) self.assertTrue(t.base.const) t = ctree.mkIfExpr( - site, cond, lit(types.TPtr(types.TVoid())), - lit(types.TPtr(types.TInt(8, True, const=True)))).ctype() - self.assertIsInstance(t, types.TPtr) + site, cond, lit(types.Ptr(types.Void())), + lit(types.Ptr(types.Int(8, True, const=True)))).ctype() + self.assertIsInstance(t, types.Ptr) self.assertTrue(t.base.const) self.assertTrue(t.base.void) t = ctree.mkIfExpr( @@ -1332,22 +1334,22 @@ def equal_constants(self, lh, rh, op, result): def equal_pointers(self): for op in [ctree.mkEquals, ctree.mkNotEquals]: # a void pointer can be compared to any pointer - op(site, lit(types.TPtr(types.TInt(8, True))), - lit(types.TPtr(types.TVoid()))) + op(site, lit(types.Ptr(types.Int(8, True))), + lit(types.Ptr(types.Void()))) for op in [ctree.mkLessThan, ctree.mkLessThanOrEquals, ctree.mkGreaterThan, ctree.mkGreaterThanOrEquals]: - with self.assertRaises(messages.EILLCOMP): - op(site, lit(types.TPtr(types.TInt(8, True))), - lit(types.TPtr(types.TVoid()))) + with self.assertRaises(E.ILLCOMP): + op(site, lit(types.Ptr(types.Int(8, True))), + lit(types.Ptr(types.Void()))) @subtest() def null_pointers(self): - null = ctree.mkNullConstant(site) - for expr in (lit(types.TPtr(types.TInt(8, True))), + null = mkNullConstant(site) + for expr in (lit(types.Ptr(types.Int(8, True))), ctree.mkCast(site, null, - types.TPtr(types.TInt(8, True)))): + types.Ptr(types.Int(8, True)))): for op in [ctree.mkEquals, ctree.mkNotEquals]: # NULL can be compared to any pointer... res = op(site, null, expr) @@ -1356,7 +1358,7 @@ def null_pointers(self): self.assertFalse(res.constant) for (invert, op) in ((False, ctree.mkEquals), (True, ctree.mkNotEquals)): - res = op(site, null, ctree.mkNullConstant(site)); + res = op(site, null, mkNullConstant(site)); self.assertTrue(res.constant) self.assertEqual(res.value, True != invert) res = op(site, null, ctree.mkStringConstant(site, "non-null")) @@ -1367,7 +1369,7 @@ def null_pointers(self): @subtest() def assign_trunc(self): - target_type = types.TInt(5, True) + target_type = types.Int(5, True) stmt = ctree.mkCopyData(site, int_const(0x5f), variable('x', target_type)) code = output.StrOutput() @@ -1380,30 +1382,30 @@ def assign_trunc(self): @subtest() def const_types(self): type_objs = [ - types.TVoid(), - types.TDevice('struct_t'), - types.TNamed('struct_t'), - types.TBool(), - types.TInt(24, True), - types.TEndianInt(24, True, 'big-endian'), - types.TLong(False), - types.TSize(True), - types.TInt64_t(True), - types.TFloat('double'), - types.TArray(types.TBool(), int_const(3)), - types.TPtr(types.TBool()), - types.TPtr(types.TFunction([], types.TVoid())), - types.TPtr(types.TArray(types.TBool(), int_const(3))), - types.TTrait(traits.Trait( + types.Void(), + types.Device('struct_t'), + types.Named('struct_t'), + types.Bool(), + types.Int(24, True), + types.EndianInt(24, True, 'big-endian'), + types.Long(False), + types.Size(True), + types.Int64_t(True), + types.Float('double'), + types.Array(types.Bool(), int_const(3)), + types.Ptr(types.Bool()), + types.Ptr(types.Function([], types.Void())), + types.Ptr(types.Array(types.Bool(), int_const(3))), + types.Trait(traits.Trait( site, 'struct_t', set(), {}, {}, {}, {}, {}, {}, {})), - types.TTraitList('struct_t'), - types.TExternStruct({}, 'struct_t', 'struct_t'), - types.TStruct({'x': types.TBool()}, 'struct_label'), - types.TLayout( + types.TraitList('struct_t'), + types.ExternStruct({}, 'struct_t', 'struct_t'), + types.Struct({'x': types.Bool()}, 'struct_label'), + types.Layout( 'big-endian', [(site, 'x', - types.TEndianInt(24, True, 'big-endian'))], + types.EndianInt(24, True, 'big-endian'))], 'struct_label'), - types.THook([]), + types.Hook([]), ] covered_types = {type(o) for o in type_objs} all_types = {t for t in types.__dict__.values() @@ -1417,11 +1419,11 @@ def const_types(self): # abstract type types.StructType, # 1.2, weird - types.TUnknown, + types.Unknown, # known to be broken, hard to fix - types.TVector, + types.Vector, # function types don't allow const qualification - types.TFunction, + types.Function, } assert all_types - untested_types <= covered_types, ( all_types - covered_types) diff --git a/py/dml/dmlc.py b/py/dml/dmlc.py index 86eab30b0..ffee73fd3 100644 --- a/py/dml/dmlc.py +++ b/py/dml/dmlc.py @@ -8,7 +8,7 @@ import time from pathlib import Path -from . import structure, logging, messages, ctree, ast, expr_util, toplevel +from . import structure, logging, ctree, ast, expr_util, toplevel from . import serialize from . import dmlparse from . import output @@ -18,9 +18,8 @@ import dml.info_backend import dml.g_backend import dml.globals -import dml.dmlparse -from .logging import * -from .messages import * +from .logging import ICE, dbg, report +from . import errors as E, warnings as W from .env import api_versions, default_api_version import tarfile @@ -36,11 +35,11 @@ def prerr(msg): # Ignore some warnings by default -ignore_warning('WASSERT') -ignore_warning('WNDOC') -ignore_warning('WSHALL') -ignore_warning('WUNUSED') -ignore_warning('WNSHORTDESC') +logging.ignore_warning('WASSERT') +logging.ignore_warning('WNDOC') +logging.ignore_warning('WSHALL') +logging.ignore_warning('WUNUSED') +logging.ignore_warning('WNSHORTDESC') if os.getenv('DMLC_DEBUG'): debug_mode = True @@ -75,9 +74,9 @@ def process(devname, global_defs, top_tpl, extra_params): # inheriting the main file, thereby overriding any default # declarations from there param_tpl = '@' - param_site = SimpleSite(":0", + param_site = logging.SimpleSite(":0", dml_version=dml.globals.dml_version) - top_site = SimpleSite(top_tpl[1:] + ':1', + top_site = logging.SimpleSite(top_tpl[1:] + ':1', dml_version=dml.globals.dml_version) global_defs.append(ast.template_dml12( top_site, param_tpl, [ @@ -115,7 +114,7 @@ def mytrace(frame, event, arg): def parse_define(arg): "Parse a parameter assignment given as a -D option" - define_site = SimpleSite(':0', + define_site = logging.SimpleSite(':0', dml_version=dml.globals.dml_version) (lexer, _) = toplevel.get_parser((1, 4)) lexer.filename = filename = "" @@ -123,10 +122,10 @@ def parse_define(arg): lexer.input(arg) tokens = list(lexer) if len(tokens) < 3 or tokens[1].type != 'EQUALS': - raise ESYNTAX(define_site, '-D' + arg, "expected name=value") + raise E.SYNTAX(define_site, '-D' + arg, "expected name=value") (ident, _, literal) = tokens[:3] if ident.type != 'ID': - raise ESYNTAX(define_site, '-D' + arg, + raise E.SYNTAX(define_site, '-D' + arg, "invalid identifier: %s" % (ident.value,)) if literal.type == 'FCONST': @@ -138,10 +137,10 @@ def parse_define(arg): elif literal.type == 'ID' and literal.value in {'true', 'false'}: value = ast.variable(define_site, literal.value) else: - raise ESYNTAX(define_site, '-D' + arg, + raise E.SYNTAX(define_site, '-D' + arg, "Invalid literal %s" % (literal.value,)) if len(tokens) > 3: - raise ESYNTAX(define_site, '-D' + arg, + raise E.SYNTAX(define_site, '-D' + arg, "garbage after literal: " + str(tokens[3].value)) return (ident.value, value) @@ -274,8 +273,8 @@ class WarnHelpAction(HelpAction): def print_help(self): print('''Tags accepted by --warn and --nowarn:''') by_ignored = {True: [], False: []} - for tag in sorted(messages.warnings): - by_ignored[warning_is_ignored(tag)].append(tag) + for tag in sorted(W.all_warnings): + by_ignored[logging.warning_is_ignored(tag)].append(tag) print(' Enabled by default:') for tag in by_ignored[False]: print(f' {tag}') @@ -514,7 +513,7 @@ def main(argv): global outputbase, output_c if options.include_tag: - set_include_tag(True) + logging.set_include_tag(True) if options.debuggable: dml.globals.debuggable = True @@ -523,7 +522,7 @@ def main(argv): for d in options.defines: try: (name, value) = parse_define(d) - except ESYNTAX as e: + except E.SYNTAX as e: report(e) else: defs[name] = value @@ -538,7 +537,7 @@ def main(argv): " or older") if options.werror: - DMLWarning.enable_werror() + logging.DMLWarning.enable_werror() try: logging.max_errors = int(options.max_errors) @@ -634,19 +633,19 @@ def main(argv): changes.values()) if not breaking_changes.enable_WLOGMIXUP.enabled: - ignore_warning('WLOGMIXUP') + logging.ignore_warning('WLOGMIXUP') for w in options.disabled_warnings: - if not is_warning_tag(w): + if w not in W.all_warnings: prerr("dmlc: the tag '%s' is not a valid warning tag" % w) sys.exit(1) - ignore_warning(w) + logging.ignore_warning(w) for w in options.enabled_warnings: - if not is_warning_tag(w): + if w not in W.all_warnings: prerr("dmlc: the tag '%s' is not a valid warning tag" % w) sys.exit(1) - enable_warning(w) + logging.enable_warning(w) inputfilename = options.input_filename @@ -764,7 +763,7 @@ def main(argv): # if there's already a hard error somewhere, because if the # parameter was actually used, then the WREF is a duplicate # of an already reported error. - for wref in messages.WREF.instances: + for wref in W.REF.instances: report(wref) logtime("total") @@ -790,7 +789,7 @@ def main(argv): return 3 except (RuntimeError, Exception) as e: - ctx = ErrorContext.last_entered + ctx = logging.ErrorContext.last_entered if ctx: report(ICE(ctx.node, "Unexpected exception '%s' in %s" diff --git a/py/dml/dmllex.py b/py/dml/dmllex.py index 1103e477d..72202e24c 100644 --- a/py/dml/dmllex.py +++ b/py/dml/dmllex.py @@ -3,9 +3,9 @@ # Lexer -from ply import lex -from .logging import report, DumpableSite -from .messages import * +from . import logging +from .logging import report +from . import errors as E import re # Reserved words allowed as identifiers @@ -179,7 +179,7 @@ def rangecheck_int(t, value): if value >= 1 << 64: try: syntax_error(t, t.value, 'too large integer constant') - except ESYNTAX as e: + except E.SYNTAX as e: report(e) return value & ((1 << 64) - 1) return value @@ -216,7 +216,7 @@ def t_ICONST(t): } def syntax_error(t, tokenstr, reason): - raise ESYNTAX(DumpableSite(t.lexer.file_info, t.lexpos), tokenstr, reason) + raise E.SYNTAX(logging.DumpableSite(t.lexer.file_info, t.lexpos), tokenstr, reason) def t_SCONST(t): r'"(?:[^\x00-\x1f\x7f"\\]|\\.)*"' diff --git a/py/dml/dmllex12.py b/py/dml/dmllex12.py index b628c480b..23fa174b7 100644 --- a/py/dml/dmllex12.py +++ b/py/dml/dmllex12.py @@ -1,15 +1,17 @@ # © 2021 Intel Corporation # SPDX-License-Identifier: MPL-2.0 -from .dmllex import * +# PLY discovers t_* rules from module namespace +from .dmllex import * # noqa: F403 -tokens = common_tokens + ('DOLLAR', 'DOTDOT', 'HASH') +tokens = (common_tokens # noqa: F405 + + ('DOLLAR', 'DOTDOT', 'HASH')) t_DOLLAR = r'\$' t_DOTDOT = r'\.\.' t_HASH = r'\#' -keywords_dml12 = dict(keywords_common) -reserved_idents = reserved_idents_common +keywords_dml12 = dict(keywords_common) # noqa: F405 +reserved_idents = reserved_idents_common # noqa: F405 for kw in ['parameter', 'trait', 'nothrow', 'data']: keywords_dml12[kw] = kw.upper() tokens += (kw.upper(),) diff --git a/py/dml/dmllex14.py b/py/dml/dmllex14.py index baa8b471d..4148ebdb0 100644 --- a/py/dml/dmllex14.py +++ b/py/dml/dmllex14.py @@ -1,7 +1,10 @@ # © 2021 Intel Corporation # SPDX-License-Identifier: MPL-2.0 -from .dmllex import * +# PLY discovers t_* rules from module namespace +from .dmllex import * # noqa: F403 +from . import errors as E +from .logging import report, DumpableSite hashids = {'#' + kw: 'HASH' + kw.upper() for kw in [ @@ -11,7 +14,7 @@ 'select', ]} -tokens = (common_tokens +tokens = (common_tokens # noqa: F405 + ('HASHCONDOP', 'HASHCOLON') + ('DISCARD',) + tuple(hashids.values())) @@ -20,7 +23,7 @@ t_HASHCOLON = r'\#:' t_DISCARD = r'_' -keywords_dml14 = dict(keywords_common) +keywords_dml14 = dict(keywords_common) # noqa: F405 for kw in ['param', 'saved', 'async', 'await', 'with', 'shared', 'stringify', 'export', 'as', 'independent', 'startup', 'memoized', 'hook']: keywords_dml14[kw] = kw.upper() @@ -28,7 +31,7 @@ keywords_dml14['_'] = 'DISCARD' -reserved_idents = reserved_idents_common + ( +reserved_idents = reserved_idents_common + ( # noqa: F405 'PARAM', 'SAVED', 'INDEPENDENT', 'STARTUP', 'MEMOIZED') def t_ID(t): @@ -40,7 +43,7 @@ def t_HASHID(t): r'\#[A-Za-z_][\w_]*' value = hashids.get(t.value) if not value: - report(ESYNTAX(DumpableSite(t.lexer.file_info, t.lexpos), t.value, + report(E.SYNTAX(DumpableSite(t.lexer.file_info, t.lexpos), t.value, "illegal # symbol")) return None t.type = value diff --git a/py/dml/dmlparse.py b/py/dml/dmlparse.py index de461896d..53d03ed3e 100644 --- a/py/dml/dmlparse.py +++ b/py/dml/dmlparse.py @@ -3,12 +3,13 @@ # Parser for DML 1.2 -import os, sys, re, itertools +import os, itertools from ply import lex, yacc -from .logging import * -from .messages import * -from . import ast, logging +from . import logging +from .logging import report +from . import errors as E, warnings as W, porting as P +from . import ast import dml.globals from . import dmllex12 from . import dmllex14 @@ -85,7 +86,7 @@ def default_site(t, elt=1): # tracking, which would sometimes happen if tracking=False was # passed to parse(). assert lexpos != 0 or t.lineno(elt) != 0 - return DumpableSite(t.parser.file_info, lexpos) + return logging.DumpableSite(t.parser.file_info, lexpos) site = default_site @@ -112,15 +113,15 @@ def track_lexspan(): global site site = extended_site def start_site(site): - while isinstance(site, ExpandedSite): + while isinstance(site, logging.ExpandedSite): site = site.site assert lexspan_map if site not in lexspan_map: return None (start, _) = lexspan_map[site] - return DumpableSite(site.file_info, start) + return logging.DumpableSite(site.file_info, start) def end_site(site): - while isinstance(site, ExpandedSite): + while isinstance(site, logging.ExpandedSite): site = site.site assert lexspan_map if site not in lexspan_map: @@ -131,20 +132,20 @@ def end_site(site): # We still produce a well-formed site, to avoid confusing # port-dml's tag parser if os.path.isfile(site.filename() + 'ast'): - return SimpleSite(site.filename() + ':1:1') + return logging.SimpleSite(site.filename() + ':1:1') # unknown... return None (_, end) = lexspan_map[site] - return DumpableSite(site.file_info, end) + return logging.DumpableSite(site.file_info, end) def lex_end_site(t, elt): info = t.parser.file_info (start, end) = t.lexspan(elt) - return DumpableSite(info, end) + return logging.DumpableSite(info, end) def parse_bitorder(t, syn): if syn not in {'be', 'le'}: - report(EBITO(site(t), syn)) + report(E.BITO(site(t), syn)) return 'le' return syn @@ -282,7 +283,7 @@ def device_statements_empty(t): t[0] = [] @prod_dml12 -def device_statement(t): +def device_statement_dml12(t): '''device_statement : object_statement | toplevel''' t[0] = t[1] @@ -307,7 +308,7 @@ def toplevel_param(t): '''toplevel_param : param''' (_, type_info, _, _) = t[1].args if type_info is not None and type_info.kind == 'paramtype': - report(ESYNTAX(site(t), ':', + report(E.SYNTAX(site(t), ':', 'parameter type declaration only permitted' + ' in top level template block')) # fallback: dummy statement @@ -358,7 +359,7 @@ def toplevel_else_if(t): # Objects @prod_dml12 -def object_anonymous_bank(t): +def object_anonymous_bank_dml12(t): 'object : maybe_extension BANK object_spec' t[0] = ast.object_(site(t), None, 'bank', [], None, t[3]) @@ -431,23 +432,23 @@ def bitrange_2(t): endian_translate_bit(t[4], parent_bitsize(t[4].site), bitorder))] @prod_dml12 -def object_field_1(t): +def object_field_1_dml12(t): 'object : maybe_extension FIELD objident bitrange maybe_istemplate object_spec' if logging.show_porting: - report(PFIELDRANGE(site(t, 4))) + report(P.FIELDRANGE(site(t, 4))) t[0] = ast.object_(site(t), t[3], 'field', [], None, t[4] + t[5] + t[6]) @prod_dml12 -def field_array_size_no(t): +def field_array_size_no_dml12(t): 'fieldarraysize : ' fixup_emptyprod_lexpos(t) t[0] = [] @prod_dml12 -def field_array_size(t): +def field_array_size_dml12(t): 'fieldarraysize : LBRACKET ident IN expression DOTDOT expression RBRACKET fieldarraysize' if t[4].kind != 'int' or t[4].args != (0,): - report(EZRANGE(site(t, 4))) + report(E.ZRANGE(site(t, 4))) s = site(t) t[0] = [(ast.variable(site(t, 2), t[2]), ast.binop(s, ast.int(s, 1), '+', t[6]))] + t[8] @@ -457,11 +458,11 @@ def field_array_size(t): # standard PARRAY, because it's seldom used. remove_from = site(t, 7) new = ' + 1' - report(PARRAY(site(t, 3), site(t, 5), remove_from, + report(P.ARRAY(site(t, 3), site(t, 5), remove_from, end_site(t[6].site), new)) @prod_dml12 -def object_field_2(t): +def object_field_2_dml12(t): 'object : maybe_extension FIELD objident fieldarraysize bitrangespec maybe_istemplate object_spec' t[0] = ast.object_(site(t), t[3], 'field', t[4], None, t[5] + t[6] + t[7]) @@ -471,10 +472,10 @@ def session(t): t[0] = t[1] @prod_dml12 -def session(t): +def session_dml12(t): 'session : DATA' if logging.show_porting: - report(PSESSION(site(t), 'data', 'session')) + report(P.SESSION(site(t), 'data', 'session')) t[0] = t[1] @prod @@ -547,7 +548,7 @@ def object3(t): | maybe_extension IMPLEMENT objident array_list maybe_istemplate object_spec''' array_spec = t[4] if array_spec and t[2] in {'interface', 'implement'}: - report(ESYNTAX(site(t, 4), '[', f'{t[2]} array not allowed')) + report(E.SYNTAX(site(t, 4), '[', f'{t[2]} array not allowed')) array_spec = [] t[0] = ast.object_(site(t), t[3], t[2], array_spec, t[1], t[5] + t[6]) @@ -557,12 +558,12 @@ def object_subdevice(t): t[0] = ast.object_(site(t), t[3], t[2], t[4], t[1], t[5] + t[6]) @prod_dml12 -def maybe_extern_yes(t): +def maybe_extern_yes_dml12(t): '''maybe_extern : EXTERN''' t[0] = True @prod_dml12 -def maybe_extern_no(t): +def maybe_extern_no_dml12(t): '''maybe_extern :''' fixup_emptyprod_lexpos(t) t[0] = False @@ -588,29 +589,29 @@ def report_pretval(site, file_info, start, end, rparen, outp, stmts): and stmts[-1].args[0].kind == 'set'): (lh, rh) = stmts[-1].args[0].args if lh.kind == 'variable_dml12' and lh.args[0] == outp[0][2]: - report(POUTARGRETURN(lh.site, start_site(rh.site), None)) + report(P.OUTARGRETURN(lh.site, start_site(rh.site), None)) # suppress PRETVAL's insertion of return statement ends_with_return = True - report(PRETVAL( + report(P.RETVAL( site, - DumpableSite(file_info, start), - DumpableSite(file_info, end), - DumpableSite(file_info, rparen), + logging.DumpableSite(file_info, start), + logging.DumpableSite(file_info, end), + logging.DumpableSite(file_info, rparen), [(psite.loc(), pname) for (_, psite, pname, _) in outp])) if not ends_with_return: - report(PRETVAL_END( + report(P.RETVAL_END( site, - DumpableSite(file_info, end), + logging.DumpableSite(file_info, end), [pname for (_, psite, pname, _) in outp])) @prod_dml12 -def object_method_noinparams(t): +def object_method_noinparams_dml12(t): '''method : METHOD maybe_extern objident method_outparams maybe_default compound_statement''' name = t[3] (inp, outp, throws) = ([], t[4], True) if logging.show_porting: - report(PINPARAMLIST(site(t, 4))) + report(P.INPARAMLIST(site(t, 4))) if logging.show_porting and outp: (start, end) = t.lexspan(6) [stmts, _] = t[6].args @@ -625,7 +626,7 @@ def object_method_noinparams(t): @prod_dml12 -def object_method(t): +def object_method_dml12(t): '''method : METHOD maybe_extern objident LPAREN cdecl_maybe_discarded_or_ident_list RPAREN method_outparams maybe_nothrow maybe_default compound_statement''' name = t[3] inp = t[5] @@ -634,10 +635,10 @@ def object_method(t): if logging.show_porting and any(not typ for (_, _, name, typ) in inp): # some standard methods are assigned a type later on if name not in {'set', 'write'}: - report(PINLINEDECL(site(t), 'method', 'inline method')) + report(P.INLINEDECL(site(t), 'method', 'inline method')) for (_, decl_site, (_, _, argname), typ) in inp: if not typ: - report(PINLINEDECL(decl_site, argname, 'inline ' + argname)) + report(P.INLINEDECL(decl_site, argname, 'inline ' + argname)) if logging.show_porting and outp: (start, end) = t.lexspan(10) [stmts, _] = t[10].args @@ -656,20 +657,20 @@ def method_qualifiers_check(site, qualifiers, inp, outp, throws, default): memoized = 'memoized' in qualifiers if startup: if inp: - report(ESYNTAX(site, None, + report(E.SYNTAX(site, None, 'startup methods may not have input parameters')) inp = [] if (outp or throws) and not memoized: - report(ESYNTAX(site, None, + report(E.SYNTAX(site, None, 'non-memoized startup methods may not have return' + 'values or be throwing')) outp = [] elif not (outp or throws) and memoized: - report(ESYNTAX(site, None, + report(E.SYNTAX(site, None, 'memoized methods must have return values and/or ' 'be throwing')) if default: - report(ESYNTAX(site, None, + report(E.SYNTAX(site, None, "startup methods may not be declared 'default'")) return (inp, outp) @@ -677,7 +678,7 @@ def method_qualifiers_check(site, qualifiers, inp, outp, throws, default): def maybe_colon_yes(t): '''maybe_colon : COLON''' if not site(t).provisional_enabled(provisional.explicit_method_decls): - report(ESYNTAX(site(t), ':', "expected '{' or 'default'")) + report(E.SYNTAX(site(t), ':', "expected '{' or 'default'")) t[0] = False else: t[0] = True @@ -720,7 +721,7 @@ def object_inline_method(t): if all(typ for (_, asite, name, typ) in inp): # inline annotation would have no effect for fully typed methods. # We forbid it as a way to strongly discourage unneeded use of inline. - report(ESYNTAX(site(t, 2), 'inline', + report(E.SYNTAX(site(t, 2), 'inline', 'only use inline if there are untyped arguments')) body = t[7] t[0] = ast.method(site(t), name, @@ -729,17 +730,17 @@ def object_inline_method(t): @prod_dml12 -def arraydef1(t): +def arraydef1_dml12(t): '''arraydef : expression''' t[0] = (ast.variable(site(t), 'i'), t[1]) if logging.show_porting: - report(PARRAY_I(site(t))) + report(P.ARRAY_I(site(t))) @prod_dml12 -def arraydef2(t): +def arraydef2_dml12(t): '''arraydef : ident IN expression DOTDOT expression''' if t[3].kind != 'int' or t[3].args != (0,): - report(EZRANGE(site(t, 3))) + report(E.ZRANGE(site(t, 3))) s = site(t) t[0] = (ast.variable(site(t, 1), t[1]), ast.binop(s, ast.int(s, 1), '+', t[5])) @@ -759,7 +760,7 @@ def arraydef2(t): # j in 0..expr-1 => j < expr remove_from = t[5].site new = '' - report(PARRAY(site(t, 2), site(t, 4), remove_from, + report(P.ARRAY(site(t, 2), site(t, 4), remove_from, end_site(t[5].site), new)) @prod_dml14 @@ -775,35 +776,35 @@ def arraydef_implicit(t): # Traits @prod_dml12 -def toplevel_trait(t): +def toplevel_trait_dml12(t): 'toplevel : TRAIT typeident maybe_istemplate LBRACE trait_stmts RBRACE' - report(WEXPERIMENTAL(site(t), 'traits')) + report(W.EXPERIMENTAL(site(t), 'traits')) t[0] = ast.template(site(t), t[2], t[3] + t[5]) @prod_dml12 -def trait_stmts_none(t): +def trait_stmts_none_dml12(t): '''trait_stmts : ''' fixup_emptyprod_lexpos(t) t[0] = [] @prod_dml12 -def trait_stmts(t): +def trait_stmts_dml12(t): '''trait_stmts : trait_stmts trait_stmt''' t[0] = t[1] + t[2] @prod_dml12 -def trait_stmt(t): +def trait_stmt_dml12(t): '''trait_stmt : trait_method | trait_param''' t[0] = [t[1]] @prod_dml12 -def trait_stmt_istemplate(t): +def trait_stmt_istemplate_dml12(t): '''trait_stmt : istemplate SEMI''' t[0] = [t[1]] @prod_dml12 -def trait_session(t): +def trait_session_dml12(t): # We don't support session variable initializers yet, because it's # not sufficiently obvious in what scope they should be evaluated. 'trait_stmt : SESSION named_cdecl SEMI' @@ -843,14 +844,14 @@ def template_statement_shared_hook(t): @prod_dml12 -def trait_template(t): +def trait_template_dml12(t): '''trait_stmt : TEMPLATE LBRACE object_statements RBRACE''' for stmt in t[3]: if stmt.kind == 'is': # 'is' in a trait block means the same as it would have # meant in its template block, and it's confusing to have # two syntaxes for the same thing. - report(EISINTPL(stmt.site)) + report(E.ISINTPL(stmt.site)) t[0] = t[3] @prod_dml14 @@ -864,7 +865,7 @@ def method_qualifiers(t): t[0] = list(itertools.islice(t, 1, None)) @prod_dml12 -def trait_method(t): +def trait_method_dml12(t): '''trait_method : METHOD shared_method''' (name, (inp, outp, throws), overridable, explicit_decl, body, rbrace_site) = t[2] @@ -886,7 +887,7 @@ def shared_method_final(t): t[0] = (t[1], t[2], False, t[3], t[4], lex_end_site(t, -1)) @prod_dml12 -def trait_param(t): +def trait_param_dml12(t): '''trait_param : PARAMETER named_cdecl SEMI''' (name, typ) = t[2].args t[0] = ast.param(site(t), name, ast.paramtype(t[2].site, typ), True, None) @@ -894,7 +895,7 @@ def trait_param(t): # Templates @prod_dml12 -def template(t): +def template_dml12(t): 'toplevel : TEMPLATE objident maybe_istemplate object_spec' t[0] = ast.template_dml12(site(t), t[2], t[3] + t[4]) @@ -905,7 +906,7 @@ def template(t): shared_methods = [s for s in t[5] if s.kind == 'sharedmethod'] stray_is = stray_is_check(t[5]) if not stray_is and ises and shared_methods: - report(WTEMPLATEIS(ises[0].site)) + report(W.TEMPLATEIS(ises[0].site)) t[0] = ast.template(site(t), t[2], t[3] + t[5]) # Header/footer @@ -939,10 +940,10 @@ def constant(t): 'toplevel : CONSTANT ident EQUALS expression SEMI' t[0] = ast.constant(site(t), t[2], t[4]) if logging.show_porting: - report(PCONSTANT(site(t))) + report(P.CONSTANT(site(t))) @prod_dml12 -def extern(t): +def extern_dml12(t): 'toplevel : EXTERN cdecl_maybe_discarded_or_ident SEMI' t[0] = ast.extern(site(t), cdecl_enforce_not_discarded(t[2])) @@ -962,10 +963,10 @@ def extern_typedef(t): t[0] = ast.extern_typedef(site(t), t[3]) @prod_dml12 -def top_struct(t): +def top_struct_dml12(t): 'toplevel : STRUCT ident LBRACE struct_decls RBRACE' if logging.show_porting: - report(PSTRUCTDECL(site(t, 1), site(t, 2), site(t, 5))) + report(P.STRUCTDECL(site(t, 1), site(t, 2), site(t, 5))) t[0] = ast.dml_typedef(site(t), ast.cdecl(site(t), t[2], [('struct', t[4])])) @@ -993,7 +994,7 @@ def maybe_extension_yes(t): 'maybe_extension : IN' if not site(t).provisional_enabled( provisional.explicit_object_extensions): - report(ESYNTAX(site(t), 'in', None)) + report(E.SYNTAX(site(t), 'in', None)) t[0] = None else: t[0] = True @@ -1010,7 +1011,7 @@ def maybe_extension_no(t): # may seem redundant, but no! Removing those uses would lead to shift/reduce # conflicts. @prod_dml12 -def maybe_extension(t): +def maybe_extension_dml12(t): 'maybe_extension : ' fixup_emptyprod_lexpos(t) t[0] = None @@ -1062,7 +1063,7 @@ def stray_is_check(body): if (other_stmt.kind == 'is' and (other_site.lineno == rough_end_site.lineno or other_site.colno > stmt.site.colno)): - report(WSTRAYIS(other_site, obj_type)) + report(W.STRAYIS(other_site, obj_type)) some_stray_is = True else: break @@ -1076,7 +1077,7 @@ def object_statement(t): '''object_statement : object_statement_or_typedparam''' if (t[1].kind == 'param' and t[1].args[1] is not None and t[1].args[1].kind == 'paramtype'): - report(ESYNTAX(t[1].args[1].site, None, + report(E.SYNTAX(t[1].args[1].site, None, 'parameter type declaration only permitted' + ' in top level template block')) # fallback: dummy statement @@ -1092,14 +1093,14 @@ def object_statement_bad_shared_method(t): @prod_dml14 def bad_shared_method(t): '''bad_shared_method : SHARED method_qualifiers METHOD shared_method''' - report(ESYNTAX(site(t), 'shared', + report(E.SYNTAX(site(t), 'shared', 'shared method declaration only permitted' + ' in top level template block')) # fallback: dummy statement t[0] = ast.hashif(site(t), ast.variable(site(t), 'false'), [], []) @prod_dml12 -def object_statement_or_typedparam(t): +def object_statement_or_typedparam_dml12(t): '''object_statement_or_typedparam : object | param | method @@ -1140,14 +1141,14 @@ def validate_if_body(stmts): result.append(stmt) else: assert stmt.kind in {'param', 'is'} - report(EBADCONDSTMT(stmt.site, stmt.kind)) + report(E.BADCONDSTMT(stmt.site, stmt.kind)) return result @prod_dml12 -def hashif(t): +def hashif_dml12(t): '''hashif : IF''' if logging.show_porting: - report(PHASH(site(t))) + report(P.HASH(site(t))) @prod_dml14 def hashif(t): @@ -1156,13 +1157,13 @@ def hashif(t): @prod_dml14 def hashif_nohash(t): '''hashif : IF''' - report(ESYNTAX(site(t), 'if', "invalid 'if', use '#if' in object context")) + report(E.SYNTAX(site(t), 'if', "invalid 'if', use '#if' in object context")) @prod_dml12 -def hashelse(t): +def hashelse_dml12(t): '''hashelse : ELSE''' if logging.show_porting: - report(PHASH(site(t))) + report(P.HASH(site(t))) @prod_dml14 def hashelse(t): @@ -1171,7 +1172,7 @@ def hashelse(t): @prod_dml14 def hashelse_nohash(t): '''hashelse : ELSE''' - report(ESYNTAX(site(t), 'else', "invalid 'else', use '#else'")) + report(E.SYNTAX(site(t), 'else', "invalid 'else', use '#else'")) @prod def object_if(t): @@ -1199,21 +1200,21 @@ def object_else_if(t): # Parameter specification @prod_dml12 -def object_parameter(t): +def object_parameter_dml12(t): '''param : PARAMETER objident paramspec_maybe_empty''' if logging.show_porting: - report(PPARAMETER(site(t))) + report(P.PARAMETER(site(t))) if logging.show_porting: if t[2] == 'hard_reset_value': - report(PHARD_RESET_VALUE(site(t, 2))) + report(P.HARD_RESET_VALUE(site(t, 2))) if t[2] == 'soft_reset_value' and not t[3][0]: - report(PSOFT_RESET_VALUE(site(t))) + report(P.SOFT_RESET_VALUE(site(t))) if t[2] == 'miss_pattern': - report(PMISS_PATTERN(site(t, 2))) + report(P.MISS_PATTERN(site(t, 2))) t[0] = ast.param(site(t), t[2], None, *t[3]) @prod_dml12 -def object_parameter_auto(t): +def object_parameter_auto_dml12(t): '''param : PARAMETER objident AUTO SEMI''' t[0] = ast.param(site(t), t[2], ast.auto(site(t, 3)), False, None) @@ -1232,7 +1233,7 @@ def object_param_walrus(t): '''param : PARAM objident COLON paramspec''' param_type = ast.walrus(site(t, 3)) if provisional.explicit_param_decls not in t.parser.file_info.provisional: - report(ESYNTAX(site(t, 3), ':', "expected '=' or 'default'")) + report(E.SYNTAX(site(t, 3), ':', "expected '=' or 'default'")) param_type = None t[0] = ast.param(site(t), t[2], param_type, *t[4]) @@ -1243,7 +1244,7 @@ def object_param_typed(t): if (value is not None and (provisional.explicit_param_decls not in t.parser.file_info.provisional)): - report(ESYNTAX(site(t, 5), 'default' if is_default else '=', + report(E.SYNTAX(site(t, 5), 'default' if is_default else '=', 'expected ;')) (is_default, value) = (True, None) t[0] = ast.param(site(t), t[2], ast.paramtype(site(t, 2), t[4]), @@ -1277,7 +1278,7 @@ def method_outparams_none(t): t[0] = [] @prod_dml12 -def method_outparams_some(t): +def method_outparams_some_dml12(t): 'method_outparams : ARROW LPAREN cdecl_maybe_discarded_or_ident_list RPAREN' cdecl_maybe_discarded_list_enforce_not_discarded(t[3]) t[0] = t[3] @@ -1290,7 +1291,7 @@ def method_outparams_some(t): # It would be logical to just use ESYNTAX here, but be nicer # because this is a very common mistake until 1.2 is # deprecated - report(ERETARGNAME( + report(E.RETARGNAME( psite, name.args[0] if name.kind == 'variable' else '_')) t[3][i] = ast.cdecl(psite, None, typ) t[0] = t[3] @@ -1305,7 +1306,7 @@ def cdecl_maybe_discarded_list_enforce_unnamed(decls): for (i, (kind, psite, name, typ)) in enumerate(decls): assert kind == 'cdecl_maybe_discarded' if name: - report(ESYNTAX( + report(E.SYNTAX( psite, name.args[0] if name.kind == 'variable' else '_', '')) decls[i] = ast.cdecl(psite, None, typ) @@ -1313,7 +1314,7 @@ def cdecl_maybe_discarded_list_enforce_named(decls): for (i, (kind, psite, name, typ)) in enumerate(decls): assert kind == 'cdecl_maybe_discarded', kind if not name: - report(ESYNTAX(psite, None, + report(E.SYNTAX(psite, None, 'name omitted in parameter declaration')) decls[i] = ast.cdecl_maybe_discarded( psite, @@ -1344,16 +1345,16 @@ def method_params_typed(t): t[0] = (t[2], t[4], t[5]) @prod_dml12 -def maybe_nothrow_throws(t): +def maybe_nothrow_throws_dml12(t): 'maybe_nothrow : ' fixup_emptyprod_lexpos(t) t[0] = True @prod_dml12 -def maybe_nothrow_nothrow(t): +def maybe_nothrow_nothrow_dml12(t): 'maybe_nothrow : NOTHROW' if logging.show_porting: - report(PNOTHROW(site(t))) + report(P.NOTHROW(site(t))) t[0] = False @prod @@ -1370,13 +1371,13 @@ def throws_not(t): # Method arguments @prod_dml12 -def returnargs_empty(t): +def returnargs_empty_dml12(t): 'returnargs : ' fixup_emptyprod_lexpos(t) t[0] = [] @prod_dml12 -def returnargs(t): +def returnargs_dml12(t): 'returnargs : ARROW LPAREN expression_list RPAREN' t[0] = t[3] @@ -1433,7 +1434,7 @@ def offsetspec_empty(t): # A C-like declaration, or a simple name @prod_dml12 -def cdecl_maybe_discarded_or_ident_decl(t): +def cdecl_maybe_discarded_or_ident_decl_dml12(t): '''cdecl_maybe_discarded_or_ident : cdecl_maybe_discarded''' (_, site, name, typ) = t[1] if name: @@ -1446,7 +1447,7 @@ def cdecl_maybe_discarded_or_ident_decl(t): ast.variable(site, typ[0]), None) else: - raise ESYNTAX(site, None, "missing parameter name") + raise E.SYNTAX(site, None, "missing parameter name") @prod_dml14 def cdecl_maybe_discarded_or_ident_decl(t): @@ -1469,7 +1470,7 @@ def named_cdecl_maybe_discarded(t): if name: t[0] = t[1] else: - report(ESYNTAX(site, None, "missing name in declaration")) + report(E.SYNTAX(site, None, "missing name in declaration")) t[0] = ast.cdecl_maybe_discarded(site, ast.variable(site, '_name_omitted'), typ) @@ -1507,14 +1508,14 @@ def basetype(t): t[0] = t[1] @prod_dml12 -def basetype(t): +def basetype_dml12(t): '''basetype : typeident | struct | layout | bitfields | typeof''' if logging.show_porting and t[1] == 'int1': - report(PINT1(site(t))) + report(P.INT1(site(t))) t[0] = t[1] @prod_dml14 @@ -1552,13 +1553,13 @@ def cdecl2_vect(t): if vsite.dml_version() != (1, 2): # defensively suppress warning in 1.2, for # compatibility - report(WEXPERIMENTAL(site(t), 'vect types')) + report(W.EXPERIMENTAL(site(t), 'vect types')) else: - report(EOLDVECT(site(t))) + report(E.OLDVECT(site(t))) t[0] = ['vect'] + t[2] @prod_dml12 -def cdecl3(t): +def cdecl3_dml12(t): # Madness! we actually allow the declaration 'local int int;'. # The declaration 'data int int;' is also accepted, but gives # invalid C code. @@ -1667,7 +1668,7 @@ def check_struct_namecoll(member_decls): continue (name,) = ident.args if name in sites_by_name: - report(ENAMECOLL(decl.site, sites_by_name[name], name)) + report(E.NAMECOLL(decl.site, sites_by_name[name], name)) else: sites_by_name[name] = decl.site @@ -1715,7 +1716,7 @@ def layout_decl(t): fields = t[4] check_struct_namecoll(fields) if endian not in {'big-endian', 'little-endian'}: - raise ESYNTAX(site(t, 2), '"%s"' % endian, + raise E.SYNTAX(site(t, 2), '"%s"' % endian, 'not one of "big-endian" or "little-endian"') t[0] = (endian, fields) @@ -1862,7 +1863,7 @@ def typeident(t): # expression @prod_dml12 -def expression_assign(t): +def expression_assign_dml12(t): 'expression : expression EQUALS expression' t[0] = ast.set(site(t, 2), t[1], t[3]) @@ -1881,7 +1882,7 @@ def assignop(t): t[0] = ast.assignop(site(t, 2), t[1], t[2], t[3]) @prod_dml12 -def expression_assignop(t): +def expression_assignop_dml12(t): '''expression : assignop''' (tgt, op, src) = t[1].args t[0] = ast.set(t[1].site, tgt, ast.binop(t[1].site, tgt, op[:-1], src)) @@ -1944,10 +1945,10 @@ def expression_unary_operator(t): t[0] = ast.unop(site(t), t[1], t[2]) @prod_dml12 -def expression_hash(t): +def expression_hash_dml12(t): '''expression : HASH expression''' if logging.show_porting: - report(PSTRINGIFY(site(t, 1), end_site(site(t, 2)))) + report(P.STRINGIFY(site(t, 1), end_site(site(t, 2)))) t[0] = ast.unop(site(t), "stringify", t[2]) @prod_dml14 @@ -1968,7 +1969,7 @@ def expression_postincdec(t): t[0] = ast.unop(site(t), 'post' + t[2], t[1]) @prod_dml12 -def application(t): +def application_dml12(t): 'expression : expression LPAREN expression_list RPAREN' t[0] = ast.apply( site(t), t[1], @@ -2009,7 +2010,7 @@ def utf8_string(t): try: t[0] = t[1].decode('utf-8') except UnicodeDecodeError as e: - raise ESYNTAX( + raise E.SYNTAX( site(t), repr(t), 'utf-8 decoding error: ' + e.reason) @@ -2020,14 +2021,14 @@ def expression_undefined(t): t[0] = ast.undefined(site(t)) @prod_dml12 -def expression_objectref(t): +def expression_objectref_dml12(t): 'expression : DOLLAR objident' t[0] = ast.objectref(site(t, 2), t[2]) if logging.show_porting: - report(PNODOLLAR(site(t, 1))) + report(P.NODOLLAR(site(t, 1))) @prod_dml12 -def expression_ident(t): +def expression_ident_dml12(t): '''expression : objident | DEFAULT''' t[0] = ast.variable_dml12(site(t), t[1]) @@ -2154,13 +2155,13 @@ def expression_list_many(t): # A comma-separated expression list. A trailing comma is NOT allowed. @prod_dml12 -def expression_list_ntc_empty(t): +def expression_list_ntc_empty_dml12(t): 'expression_list_ntc : ' fixup_emptyprod_lexpos(t) t[0] = [] @prod_dml12 -def expression_list_ntc_nonempty(t): +def expression_list_ntc_nonempty_dml12(t): 'expression_list_ntc : expression_list_ntc_nonempty' t[0] = t[1] @@ -2354,7 +2355,7 @@ def statement_do(t): # In DML 1.2, assignments are expressions, and pre/post actions are # expression lists. @prod_dml12 -def statement_for(t): +def statement_for_dml12(t): 'statement_except_hashif : FOR LPAREN expression_list_ntc SEMI expression_opt SEMI expression_list_ntc RPAREN statement' post = [ast.expression(e.site, e) for e in t[7]] t[0] = ast.for_(site(t), t[3], t[5], post, t[9]) @@ -2415,7 +2416,7 @@ def statement_for(t): s) @prod_dml12 -def statement_switch(t): +def statement_switch_dml12(t): 'statement_except_hashif : SWITCH LPAREN expression RPAREN statement' t[0] = ast.switch(site(t), t[3], t[5]) @@ -2469,12 +2470,12 @@ def statent_try(t): t[0] = ast.try_(site(t), t[2], t[4]) @prod_dml12 -def statement_delay(t): +def statement_delay_dml12(t): 'statement_except_hashif : AFTER LPAREN expression RPAREN CALL expression SEMI' if logging.show_porting: if t[6].kind != 'apply': - report(PINPARAMLIST(site(t, 7))) - report(PAFTER(site(t, 5), site(t, 6), site(t, 2), site(t, 4))) + report(P.INPARAMLIST(site(t, 7))) + report(P.AFTER(site(t, 5), site(t, 6), site(t, 2), site(t, 4))) t[0] = ast.after(site(t), 's', t[3], t[6]) @prod_dml14 @@ -2485,7 +2486,7 @@ def statement_delay(t): supported_units = ['s', 'ps', 'cycles'] if unit not in supported_units: suggestions = ' or '.join(f"'{unit}'" for unit in supported_units) - raise ESYNTAX(site(t, 3), t[3], + raise E.SYNTAX(site(t, 3), t[3], f"expected time unit ({suggestions})") t[0] = ast.after(site(t), unit, t[2], t[5]) @@ -2559,7 +2560,7 @@ def statement_delay_immediate(t): t[0] = ast.immediateafter(site(t), t[3]) @prod_dml12 -def call(t): +def call_dml12(t): '''statement_except_hashif : CALL expression returnargs SEMI | INLINE expression returnargs SEMI''' # This is a bit ugly. The 'expression' can be a function @@ -2574,12 +2575,12 @@ def call(t): inargs.append(init_ast.args[0]) else: if logging.show_porting: - report(PINPARAMLIST(site(t, 3))) + report(P.INPARAMLIST(site(t, 3))) method_ast = t[2] inargs = [] if logging.show_porting: - report(PINVOKE(site(t, 1), site(t, 2), site(t, 3), site(t, 4), + report(P.INVOKE(site(t, 1), site(t, 2), site(t, 3), site(t, 4), len(t[3]))) t[0] = ast.get(t[1])(site(t), method_ast, inargs, t[3]) @@ -2598,7 +2599,7 @@ def log_kind(t): | ERROR''' lt = log_types.get(t[1], None) if lt is None: - report(ELTYPE(site(t), t[1])) + report(E.LTYPE(site(t), t[1])) lt = 'info' t[0] = lt @@ -2614,15 +2615,15 @@ def log_level(t): old_log_types = set(log_types.values()) @prod_dml12 -def log_kind_old(t): +def log_kind_old_dml12(t): 'log_kind : utf8_sconst' lt = t[1] if lt not in old_log_types: - report(ELTYPE(site(t), t[1])) + report(E.LTYPE(site(t), t[1])) lt = 'info' if logging.show_porting: [newkind] = [k for k in log_types if log_types[k] == lt] - report(PLOGKIND(site(t, 1), '"%s"' % lt, newkind)) + report(P.LOGKIND(site(t, 1), '"%s"' % lt, newkind)) t[0] = lt @prod @@ -2657,10 +2658,10 @@ def statement_log_3(t): t[0] = ast.log(site(t), kind, level, later_level, flags, fmt, args) @prod_dml12 -def hashselect(t): +def hashselect_dml12(t): '''hashselect : SELECT''' if logging.show_porting: - report(PHASH(site(t))) + report(P.HASH(site(t))) @prod_dml14 def hashselect(t): @@ -2672,11 +2673,11 @@ def select(t): t[0] = ast.select(site(t), t[2], t[5], t[9], t[11], t[13]) @prod_dml12 -def foreach(t): +def foreach_dml12(t): 'statement_except_hashif : FOREACH ident IN LPAREN expression RPAREN statement' t[0] = ast.foreach_dml12(site(t), t[2], t[5], t[7]) if logging.show_porting: - report(PHASH(site(t))) + report(P.HASH(site(t))) @prod_dml14 def foreach(t): @@ -2689,17 +2690,17 @@ def hashforeach(t): t[0] = ast.hashforeach(site(t), t[2], t[5], t[7]) @prod_dml12 -def labeled_statement(t): +def labeled_statement_dml12(t): 'statement_except_hashif : ident COLON statement' t[0] = ast.label(site(t), t[1], t[3]) @prod_dml12 -def statement_case(t): +def statement_case_dml12(t): 'statement_except_hashif : CASE expression COLON statement' t[0] = ast.case_dml12(site(t), t[2], t[4]) @prod_dml12 -def statement_default(t): +def statement_default_dml12(t): 'statement_except_hashif : DEFAULT COLON statement' t[0] = ast.default_dml12(site(t), t[3]) @@ -2717,12 +2718,12 @@ def case_statement_default(t): def goto_statement(t): 'statement_except_hashif : GOTO ident SEMI' # Restricted goto should be implemented, see SIMICS-6130 - report(ESYNTAX(site(t), 'goto', + report(E.SYNTAX(site(t), 'goto', 'goto statements are not yet implemented in DML 1.4')) t[0] = ast.null(site(t)) @prod_dml12 -def goto_statement(t): +def goto_statement_dml12(t): 'statement_except_hashif : GOTO ident SEMI' t[0] = ast.goto(site(t), t[2]) @@ -2735,7 +2736,7 @@ def simple_statement(t): t[0] = ast.get(t[1])(site(t)) @prod_dml12 -def return_statement_noargs(t): +def return_statement_noargs_dml12(t): '''statement_except_hashif : RETURN SEMI''' t[0] = ast.return_dml12(site(t), []) @@ -2773,8 +2774,8 @@ def warning_statement(t): def warning_stmt(t): 'warning_stmt : _WARNING bracketed_string_literal SEMI' if breaking_changes.forbid_warning_statement.enabled: - raise ESYNTAX(site(t), '_warning', 'deprecated _warning statement') - report(WEXPERIMENTAL(site(t), "_warning statement")) + raise E.SYNTAX(site(t), '_warning', 'deprecated _warning statement') + report(W.EXPERIMENTAL(site(t), "_warning statement")) t[0] = ast.warning(site(t), t[2]) # Format arguments for log statements @@ -2812,10 +2813,10 @@ def statement_list_2(t): # local @prod_dml12 -def local_keyword_auto(t): +def local_keyword_auto_dml12(t): '''local_keyword : AUTO''' if logging.show_porting: - report(PAUTO(site(t))) + report(P.AUTO(site(t))) t[0] = 'local' @prod @@ -2829,10 +2830,10 @@ def static(t): t[0] = 'session' @prod_dml12 -def static(t): +def static_dml12(t): 'static : STATIC' if logging.show_porting: - report(PSESSION(site(t), 'static', 'session')) + report(P.SESSION(site(t), 'static', 'session')) t[0] = 'session' @prod @@ -2848,7 +2849,7 @@ def local_one(t): assert typ if not name: - raise ESYNTAX(tsite, ";", "variable name omitted") + raise E.SYNTAX(tsite, ";", "variable name omitted") if t[1] in {'session', 'saved'}: decl = cdecl_enforce_not_discarded(decl) @@ -2865,7 +2866,7 @@ def local_one_init(t): (_, _, name, typ) = decl = t[2] assert typ if not name: - raise ESYNTAX(site(t, 3), "=", "variable name omitted") + raise E.SYNTAX(site(t, 3), "=", "variable name omitted") if t[1] in {'session', 'saved'}: decl = cdecl_enforce_not_discarded(decl) @@ -2913,11 +2914,11 @@ def hook_decl(t): # Hook arrays are an internal feature, as their design depends on if we # are able to make hooks compound objects in the future if dml.globals.enable_testing_features: - report(WEXPERIMENTAL( + report(W.EXPERIMENTAL( site(t), "***FEATURE FOR INTERNAL TESTING***: hook arrays")) else: - report(ESYNTAX(site(t, 6), '[', '')) + report(E.SYNTAX(site(t, 6), '[', '')) t[0] = ast.hook(site(t), t[5], t[6], [typ for (_, _, _, typ) in t[3]]) @prod_dml14 @@ -2937,7 +2938,7 @@ def objident_list(t): # Object/parameter names may use some additional keywords for now... @prod_dml12 -def objident_base(t): +def objident_base_dml12(t): '''objident_base : ident | THIS | REGISTER @@ -2963,7 +2964,7 @@ def objident_discard(t): t[0] = '__' def discard_error(site): - report(ESYNTAX(site, + report(E.SYNTAX(site, "_", "can't use the name '_' (the discard identifier) in this " + "context. See the description of 'Identifiers' within " @@ -2994,7 +2995,7 @@ def ident_rule(idents): @prod_dml12 @lex.TOKEN(ident_rule(dmllex12.reserved_idents + ( 'ID', 'EACH', 'SESSION', 'SEQUENCE'))) -def ident(t): +def ident_dml12(t): t[0] = t[1] @prod_dml14 @@ -3012,13 +3013,13 @@ def ident(t): @prod_dml12 @lex.TOKEN(ident_rule(reserved_words_12)) -def reserved(t): - raise ESYNTAX(site(t, 1), str(t[1]), "reserved word") +def reserved_dml12(t): + raise E.SYNTAX(site(t, 1), str(t[1]), "reserved word") @prod_dml14 @lex.TOKEN(ident_rule(reserved_words_14)) def reserved(t): - raise ESYNTAX(site(t, 1), str(t[1]), "reserved word") + raise E.SYNTAX(site(t, 1), str(t[1]), "reserved word") # Error handling @prod @@ -3031,7 +3032,7 @@ def error(t): raise UnexpectedEOF() else: value = str(t.value) - raise ESYNTAX(DumpableSite(t.lexer.file_info, t.lexpos), value, None) + raise E.SYNTAX(logging.DumpableSite(t.lexer.file_info, t.lexpos), value, None) # Specific grammars to be passed to ply class Grammar(object): diff --git a/py/dml/messages.py b/py/dml/errors.py similarity index 60% rename from py/dml/messages.py rename to py/dml/errors.py index 5a277e0c1..80ce909e3 100644 --- a/py/dml/messages.py +++ b/py/dml/errors.py @@ -1,30 +1,9 @@ # © 2021 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): +from .logging import DMLError, ICE, truncate, binary_dump + +class AFTER(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 @@ -57,7 +36,7 @@ def log(self): + f"{p.typ}" for p in self.unserializable or [])) -class EAFTERSENDNOW(DMLError): +class AFTERSENDNOW(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 @@ -83,7 +62,7 @@ def __init__(self, site, target_hook, callback_hook, unserializable): DMLError.__init__(self, site, on_hook, callback_hook, callback_hook, clarification, unserializable_msg) -class EAFTERHOOK(DMLError): +class AFTERHOOK(DMLError): """ An illegal hook-bound `after` statement was specified. The number of message component parameters must be equal to the number of @@ -94,7 +73,7 @@ class EAFTERHOOK(DMLError): + 'hook has %d message components, but %d message component ' + 'parameters are given') -class EAFTERMSGCOMPPARAM(DMLError): +class AFTERMSGCOMPPARAM(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. @@ -103,7 +82,7 @@ class EAFTERMSGCOMPPARAM(DMLError): 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): +class HOOKTYPE(DMLError): """There are some minor restrictions to a hook's message component types. Anonymous structs and arrays of variable/unknown size are not supported. @@ -112,7 +91,7 @@ class EHOOKTYPE(DMLError): fmt = ("'%s' is a not a valid message component type for a hook, as it " "is or contains some %s") -class ECYCLICIMP(DMLError): +class CYCLICIMP(DMLError): """ A DML file imports itself, either directly or indirectly. """ @@ -125,7 +104,7 @@ def log(self): for site in self.other_sites: self.print_site_message(site, "via here") -class ECYCLICTEMPLATE(DMLError): +class CYCLICTEMPLATE(DMLError): """ A template inherits from itself, either directly or indirectly. """ @@ -138,7 +117,7 @@ def log(self): for site in self.other_sites: self.print_site_message(site, "via here") -class EAMBINH(DMLError): +class AMBINH(DMLError): """ If a method or parameter has multiple definitions, then there must be a unique definition that overrides all other definitions. @@ -185,7 +164,7 @@ def log(self): for (site, msg) in self.extra_lines: self.print_site_message(site, msg) -class EAMBDEFAULT(DMLError): +class AMBDEFAULT(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 @@ -200,7 +179,7 @@ def log(self): for site in self.default_sites: self.print_site_message(site, "default method candidate") -class EAMETH(DMLError): +class AMETH(DMLError): """ A shared abstract method cannot override another method. """ @@ -215,7 +194,7 @@ def log(self): self.print_site_message( self.prev_site, "previous declaration") -class ETMETH(DMLError): +class TMETH(DMLError): """ A shared method cannot override a non-shared method """ @@ -229,14 +208,14 @@ def log(self): self.print_site_message( self.trait_method_site, "shared method definition") -class ETEMPLATEUPCAST(DMLError): +class TEMPLATEUPCAST(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): +class ABSTEMPLATE(DMLError): """ If a template has any abstract methods or parameters, they must all be implemented when instantiating the template. @@ -251,14 +230,14 @@ def log(self): self.print_site_message( self.decl_site, "abstract declaration") -class EABSMETH(DMLError): +class ABSMETH(DMLError): """ An (abstractly) declared method never has any definition made for it. """ version = "1.4" fmt = "declared method %s is never implemented" -class EIMPORT(DMLError): +class IMPORT(DMLError): """ The file to imported could not be found. Use the `-I` option to specify additional directories to search for imported @@ -268,7 +247,7 @@ class EIMPORT(DMLError): def __init__(self, site, filename): DMLError.__init__(self, site, filename) -class ESIMAPI(DMLError): +class SIMAPI(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. @@ -277,19 +256,19 @@ class ESIMAPI(DMLError): def __init__(self, site, dml_ver, api_ver): DMLError.__init__(self, site, dml_ver, api_ver) -class ETYPE(DMLError): +class TYPE(DMLError): """ The data type is not defined in the DML code. """ fmt = "unknown type: '%s'" -class EVARTYPE(DMLError): +class VARTYPE(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): +class TREC(DMLError): """ The definition of a structure type can not have itself as direct or indirect member. @@ -303,7 +282,7 @@ def log(self): for site in self.other_sites: self.print_site_message(site, "via here") -class EANONSTRUCT(DMLError): +class ANONSTRUCT(DMLError): """ Declarations of new structs are not permitted in certain contexts, such as method arguments, `new` expressions, @@ -311,7 +290,7 @@ class EANONSTRUCT(DMLError): """ fmt = "struct declaration not allowed in a %s" -class EEMPTYSTRUCT(DMLError): +class EMPTYSTRUCT(DMLError): """ A struct or layout type must have at least one field. This restriction does not apply to structs declared in a @@ -319,7 +298,7 @@ class EEMPTYSTRUCT(DMLError): """ fmt = "struct or layout with no fields" -class ECAST(DMLError): +class CAST(DMLError): """ The cast operation was not allowed. It is illegal to cast to void. """ @@ -327,12 +306,12 @@ class ECAST(DMLError): def __init__(self, site, expr, type): DMLError.__init__(self, site, type) -class EVOID(DMLError): +class VOID(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): +class NBOOL(DMLError): """ Conditions must be properly boolean expressions; e.g., "`if (i == 0)`" is allowed, but "`if (i)`" is not, if `i` is an @@ -342,7 +321,7 @@ class ENBOOL(DMLError): def __init__(self, expr): DMLError.__init__(self, expr, expr, expr.ctype()) -class EASSIGN(DMLError): +class ASSIGN(DMLError): """ The target of the assignment is not an l-value, and thus cannot be assigned to. @@ -351,7 +330,7 @@ class EASSIGN(DMLError): def __init__(self, site, target): DMLError.__init__(self, site, target) -class EASTYPE(DMLError): +class ASTYPE(DMLError): """ The target of an initializer is incompatible with the type of the initializer. @@ -366,14 +345,14 @@ def __init__(self, site, target_type, source): site, source.ctype().describe(), target_type.describe_assign_types()) -class EINCTYPE(DMLError): +class INCTYPE(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): +class BTYPE(DMLError): """ An expression had the wrong type. """ @@ -381,20 +360,20 @@ class EBTYPE(DMLError): "got: %s\n" "expected: %s") -class ECSADD(DMLError): +class CSADD(DMLError): """ Non-constant strings cannot be concatenated using `+`. """ fmt = ("non-constant strings cannot be concatenated using '+'") -class EEARG(DMLError): +class EARG(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): +class ASSINL(DMLError): """ The target of the assignment is a method parameter that has been given a constant or undefined value when inlining the method. @@ -403,7 +382,7 @@ class EASSINL(DMLError): def __init__(self, site, name): DMLError.__init__(self, site, name) -class EERRSTMT(DMLError): +class ERRSTMT(DMLError): """ The source code contained a statement "`error;`", which forces a compilation error with the given message, or the standard message @@ -413,13 +392,13 @@ class EERRSTMT(DMLError): def __init__(self, site, msg): DMLError.__init__(self, site, msg) -class EEXTERN(DMLError): +class EXTERN(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): +class EXPORT(DMLError): """Can only export non-inline, non-shared, non-throwing methods declared outside object arrays.""" fmt = "cannot export this method" @@ -433,7 +412,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.export_site, "exported here") -class ESTATICEXPORT(DMLError): +class STATICEXPORT(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.""" @@ -449,7 +428,7 @@ def log(self): self.print_site_message(self.addressof_site, "attempted conversion here") -class EINVALID(DMLError): +class INVALID(DMLError): """ The expression does not produce a proper value. """ @@ -457,7 +436,7 @@ class EINVALID(DMLError): def __init__(self, expr): DMLError.__init__(self, expr, expr) -class EUNDEF(DMLError): +class UNDEF(DMLError): """ Caused by an attempt to generate code for an expression that contains the `undefined` value. @@ -468,20 +447,21 @@ def __init__(self, site, expr = None): expr = site DMLError.__init__(self, site, expr) -class ESHNEG(DMLError): +class SHNEG(DMLError): """ The right-hand side operand to a shift operator must not be negative. """ fmt = "shift with negative shift count: '%s" -class EDIVZ(DMLError): +class DIVZ(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): + +class BINOP(DMLError): """ One or both of the operands have the wrong type for the given binary operator. @@ -490,27 +470,27 @@ class EBINOP(DMLError): def __init__(self, site, op, lh, rh): DMLError.__init__(self, site, op, binary_dump(lh, rh)) -class EBSLICE(DMLError): +class BSLICE(DMLError): """ A bitslice operation was attempted on an expression that is not an integer. """ fmt = "illegal bitslice operation" -class EBSSIZE(DMLError): +class BSSIZE(DMLError): """ Bit slices cannot be larger than 64 bits. """ fmt = "bitslice size of %s bits is not between 1 and 64" -class EBSBE(DMLError): +class BSBE(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): +class ZRANGE(DMLError): """ An array index range must start at zero. """ @@ -518,7 +498,7 @@ class EZRANGE(DMLError): def __init__(self, site): DMLError.__init__(self, site) -class ENARRAY(DMLError): +class NARRAY(DMLError): """ Indexing can only be applied to arrays, integers (bit-slicing), and lists. @@ -527,7 +507,7 @@ class ENARRAY(DMLError): def __init__(self, expr): DMLError.__init__(self, expr, expr) -class EOOB(DMLError): +class OOB(DMLError): """ The used index is outside the defined range. """ @@ -535,19 +515,19 @@ class EOOB(DMLError): def __init__(self, expr): DMLError.__init__(self, expr) -class EAVAR(DMLError): +class AVAR(DMLError): """ Indexing into constant lists can only be done with constant indexes. """ fmt = "cannot use variable index in a constant list" -class ENLST(DMLError): +class NLST(DMLError): """ A list was expected. """ fmt = "not a list: %s" -class ENVAL(DMLError): +class NVAL(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 @@ -555,7 +535,7 @@ class ENVAL(DMLError): """ fmt = "not a value: %s" -class ENORET(DMLError): +class NORET(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 @@ -569,7 +549,7 @@ class ENORET(DMLError): version = "1.4" fmt = "missing return statement in method with output argument" -class EATYPE(DMLError): +class ATYPE(DMLError): """ Either the `attr_type` or the `type` parameter of the attribute must be specified. @@ -578,14 +558,14 @@ class EATYPE(DMLError): def __init__(self, attr): DMLError.__init__(self, attr, attr.identity()) -class EANAME(DMLError): +class ANAME(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): +class ACHK(DMLError): """ An attribute must have set and get methods to be checkpointable. This attribute has neither, and the @@ -593,13 +573,13 @@ class EACHK(DMLError): """ fmt = "checkpointable attribute missing set or get method" -class EANULL(DMLError): +class ANULL(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): +class REGVAL(DMLError): """ When a register has been specified with explicit fields, you have to use the `get` and `set` methods to access the register as @@ -609,7 +589,7 @@ class EREGVAL(DMLError): def __init__(self, site, reg): DMLError.__init__(self, site, reg.identity()) -class ENOPTR(DMLError): +class NOPTR(DMLError): """ A pointer value was expected. """ @@ -617,7 +597,7 @@ class ENOPTR(DMLError): def __init__(self, site, expr): DMLError.__init__(self, site, expr, expr.ctype().describe()) -class ENOSTRUCT(DMLError): +class NOSTRUCT(DMLError): """ The left-hand side operand of the `.` operator is not of struct type. @@ -626,13 +606,13 @@ class ENOSTRUCT(DMLError): def __init__(self, site, expr, ctype = None): DMLError.__init__(self, site, expr, ctype or expr.ctype()) -class EBADFAIL(DMLError): +class BADFAIL(DMLError): """ An exception is thrown in a context where it will not be caught. """ fmt = "uncaught exception" -class EBADFAIL_dml12(DMLError): +class BADFAIL_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 @@ -707,7 +687,7 @@ def all_errors(cls): yield cls(site, shortest_call_chains[m], cls.protected_calls[m][1:]) -class EAPPLY(DMLError): +class APPLY(DMLError): """ The applied value is not a function. """ @@ -718,7 +698,7 @@ def __init__(self, fun, ftype = None): ftype = fun.ctype() DMLError.__init__(self, fun, fun, ftype) -class EAPPLYMETH(DMLError): +class APPLYMETH(DMLError): """ Calls to inline methods, methods that may throw, or methods that have multiple output parameters cannot be used as arbitrary expressions. In DML @@ -738,7 +718,7 @@ def __init__(self, site, fun): + "of an assignment)") DMLError.__init__(self, site, fun, suggestion) -class EIDENT(DMLError): +class IDENT(DMLError): """ The identifier has not been declared anywhere. """ @@ -748,33 +728,33 @@ def __init__(self, site, name): DMLError.__init__(self, site, name) self.identifier = name -class ENAMEID(DMLError): +class NAMEID(DMLError): """ The name parameter does not follow identifier syntax. """ fmt = "invalid name parameter value: '%s'" -class EFORMAT(DMLError): +class FORMAT(DMLError): """ The log-statement format string is malformed. """ fmt = "malformed format string: unknown format at position %d" -class EDEVICE(DMLError): +class DEVICE(DMLError): """ The main source file given to the DML compiler must contain a `device` declaration. """ fmt = "missing device declaration" -class ELTYPE(DMLError): +class LTYPE(DMLError): """ Log-statement type must be one of `info`, `warning`, `error`, `spec_viol`, and `unimpl`. """ fmt = "invalid log type: '%s'" -class ELLEV(DMLError): +class LLEV(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 ...`), unless the log kind is @@ -783,7 +763,7 @@ class ELLEV(DMLError): """ fmt = "log level must be %s" -class ESYNTAX(DMLError): +class SYNTAX(DMLError): """ The code is malformed. """ @@ -800,13 +780,13 @@ def __init__(self, site, tokenstr, reason): reason = "" DMLError.__init__(self, site, where, reason) -class EPARAM(DMLError): +class PARAM(DMLError): """ The parameter is not bound to a legal value. """ fmt = "illegal value for parameter '%s'" -class EUNINITIALIZED(DMLError): +class UNINITIALIZED(DMLError): """ Some parameters that are automatically supplied by DML cannot be accessed in early stages of compilation, such as in object-level @@ -814,7 +794,7 @@ class EUNINITIALIZED(DMLError): """ fmt = "value of parameter %s is not yet initialized" -class EBADCONDSTMT(DMLError): +class BADCONDSTMT(DMLError): """ `#if` statements in object scope are only allowed to contain certain kinds of declarations: objects, `method`, `session`, @@ -833,7 +813,8 @@ class EBADCONDSTMT(DMLError): # 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): + +class ATTRDATA(DMLError): """ Specifying `allocate_type` and using 'data' declarations in the same attribute object is not allowed. @@ -851,7 +832,7 @@ def log(self): for data_site in self.data_sites: self.print_site_message(data_site, 'data object declared here') -class ERETTYPE(DMLError): +class RETTYPE(DMLError): """ The type of the return value (if any) must be specified for methods that implement interfaces. @@ -860,20 +841,20 @@ class ERETTYPE(DMLError): def __init__(self, meth): DMLError.__init__(self, meth) -class ERETARGNAME(DMLError): +class RETARGNAME(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): +class IFREF(DMLError): """ Interface function calls must be simple references to the method. """ fmt = "illegal interface method reference: %s" -class EREF(DMLError): +class REF(DMLError): """ The referenced object has not been declared. """ @@ -885,26 +866,26 @@ def __init__(self, site, name, obj = None): place = "%s.%s" % (obj, name) DMLError.__init__(self, site, place) -class ENOBJ(DMLError): +class NOBJ(DMLError): """ A reference to an object was expected. """ fmt = "object expected: %s" -class EFMTARGN(DMLError): +class FMTARGN(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): +class ASZVAR(DMLError): """ The size of an array must be a constant integer. """ fmt = "array upper bound is not a constant integer: %s" -class EASZR(DMLError): +class ASZR(DMLError): """ An array must have at least one element. """ @@ -912,7 +893,7 @@ class EASZR(DMLError): def __init__(self, site): DMLError.__init__(self, site) -class EASZLARGE(DMLError): +class ASZLARGE(DMLError): """ Object arrays with huge dimensions are not allowed; the product of dimension sizes must be smaller than 231. @@ -922,7 +903,7 @@ class EASZLARGE(DMLError): # signed 32-bit integer arithmetic on packed indices. fmt = f"array has too many elements (%d >= {2**31})" -class EAINCOMP(DMLError): +class AINCOMP(DMLError): """ The array has been declared more than once, in an incompatible way. """ @@ -935,40 +916,40 @@ def log(self): if self.othersite: self.print_site_message(self.othersite, "conflicting declaration") -class EAUNKDIMSIZE(DMLError): +class AUNKDIMSIZE(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%s is never defined") -class ENCONST(DMLError): +class NCONST(DMLError): """ A constant expression was expected. """ fmt = "non-constant expression: %s" -class ECONT(DMLError): +class CONT(DMLError): """ A `continue` statement can only be used inside a loop construct. """ fmt = "nothing to continue" -class ECONTU(DMLError): +class CONTU(DMLError): """ A `continue` statement cannot be used in a `#foreach` or `#select` statement. """ fmt = "continue is not possible here" -class EBREAK(DMLError): +class BREAK(DMLError): """ A `break` statement can only be used inside a loop or switch construct. """ fmt = "nothing to break from" -class ENMETH(DMLError): +class NMETH(DMLError): """ A method name was expected. This might be caused by using `call` or `inline` on something that counts as a C @@ -976,21 +957,21 @@ class ENMETH(DMLError): """ fmt = "not a method: '%s'" -class ENDEFAULT(DMLError): +class NDEFAULT(DMLError): """ The default implementation of a method was invoked, but there was no default implementation. """ fmt = "no default implementation" -class EARG(DMLError): +class ARG(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): +class RETLVALS(DMLError): """ The number of return value recipients differs from the number of values the called method returns. @@ -998,7 +979,7 @@ class ERETLVALS(DMLError): version = "1.4" fmt = "wrong number of return value recipients: Expected %d, got %d" -class ERETARGS(DMLError): +class RETARGS(DMLError): """ The number of return values in a return statement must match the number of outputs in the method. @@ -1006,13 +987,13 @@ class ERETARGS(DMLError): version = "1.4" fmt = "wrong number of return values: Expected %d, got %d" -class EARGD(DMLError): +class ARGD(DMLError): """ All parameter names of a method must be distinct. """ fmt = "duplicate method parameter name '%s'" -class EARGT(DMLError): +class ARGT(DMLError): """ The data type of the argument value given for the mentioned method parameter differs from the method definition. @@ -1032,7 +1013,7 @@ def __init__(self, site, invocation_type, method_name, direction, pref, invok, method_name, got_type, ptype) -class ENARGT(DMLError): +class NARGT(DMLError): """ Methods that are called must have data type declarations for all their parameters. (Methods that are only inlined do not need this.) @@ -1046,7 +1027,7 @@ def log(self): if self.callsite: self.print_site_message(self.callsite, "called from here") -class EPTYPE(DMLError): +class PTYPE(DMLError): """ The data type of the argument value given for the mentioned method or function parameter differs from the function prototype. @@ -1057,7 +1038,7 @@ class EPTYPE(DMLError): def __init__(self, site, arg, ptype, pref, kind): DMLError.__init__(self, site, pref, kind, arg.ctype(), ptype) -class ENAMECOLL(DMLError): +class NAMECOLL(DMLError): """ The name is already in use in the same scope. """ @@ -1070,7 +1051,7 @@ def log(self): if self.othersite: self.print_site_message(self.othersite, "conflicting definition") -class ENALLOW(DMLError): +class NALLOW(DMLError): """ Many object types have limitations on the contexts in which they may appear. @@ -1079,7 +1060,7 @@ class ENALLOW(DMLError): def __init__(self, site, parent): DMLError.__init__(self, site) -class ENALLOC(DMLError): +class NALLOC(DMLError): """ An object which is not allocated at run-time cannot be referenced as a run-time value. @@ -1088,7 +1069,7 @@ class ENALLOC(DMLError): def __init__(self, site, reg): DMLError.__init__(self, site, reg.identity()) -class ENTMPL(DMLError): +class NTMPL(DMLError): """ The template has not been defined. """ @@ -1099,7 +1080,7 @@ def __init__(self, site, name): raise ICE(site, 'missing template for ' + name[1:]) DMLError.__init__(self, site, name) -class EISINTPL(DMLError): +class ISINTPL(DMLError): """ A `template` block inside a `trait` block may not contain any `is` statements on top level. Templates should be @@ -1111,7 +1092,7 @@ class EISINTPL(DMLError): fmt = ("'is' statement forbidden for template block inside trait;" + " please move to surrounding trait block") -class EINVOVER(DMLError): +class INVOVER(DMLError): """ Only default declarations of parameters can be overridden. """ @@ -1123,7 +1104,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.non_default_site, "overridden assignment") -class ENPARAM(DMLError): +class NPARAM(DMLError): """ The parameter has been declared, but is not assigned a value or a default value. @@ -1132,13 +1113,13 @@ class ENPARAM(DMLError): def __init__(self, site, name): DMLError.__init__(self, site, name) -class EAUTOPARAM(DMLError): +class AUTOPARAM(DMLError): """Some parameters are predefined by DML, using the `auto` keyword. Such parameters may only be declared by the standard library, and they may not be overridden.""" fmt = "bad declaration of automatic parameter '%s'" -class ENOVERRIDEPARAM(DMLError): +class NOVERRIDEPARAM(DMLError): """When the `explict_param_decls` provisional feature is enabled, parameter definitions written using `=` and `default` are only accepted if the parameter has already been declared. @@ -1158,8 +1139,7 @@ def log(self): prov_site, "enabled by the explicit_param_decls provisional feature") - -class EOVERRIDEPARAM(DMLError): +class OVERRIDEPARAM(DMLError): """When the `explict_param_decls` provisional feature is enabled, any parameter declared via `:=` or `:default` may not already have been declared. This means `:=` or `:default` syntax can't be used @@ -1176,8 +1156,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.other_site, "existing declaration") - -class EEXTENSION(DMLError): +class EXTENSION(DMLError): """When the [`explicit_object_extensions` provisional feature](provisional-auto.html#explicit_object_extensions) is enabled, any object definition made via `in` syntax is considered an extension such @@ -1190,7 +1169,7 @@ class EEXTENSION(DMLError): fmt = ("object '%s' not declared elsewhere." " To declare and define a new object, omit 'in'.") -class EMULTIOBJDECL(DMLError): +class MULTIOBJDECL(DMLError): """When the [`explicit_object_extensions` provisional feature](provisional-auto.html#explicit_object_extensions) is enabled, any object declaration not made using `in` syntax is considered a @@ -1215,13 +1194,13 @@ def log(self): prov_site, "enabled by the explicit_object_extensions provisional feature") -class EVARPARAM(DMLError): +class VARPARAM(DMLError): """ The value assigned to the parameter is not a well-defined constant. """ fmt = "non-constant parameter, or circular parameter dependencies: '%s'" -class ERECPARAM(DMLError): +class RECPARAM(DMLError): """ The value of a parameter may not reference the parameter itself, neither directly nor indirectly. @@ -1235,7 +1214,7 @@ def log(self): for site in self.other_sites: self.print_site_message(site, "via here") -class EIDXVAR(DMLError): +class IDXVAR(DMLError): """Expressions that are evaluated statically to constants cannot have different values for different elements in a register array. This includes, for instance, the `allocate` parameter in @@ -1245,26 +1224,26 @@ class EIDXVAR(DMLError): def __init__(self, site, var): DMLError.__init__(self, site, var) -class EINDEPENDENTVIOL(DMLError): +class INDEPENDENTVIOL(DMLError): """Expressions that depend on values stored in a device instance cannot be evaluated in contexts where the device instance is not available. This is within static contexts — for example when initializing typed template parameters — or within independent methods.""" fmt = "cannot access device instance in device independent context" -class ETYPEDPARAMVIOL(DMLError): +class TYPEDPARAMVIOL(DMLError): """Independent method calls are not allowed within the definitions of typed parameters.""" fmt = ("typed parameter definitions may not contain independent methods " + "calls") -class EFARRSZ(DMLError): +class FARRSZ(DMLError): """ The bit width must be identical across the elements of a field array. """ fmt = "heterogeneous bitsize in field array" -class EDVAR(DMLError): +class DVAR(DMLError): """ A local variable has more than one definition in the same code block. """ @@ -1277,7 +1256,7 @@ def log(self): if self.othersite: self.print_site_message(self.othersite, "conflicting definition") -class EDDEFMETH(DMLError): +class DDEFMETH(DMLError): """ If a method has two default implementations, then at least one of them must be defined in a template. @@ -1290,7 +1269,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.othersite, "conflicting definition") -class EDMETH(DMLError): +class DMETH(DMLError): """ A method can only be overridden if it is declared as `default` """ @@ -1302,7 +1281,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.othersite, "conflicting definition") -class EMETH(DMLError): +class METH(DMLError): """ The default implementation is overridden by an implementation with different input/output parameters. @@ -1316,7 +1295,7 @@ def log(self): if self.othersite: self.print_site_message(self.othersite, "conflicting definition") -class ENOVERRIDEMETH(DMLError): +class NOVERRIDEMETH(DMLError): """When the `explict_method_decls` provisional feature is enabled, method definitions written using `{ ... }` and `default { ... }` are only accepted if the method has already been declared. @@ -1337,7 +1316,7 @@ def log(self): prov_site, "enabled by the explicit_method_decls provisional feature") -class EOVERRIDEMETH(DMLError): +class OVERRIDEMETH(DMLError): """When the `explict_method_decls` provisional feature is enabled, any method declared via `:{ ... }` or `:default { ... }` may not already have been declared. This means `:{ ... }` or `:default { ... }` syntax @@ -1354,7 +1333,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.other_site, "existing declaration") -class EIMPLMEMBER(DMLError): +class IMPLMEMBER(DMLError): """ A method in an `implement` object corresponds to a struct member that isn't a function pointer @@ -1367,7 +1346,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.othersite, "interface struct definition") -class EANONPORT(DMLError): +class ANONPORT(DMLError): """ An `implement` definition can only exist in a port or bank that has a name. @@ -1381,7 +1360,7 @@ def log(self): self.print_site_message(self.port.site, "this is the %s" % self.port.objtype) -class EDBFUNC(DMLError): +class DBFUNC(DMLError): """ The device contains two differently-named banks that use the same function number. @@ -1395,7 +1374,7 @@ def log(self): if self.othersite: self.print_site_message(self.othersite.site, "conflicting bank") -class EREGNSZ(DMLError): +class REGNSZ(DMLError): """ All registers must have a specified constant size. """ @@ -1403,7 +1382,7 @@ class EREGNSZ(DMLError): def __init__(self, reg): DMLError.__init__(self, reg, reg.identity()) -class EREGISZ(DMLError): +class REGISZ(DMLError): """ The specified register size is not allowed. Possible values are 1-8. """ @@ -1411,7 +1390,7 @@ class EREGISZ(DMLError): def __init__(self, reg): DMLError.__init__(self, reg, reg.identity()) -class EREGOL(DMLError): +class REGOL(DMLError): """ The registers are mapped to overlapping address ranges. """ @@ -1426,7 +1405,7 @@ def log(self): self.other.site, "register %s defined here" % (self.other.identity())) -class EBITRR(DMLError): +class BITRR(DMLError): """ The bit range of a field can only use bits present in the register. @@ -1435,7 +1414,7 @@ class EBITRR(DMLError): def __init__(self, f): DMLError.__init__(self, f, f.identity()) -class EBITRO(DMLError): +class BITRO(DMLError): """ The fields of a register must not overlap. """ @@ -1450,7 +1429,7 @@ def log(self): self.other.site, "field %s defined here" % (self.other.identity(),)) -class EBITRN(DMLError): +class BITRN(DMLError): """ The size of the bit range must be positive. Note that the [msb:lsb] syntax requires that the most significant bit (msb) is written to the @@ -1460,27 +1439,27 @@ class EBITRN(DMLError): def __init__(self, f, low, high): DMLError.__init__(self, f, low, high, f.identity()) -class EBITO(DMLError): +class BITO(DMLError): """ The specified bit-order is not allowed. """ fmt = "illegal bitorder: '%s'" -class EDEVIMP(DMLError): +class DEVIMP(DMLError): """ Source files that are used with `import` directives may not contain `device` declarations. """ fmt = "cannot import file containing device declaration" -class EIMPRET(DMLError): +class IMPRET(DMLError): """ Methods within an `interface` declaration may have only have zero or one output parameter. """ fmt = "more than one output parameter not allowed in interface methods" -class ERECUR(DMLError): +class RECUR(DMLError): """ Methods may not be inlined recursively. """ @@ -1488,14 +1467,14 @@ class ERECUR(DMLError): def __init__(self, site, method): DMLError.__init__(self, site, method.identity()) -class ECONSTP(DMLError): +class CONSTP(DMLError): """ C function called with a pointer to a constant value for a parameter declared without const in the prototype. """ fmt = "passing const reference for nonconst parameter %s in %s" -class ECONST(DMLError): +class CONST(DMLError): """ The lvalue that is assigned to is declared as a `const` and thus can't be assigned to. @@ -1504,26 +1483,26 @@ class ECONST(DMLError): def __init__(self, site): DMLError.__init__(self, site); -class EFUNSTRUCT(DMLError): +class FUNSTRUCT(DMLError): """ A member of a struct cannot have a function type. """ fmt = "struct member is a function" -class EFUNARRAY(DMLError): +class FUNARRAY(DMLError): """ It is illegal to express an array type where the base type is a function type. """ fmt = "illegal type: array of functions" -class ECONSTFUN(DMLError): +class CONSTFUN(DMLError): """ A function type cannot be `const` qualified; """ fmt = "const qualified function type" -class EDISCONST(DMLError): +class DISCONST(DMLError): """ A pointer to a constant value has been assigned to a pointer to a non-constant. @@ -1532,7 +1511,7 @@ class EDISCONST(DMLError): def __init__(self, site): DMLError.__init__(self, site); -class EFMTARGT(DMLError): +class FMTARGT(DMLError): """ Argument type mismatch in a log-statement format string. """ @@ -1541,7 +1520,7 @@ class EFMTARGT(DMLError): def __init__(self, site, expr, n, expected): DMLError.__init__(self, site, n, expr, expected, expr.ctype()) -class EILLCOMP(DMLError): +class ILLCOMP(DMLError): """ The values being compared do not have matching types. """ @@ -1553,7 +1532,7 @@ def __init__(self, site, expr1, typ1, expr2, typ2): truncate(str(expr1), 10), typ1, truncate(str(expr2), 10), typ2) -class EARRAY(DMLError): +class ARRAY(DMLError): """ A whole array cannot be used as a single value. """ @@ -1561,7 +1540,7 @@ class EARRAY(DMLError): def __init__(self, site, a): DMLError.__init__(self, site, a) -class EMEMBER(DMLError): +class MEMBER(DMLError): """ Attempt to access a nonexisting member of a compound data structure. """ @@ -1569,13 +1548,13 @@ class EMEMBER(DMLError): def __init__(self, site, expr, member): DMLError.__init__(self, site, expr, member) -class EIFTYPE(DMLError): +class IFTYPE(DMLError): """ The interface datatype is unknown. """ fmt = "unknown interface type: %s" -class EVERS(DMLError): +class VERS(DMLError): """ A device declared to be written in one DML language version tried to import a file written in an incompatible language version. @@ -1588,7 +1567,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.impsite, "imported here") -class ELAYOUT(DMLError): +class LAYOUT(DMLError): """ The type of a member of a `layout` declaration must be an integer or bitfield with a bit width that is a multiple of 8, or another layout. @@ -1597,7 +1576,7 @@ class ELAYOUT(DMLError): def __init__(self, site, msg): DMLError.__init__(self, site, msg) -class EBFLD(DMLError): +class BFLD(DMLError): """ A `bitfield` declaration must have an integer type that matches the width of the field. @@ -1606,21 +1585,21 @@ class EBFLD(DMLError): def __init__(self, site, msg): DMLError.__init__(self, site, msg) -class EINTPTRTYPE(DMLError): +class INTPTRTYPE(DMLError): """ Pointer types that point to integers with a bit width that is not a power of two are not allowed. """ fmt = "illegal pointer type: %s" -class ERVAL(DMLError): +class RVAL(DMLError): """ The operand of `sizeof`, `typeof` and `&` must be a lvalue. """ fmt = "operand of '%s' is not an lvalue" -class EINC(DMLError): +class INC(DMLError): """ An increment or decrement operation can only be performed on simple lvalues such as variables. @@ -1634,26 +1613,26 @@ def log(self): self.print_site_message(self.site, self.hint) fmt = "illegal increment/decrement operation" -class ENTYPE(DMLError): +class NTYPE(DMLError): """ This expression has an unknown type. """ fmt = "unknown type of expression" -class EDATAINIT(DMLError): +class DATAINIT(DMLError): """ An invalid initializer was detected. The error message provides the detailed information. """ fmt = "invalid data initializer: %s" -class ENOFILE(DMLError): +class NOFILE(DMLError): """ The main input file could not be found. """ fmt = "file not found" -class ENSHARED(DMLError): +class NSHARED(DMLError): """If a template provides an object that is not accessible from shared methods, such as an untyped parameter or a non-shared method, then that object's name is reserved within the scope of the shared @@ -1673,14 +1652,14 @@ def log(self): if self.decl_site: self.print_site_message(self.decl_site, "declared here") -class ESERIALIZE(DMLError): +class SERIALIZE(DMLError): """Some complex types, in particular most pointer types, cannot be automatically checkpointed by DML, and are therefore disallowed in contexts such as `saved` declarations. """ fmt = "unserializable type: %s" -class EATTRCOLL(DMLError): +class ATTRCOLL(DMLError): """ This error is signalled if two DML declarations would result in two Simics attributes being registered with the same name. @@ -1700,31 +1679,31 @@ def log(self): DMLError.log(self) self.print_site_message(self.othersite, "conflicting definition") -class ESTOREDINLINE(DMLError): +class STOREDINLINE(DMLError): """You cannot declare session or saved variables in methods marked with 'inline'""" fmt = "Cannot declare '%s' variable in an inline method" -class ESWITCH(DMLError): +class SWITCH(DMLError): """A switch statement must start with a `case` label, and there may be at most one `default` label which must appear after all `case` labels""" fmt = "malformed switch statement: %s" -class EVLALEN(DMLError): +class VLALEN(DMLError): """ .len cannot be used with variable-length arrays """ fmt = "'.len' cannot be used with variable-length arrays" -class ESAVEDCONST(DMLError): +class SAVEDCONST(DMLError): """ Declaring a saved variable with a type that is (partially) const-qualified is not allowed, as they can be modified due to checkpoint restoration. """ fmt = "saved variable declared with (partially) const-qualified type %s" -class EVLACONST(DMLError): +class VLACONST(DMLError): """ Variable length arrays may not be declared const-qualified or with a base type that is (partially) const-qualified. @@ -1732,7 +1711,7 @@ class EVLACONST(DMLError): fmt = ("variable length array declared with (partially) const-qualified " + "type") -class EIDENTSIZEOF(DMLError): +class IDENTSIZEOF(DMLError): """ A variant of the EIDENT message exclusive to usages of `sizeof`: it is emitted when the operand of `sizeof` makes use of an identifier which is @@ -1745,7 +1724,7 @@ class EIDENTSIZEOF(DMLError): def __init__(self, site, identifier): DMLError.__init__(self, site, identifier, identifier) -class ELOGGROUPS(DMLError): +class LOGGROUPS(DMLError): """ Too many log groups were declared. A device may have a maximum of 63 `loggroup` declarations (61 excluding the built-in `Register_Read` and @@ -1754,21 +1733,19 @@ class ELOGGROUPS(DMLError): fmt = ("Too many loggroup declarations. A maximum of 63 log groups (61 " + "excluding builtins) may be declared per device.") - -class ENOPROV(DMLError): +class NOPROV(DMLError): """ An invalid identifier was passed in the `provisional` statement. """ fmt = "No such provisional feature %s. Valid values are: %s" - -class ETQMIC(DMLError): +class TQMIC(DMLError): """A template-qualified method implementation call can only be done if the specified template is actually instantiated by the object.""" fmt = ("invalid template-qualified method implementation call, '%s' does " + "not instantiate '%s'") -class EAMBTQMIC(DMLError): +class AMBTQMIC(DMLError): """A template-qualified method implementation call was made, when the template inheritance graph for specified template is insufficient to infer that one implementation overrides the others. @@ -1796,7 +1773,7 @@ def log(self): "implementation candidate provided by ancestor template " + f"'{ancestor.name}'") -class EMEMBERTQMIC(DMLError): +class MEMBERTQMIC(DMLError): """A template-qualified method implementation call can only be done if the specified template actually does provide or inherit an implementation of the named method for the object instantiating the template. That the @@ -1827,8 +1804,7 @@ def log(self): DMLError.log(self) self.print_site_message(self.template.site, "template declaration") - -class ENSHAREDTQMIC(DMLError): +class NSHAREDTQMIC(DMLError): """ A template-qualified method implementation call via a value of template type, including when `this.templates` is used within the body of a @@ -1941,7 +1917,7 @@ class ENSHAREDTQMIC(DMLError): + "value of template type: '%s' does not provide nor inherit a " + "shared implementation of '%s'") -class ETTQMIC(DMLError): +class TTQMIC(DMLError): """A template-qualified method implementation call via a value of template type, including when `this.templates` is used within the body of a `shared` method, can only be done if the specified template is an ancestor template @@ -1951,7 +1927,7 @@ class ETTQMIC(DMLError): fmt = ("invalid template-qualified method implementation call, " + "'%s' not a subtemplate of '%s'") -class EEXTERNINCOMP(DMLError): +class EXTERNINCOMP(DMLError): """Multiple `extern` declarations with mismatching types are given for the same identifier.""" fmt = "incompatible extern declarations for '%s': type mismatch" @@ -1970,18 +1946,18 @@ def log(self): "conflicting declaration, which specifies the type: " + self.other_type.describe()) -class EPRAGMA(DMLError): +class PRAGMA(DMLError): """ An unknown pragma was specified """ fmt = "Unknown pragma: %s" -class EOLDVECT(DMLError): +class OLDVECT(DMLError): """`vect` types are only permitted if the [`simics_util_vect` provisional feature](provisional-auto.html#simics_util_vect) is enabled.""" fmt = "declaration of vect type without simics_util_vect provisional" -class EDISCARDREF(DMLError): +class DISCARDREF(DMLError): """ The expression `_` resolves to the [discard reference](language.html#discard-reference), and can only be used as an @@ -1991,908 +1967,9 @@ class EDISCARDREF(DMLError): fmt = ("'_' can only be used as an assignment target " + "(to discard some value)") -# -# WARNINGS (keep these as few as possible) -# - -class WNOVER(DMLWarning): - """ - A DML file must start with a version statement, such as `dml 1.4;` - """ - fmt = "file has no version tag, assuming version 1.2" - -class WSHALL(DMLWarning): - """ - The result of the shift operation will always be zero. - (This warning is disabled by default.) - """ - fmt = "shifting away all data\n%s" - def __init__(self, node, lh, rh): - DMLWarning.__init__(self, node, binary_dump(lh, rh)) - -class WNDOC(DMLWarning): - """ - No documentation string was specified for the attribute. - (This warning is disabled by default.) - """ - fmt = "no documentation for '%s'" - def __init__(self, node, member): - DMLWarning.__init__(self, node, member) - -class WNSHORTDESC(DMLWarning): - """ - No short description string was specified using the 'desc' parameter. - (This warning is disabled by default.) - """ - fmt = "no 'desc' parameter specified for device" - def __init__(self, node): - DMLWarning.__init__(self, node) - -class WNDOCRA(DMLWarning): - """ - No documentation string was specified for a _required_ attribute. - """ - fmt = "no documentation for required attribute '%s'" - def __init__(self, node, member): - DMLWarning.__init__(self, node, member) - -class WNEGOFFS(DMLWarning): - """ - A negative integer expression is given as a register offset. - Register offsets are unsigned 64-bit numbers, which means that - a negative offset expression translates to a very large offset. - """ - fmt = "negative register offset: %d" - -class WUNUSED(DMLWarning): - """ - The object is not referenced anywhere. - (This warning is disabled by default.; it typically causes many false - warnings.) - """ - fmt = "unused: %s" - def __init__(self, obj): - DMLWarning.__init__(self, obj, obj.identity()) - -class WUNUSEDDEFAULT(DMLWarning): - """ - The object is not referenced anywhere but it matches a name of an - object automatically referenced in another scope. This is the same - as WUNUSED but only for known common errors and it will never be - emitted if WUNUSED is enabled. - """ - fmt = "unused: %s methods are not called automatically for %s objects in %s" - def __init__(self, obj): - DMLWarning.__init__(self, obj, obj.name, obj.parent.objtype, - obj.identity()) - -class WUNUSED_DML12(DMLWarning): - """A DML 1.4 file contains a method implementation that would override - a library method in DML 1.2, but which is not part of the DML 1.4 - library, because some methods have been renamed. For instance, - implementing `read_access` in a register makes no sense - in DML 1.4, because the method has been renamed to - `read_register`. - - If a DML 1.4 file contains common code that also is imported from - DML 1.2 devices, then it may need to implement methods like - `read_access` to get the right callbacks when compiled - for DML 1.2. Such implementations can be placed inside `#if - (dml_1_2) { }` blocks to avoid this warning. - """ - fmt = ("unused implementation of DML 1.2 method %s;" - + " enclose in #if (dml_1_2) ?") - def __init__(self, obj): - DMLWarning.__init__(self, obj, obj.name) - -class WDUPEVENT(DMLWarning): - """ - Two or more events will be checkpointed using the same name, which - means that the checkpoint cannot be safely read back. - """ - fmt = "duplicate event checkpoint names: %s" - def __init__(self, site, objlist): - DMLWarning.__init__(self, site, - ", ".join(dollar(self.site) + o.logname() - for o in objlist)) - -class WSIZEOFTYPE(DMLWarning): - """ - The 'sizeof' operator is used on a type name, but expects an - expression. Use the 'sizeoftype' operator for types. - """ - fmt = "sizeof on a type is not legal, use sizeoftype instead" - -class WDEPRECATED(DMLWarning): - """ - This part of the language is deprecated, usually because the - underlying support in Simics is deprecated. - """ - fmt = "deprecation: %s" - -class WEXPERIMENTAL(DMLWarning): - """ - This part of the language is experimental, and not yet officially - supported. Code relying on the feature may break without notice in - future releases. - """ - fmt = "Use of unsupported feature: %s" - def preprocess(self): - return super(WEXPERIMENTAL, self).preprocess() - -class WEXPERIMENTAL_UNMAPPED(WEXPERIMENTAL): - __doc__ = WEXPERIMENTAL.__doc__ - -class WCONFIDENTIAL(DMLWarning): - """ - The object's name/qname is used as part of an expression in a - context other than the log statement, which could potentially lead - to the leak of confidential information. - """ - fmt = "potential leak of confidential information" - def __init__(self, site): - DMLWarning.__init__(self, site) - -# Not used (see ctree.py class CopyData), not documented. -# class WASSIGN(DMLWarning): -# def __init__(self, site): -# DMLWarning.__init__(self, site, "cannot perform assignment") - -class WOLDAST(DMLWarning): - """ - A precompiled DML file has an old time-stamp. This may happen if a - user accidentally edits a DML file from the standard library. A - safe way to suppress the warning is to remove the outdated - `.dmlast` file. - """ - fmt = "Outdated AST file: %s" - def __init__(self, dmlfile): - DMLWarning.__init__(self, SimpleSite(dmlfile + ":0"), - dmlfile + "ast") - -class WWRNSTMT(DMLWarning): - """ - The source code contained a statement "`warning;`", which - causes a warning to be printed. - """ - fmt = "%s" - - # This message should be removed, SIMICS-9886 -class WREF(DMLWarning): - """An unused parameter refers to an object that has not been declared. - - This warning message will be replaced with a hard error in future - major versions of Simics. - """ - instances = [] - fmt = "unused parameter %s contains %s" - - def __init__(self, site, param, eref): - # message formatting hack is based on this assumption - assert eref.msg.startswith('reference to unknown object ') - DMLWarning.__init__(self, site, param, eref.msg) - -class WTEMPLATEIS(DMLWarning): - """In a template with methods marked `shared`, it is recommended that - other templates are instantiated on the same line""" - fmt = ("prefer 'is' statement outside template braces," - + " 'template ... is (x, y) {'") - -class WNOIS(DMLWarning): - """Many standard method overrides will only be recognized if a - template named like the method is also instantiated. For instance, - the method `set` in a field has no effect unless the - `set` template is instantiated. - """ - def __init__(self, site, name): - DMLWarning.__init__(self, site, name, name) - fmt = ("implementation of %s() without 'is %s' is ignored" - + " by the standard library") - -class WTHROWS_DML12(DMLWarning): - """In DML 1.2, a method is by default permitted to throw an exception, - while in DML 1.4, an annotation `throws` is required for that. - So, if a method without annotations is ported to DML 1.4, it will - no longer permit exceptions. If such method is overridden by - a DML 1.2 file, then a non-throwing method is overridden by a potentially - throwing method, which is normally a type error. However, this particular - case is reduced to this warning. If an exception is uncaught in the - override, then this will automatically be caught in runtime and - an error message will be printed. - """ - fmt = ("overriding non-throwing DML 1.4 method" - + " with throwing DML 1.2 method") - def __init__(self, site, other_site=None): - DMLWarning.__init__(self, site) - self.other_site = other_site - def log(self): - DMLWarning.log(self) - self.print_site_message( - self.other_site, - "original non-throwing declaration") - -class WNEGCONSTCOMP(DMLWarning): - """DML uses a special method when comparing an unsigned and signed integer, - meaning that comparing a negative constant to an unsigned integer always - has the same result, which is usually not the intended behaviour.""" - def __init__(self, site, expr, ty): - DMLWarning.__init__(self, site) - self.expr = expr - self.ty = ty - fmt = ("Comparing negative constant to unsigned integer has a constant " - + "result") - def log(self): - DMLError.log(self) - self.print_site_message( - self.expr.site, "Consider 'cast(%s, %s)'" % (self.expr, self.ty)) - -class WASTRUNC(DMLWarning): - """The source of an assignment is a constant value that can't fit in the - type of the target, and is thus truncated. This warning can be silenced by - explicitly casting the expression to the target type. - """ - fmt = ("The assignment source is a constant value which does not fit " - + "the assign target of type '%s', and will thus be truncated") - -class WREDUNDANTLEVEL(DMLWarning): - """`X then Y` log level syntax has no effect when the - first and subsequent levels are the same. - """ - def __init__(self, site): - DMLWarning.__init__(self, site) - fmt = ("'X then Y' log level has no effect when the levels are the same") - -class WTTYPEC(DMLWarning): - """ - The delay value provided to an `after` call is subject to - implicit type conversion which may be unexpected for certain types. - To silence this warning, explicitly cast the delay value to the expected - type. - """ - fmt = ("the time value of type '%s' is implicitly converted " - + "to the type '%s' expected by the specified time unit '%s'.") - -class WPCAST(DMLWarning): - """ - A pointer is cast to a base type which has incompatible representation - compared to the original. Accessing the pointed-to object via the new - pointer type will almost certainly constitute undefined behavior. - - This warning is extremely limited in scope: don't rely on it to catch every - bad pointer cast. - - To silence this warning, first cast the pointer to `void *`, then cast it - to the desired type. - """ - fmt = ("very suspect pointer-to-pointer cast: the new base type has " - + "incompatible representation. This could lead to your code " - + "getting mangled by the C compiler, with unpredictable results.\n" - + "old base type: %s\n" - + "new base type: %s%s") - def __init__(self, site, old, new, maybe_intended): - suggestion = ('\nperhaps you meant the new base type to be ' - + maybe_intended.describe() - if maybe_intended else '') - DMLWarning.__init__(self, site, old, new, suggestion) - -class WLOGMIXUP(DMLWarning): - """ - - A specified log level of a `log` looks as though you meant to specify the - log groups instead, and/or vice versa. For example: - ``` - // Log group used as log level, when the intention is instead to - // specify log groups and implicitly use log level 1 - log spec_viol, some_log_group: ...; - - // Log groups and log level mistakenly specified in reverse order - log info, (some_log_group | another_log_group), 2: ...; - - // Log level used as log groups, when the intention is instead to - // specify the subsequent log level - log info, 2, 3: ...; - ``` - If you want to specify log groups, make sure to (explicitly) specify the - log level beforehand. If you want to specify the subsequent log level, use - `then` syntax. - ``` - log spec_viol, 1, some_log_group: ...; - log info, 2, (some_log_group | another_log_group): ...; - log info, 2 then 3: ...; - ``` - - This warning is only enabled by default with Simics API version 7 or above - (due to the breaking change `enable_WLOGMIXUP`.) - """ - fmt = ("log statement with likely misspecified log level(s) and log " - + "groups: %s") - def __init__(self, site, kind, level, later_level, groups): - suggestions = [] - from .codegen import probable_loggroups_specification, \ - probable_loglevel_specification - # There are three main scenarios for which we want to offer suggestions - # -- those covered in the docstring. All other scenarios either involve - # subsequent log levels -- at which point it's too difficult to guess - # what the user actually wanted to do -- or have no obvious fix that is - # not blatantly incorrect. - if probable_loggroups_specification(level): - if (not later_level - and not (groups.constant and not (1 <= groups.value <= 4))): - # Scenario 2: 'log info, 2, some_log_groups: ...;' - details = ("the specified log level and log groups look as " - + "though they are meant to be reversed.") - suggestions.append(f"log {kind}, {groups}, {level}: ...;") - else: - details = ("log group(s) and/or constant 0 are used as log " - + "level.") - if not later_level and groups.constant and groups.value == 0: - # Scenario 1: 'log info, some_log_groups: ...;' - suggestions.append(f"log {kind}, 1, {level}: ...;") - elif later_level and probable_loggroups_specification(later_level): - details = ("log group(s) and/or constant 0 are used as subsequent " - + "log level.") - else: - assert probable_loglevel_specification(groups) - details = "non-zero integer constant used as log groups." - if not later_level: - if site is None or site.dml_version != (1, 2): - # Scenario 3: 'log info, 2, 3: ...;' - suggestions.append( - f"log {kind}, {level} then {groups}: ...;") - if (not probable_loglevel_specification(level) - and not (groups.constant and groups.value == 5)): - # Scenario 2: 'log info, nonconstant, 3: ...;' - suggestions.append(f"log {kind}, {groups}, {level}: ...;") - - if suggestions: - details += (" Perhaps you meant%s:\n%s" - % (" one of the below"*(len(suggestions) > 1), - '\n'.join(suggestions))) - - DMLWarning.__init__(self, site, details) - -class WIMMAFTER(DMLWarning): - """ - An immediate `after` statement was specified where some argument to the - callback is a pointer to some stack-allocated data — i.e. a pointer - to data stored within a local variable. That data is guaranteed to be - invalid by the point the callback is called, which presents an enormous - security risk! - """ - version = "1.4" - fmt = ("***INCREDIBLY UNSAFE*** use of immediate 'after' statement: the " - + "callback argument '%s' is a pointer to stack-allocated data!") -class WHOOKSEND(DMLWarning): - """ - The `send` operation of a hook was called, and some provided message - component is a pointer to some stack-allocated data — i.e. a pointer - to data stored within a local variable. That data is guaranteed to be - invalid by the point the message is sent, which presents an enormous - security risk! - - If you must use pointers to stack-allocated data, then `send_now` should - be used instead of `send`. If you want the message to be delayed to avoid - ordering bugs, create a method which wraps the `send_now` call together - with the declarations of the local variable(s) which you need pointers to, - and then use immediate after (`after: m(...)`) to delay the call to that - method. - """ - version = "1.4" - fmt = ("***INCREDIBLY UNSAFE*** use of the 'send' operation of a hook: " - + "the message component '%s' is a pointer to stack-allocated " - + "data!\n" - + "Did you mean to use 'send_now' instead? See the Hook " - + "Declarations section in the DML 1.4 reference manual for " - + "information about the differences between 'send' and 'send_now'") - - -class WSTRAYIS(DMLWarning): - """ - A standalone `is` statement was found that looks like it was instead - intended to affect a preceding object declaration rather than the enclosing - object/template in which the `is` statement and (sub)object declaration are - made. - - This typically happens due to a stray semicolon before the `is`, e.g.: - ``` - field f @ [31:0]; is read_only; - ``` - or - ``` - field f @ [31:0]; - is read_only; - ``` - - If done unintentionally, address this warning by making the `is` part of - the declared object. If there is indeed a stray semicolon this can - typically be accomplished simply by removing it. - - If the standalone `is` statement is intentional, silence this warning - by making sure the `is` statement is on a new line separate from the object - declaration, and is not indented any deeper than the object declaration is. - """ - fmt = ("suspect standalone 'is': formatting suggests it was meant to " - + "affect the %s declared just before it rather than the " - + "enclosing object/template. " - + "Perhaps you have a stray ';' before the 'is'?") - -class PSHA1(PortingMessage): - """The `port-dml` script requires that the DML file has not been - changed since the tag file was generated. This is verified by a - SHA1 checksum.""" - fmt = 'SHA1 checksum of DML file' - -class PVERSION(PortingMessage): - """DML 1.4 files should start with `dml 1.4;` instead - of `dml 1.2;`""" - fmt = "update version statement to 1.4" - -class PNOTHROW(PortingMessage): - """In DML 1.4, it is assumed by default that a method may not throw an - exception. Any `nothrow` annotations must be removed.""" - fmt = "remove nothrow annotation" - -class PTHROWS(PortingMessage): - """In DML 1.4, methods that can throw an exception must explicitly - declare that with a 'throws' annotation. Such annotation is - automatically added for methods that override a throwing method - that was declared in a DML 1.4 file.""" - fmt = "add throws annotation" - -class PINPARAMLIST(PortingMessage): - """If a method has no input arguments, the empty input parameter - list `()` is now required in method declarations - and `call`/`inline` statements.""" - fmt = "add () after method" - -class PSTRUCTDECL(PortingMessage): - """Struct type definitions can no longer be declared using the - labeled struct syntax. The equivalent typedef declaration should - be used instead. For example, the following is now disallowed: - -
-    struct xyz { ... }
-    
- - and should be replaced with the following: - -
-    typedef struct { ... } xyz;
-    
""" - fmt = "use typedef syntax for struct type declaration" - -class PFIELDRANGE(PortingMessage): - """In a field declaration, the field range declaration must be - preceded by `@`. In DML 1.4, the syntax `field f[4]` - declares a field array of size 4, while in DML 1.2 it denotes a field - occupying bit 4 in its parent register.""" - fmt = "insert @ before field range declaration" - -class PINLINEDECL(PortingMessage): - """Methods with untyped parameters must be explicitly marked 'inline' - in DML 1.4, as in `inline method m(inline x) -> (int y)`""" - fmt = "add inline annotation to method with untyped parameters" - -class PRETVAL(PortingMessage): - """Method output parameters are not named in DML 1.4: - ``` - method m() -> (int, int) { - ... - } - ``` - - See also `PRETURNARGS`.""" - fmt = "remove name from method output parameter" - -class PRETVAL_END(PortingMessage): - """Methods with output arguments must end with an explicit return - statement in DML 1.4; in DML 1.2, the method would return whatever - value the output argument had upon exit. See also `PRETVAL`. - """ - fmt = "add return statement to end of method" - -class PRETURNARGS(PortingMessage): - """In methods with return values, return statements now take arguments: - ``` - method m() -> (int, int) { - return (1, 4); - } - method n() -> (int) { - return 3; - } - ```""" - fmt = "add arguments to return statement" - -class POUTARGRETURN(PortingMessage): - """An assignment to an output argument directly followed by a - return statement is more concisely written as a single return - statement, without an intermediate assignment. For instance, - ``` - dml 1.2; - method four() -> (int x) { - x = 4; - return; - } - ``` - can be expressed as: - ``` - dml 1.4; - method four() -> (int) { - return 4; - } - ``` - """ - fmt = "merge outarg assignment with return statement" - -class PTYPEDOUTPARAM(PortingMessage): - """Method output parameters must have explicit types in DML 1.4. The - automatic conversion script will convert untyped output parameters - to `uint64`.""" - fmt = "declare explicit type for output parameter" - -class PINARGTYPE(PortingMessage): - """When overriding a method in DML 1.4, the overriding and default - implementation must declare the same arguments as `inline`. - If the override has untyped arguments that are typed in the default - method, then the conversion script will add a type to the override's - argument. - - Note: The inserted type declaration uses C syntax, which in most - cases matches DML syntax; however, there are exceptions where the - inserted declaration will be broken and needs to be fixed manually. - """ - fmt = "" - -class PINVOKE(PortingMessage): - """Method invocation syntax changed. Replace - - ``` - call m(x) -> (a, b); - inline n() -> (c); - call o(); - ``` - with: - ``` - (a, b) = m(x); - c = n(); - o(); - ```""" - fmt = "Use assignment syntax for method invocation" - -class PLOGKIND(PortingMessage): - """In log statements, the old syntax where log type is denoted by a string - has been removed. Use the new identifier-based syntax instead. E.g., - instead of: - ``` - log "info": "foo"; - log "spec_violation": "foo"; - ``` - you must now write: - ``` - log info: "foo"; - log spec_viol: "foo"; - ``` -""" - fmt = "Don't use string literal syntax for log type" - -class PAFTER(PortingMessage): - """The syntax of `after` statements changed: The delay should - be followed by `s` to denote time unit; furthermore, the - `call` keyword should no longer be used, and brackets - around the delay are optional. Example: - ``` - after (1.3) call send_frame(); // DML 1.2 syntax - after 1.3 s: send_frame(); // DML 1.4 syntax - ```""" - fmt = "Remove 'call' and add 's' in 'after' statement" - -class PAUTO(PortingMessage): - """The `auto` keyword is deprecated; use the equivalent - `local` instead.""" - fmt = "replace 'auto' with 'local'" - -class PSESSION(PortingMessage): - """The `data` and `static` keywords have both been replaced - with `session`: - ``` - session uint32 x; - ```""" - fmt = "replace 'data' and 'static' with 'session'" - -class PHARD_RESET_VALUE(PortingMessage): - """The `hard_reset_value` parameter is no longer - recognized. The parameter is automatically renamed to - `init_val`, which has roughly the same effect.""" - fmt = "change hard_reset_value to init_val" - -class PSOFT_RESET_VALUE(PortingMessage): - """The `soft_reset_value` parameter is renamed to - `soft_reset_val`, and requires the template - `soft_reset_val` to be instantiated.""" - fmt = "change soft_reset_value to soft_reset_val" - -class PMISS_PATTERN(PortingMessage): - """The `miss_pattern` parameter is no longer recognized by - banks, unless the `miss_pattern_bank` template, from utility.dml, is - instantiated. An instantiation is automatically added.""" - fmt = "instantiate miss_pattern_bank to use the miss_pattern parameter" - -class PATTRIBUTE(PortingMessage): - """The `allocate_type` parameter is no longer valid for attributes. - Integer, boolean and floating-point attributes instead use - standard templates such as `uint64_attr`, `int64_attr`, `bool_attr` and - `double_attr`. - - The porting rule will remove `allocate_type`, together with an - explicit type parameter if present. All integer types will be - changed to 64-bit types. Attributes with `allocate_type="string"` - have to be manually rewritten. - """ - fmt = "use uint64_attr template instead of allocate_type parameter" - -class PEVENT(PortingMessage): - """Event objects no longer have the `timebase` parameter; - instead you must choose a standard template to instantiate. The - conversion script will pick `custom_time_event`, - `custom_cycle_event`, `simple_time_event`, or `simple_cycle_event`. - """ - -class PEVENT_NO_ARG(PortingMessage): - """When `PEVENT` converts an event to `simple_time_event` or - `simple_cycle_event`, the `data` function argument to methods - `post`, `posted`, `next` and `remove` are removed. - """ - -class PEVENT_UINT64_ARG(PortingMessage): - """When one of the methods `post`, `posted`, `next` and `remove` - is called with an integer value cast to a pointer in the `data` - arg, that event is converted to a `uint64_time_event` or - `uint64_cycle_event`. The converter removes the cast and - causes the event object to be converted to a - `uint64_time_event` instead of `uint64_custom_event`. - """ - -class PEVENT_REMOVE_INFO(PortingMessage): - """When an event is converted to a `uint64_time_event` or - `uint64_cycle_event`, the `set_event_info` and `get_event_info` methods - are removed. - """ - -class POVERRIDE(PortingMessage): - """If a method has exactly one default and one non-default - declaration, and the non-default declaration resides in a - template, then DML 1.4 requires that this template inherits from - the template containing the default declaration. Conversion is done - automatically for the most common case.""" - fmt = "template with method override must instantiate overridden template" - -class POVERRIDE_IMPORT(PortingMessage): - """Similar to POVERRIDE, but if a default method does _not_ - reside in a template, then the file that instantiates the non-default - declaration must import the file containing the default declaration.""" - fmt = "template with method override must import overridden file" - -# TODO: convert
-
-class PBEFAFT(PortingMessage):
-    """In objects of type attribute, register and connect, before/after
-    methods (e.g. `before_write`, `after_read`,
-    `after_set`), are no longer called. They are transformed
-    into an override of the corresponding base function
-    (`write_register`, `read_register`, `set`).
-    Note that when a before/after method is implemented by a template,
-    then an additional `is register` declaration may be needed in
-    1.4; this is not automatically added.
-    """
-    fmt = "before / after method no longer called, override base method instead"
-
-class PABSTRACT_TEMPLATE(PortingMessage):
-    """When implementing methods `read` or `write` in a
-    field or register, or `hard_reset` or
-    `soft_reset` in a bank, or `get`, `set`,
-    `read_field`, `write_field` in a field, then this will
-    have no effect unless a template named like the method is instantiated. The
-    automatic converter will add e.g. `is read;` before an
-    implementation of `read`."""
-    fmt = ("method has no effect unless corresponding abstract template is"
-           + " instantiated")
-
-class PTRAMPOLINE(PortingMessage):
-    """The methods `miss_read_access` and
-    `miss_write_access` in `bank` objects have been
-    renamed to `unmapped_read` and `unmapped_write`
-    in 1.4. The converter creates methods with the new names, which
-    call the existing unmodified methods."""
-    fmt = "method has been renamed in 1.4, will insert trampoline method"
-
-class PIMPORT_DML12COMPAT(PortingMessage):
-    """The `PTRAMPOLINE` porting rule sometimes requires
-    that `dml12-compatibility.dml` is imported."""
-    fmt = ''
-
-class PCHANGE_INARGS(PortingMessage):
-    """Many overridable methods in the standard library have changed, and
-    method overrides must be changed accordingly. A method in 1.2
-    usually has a counterpart in 1.4, but its semantics may have
-    changed slightly and quite often the set of arguments has changed
-    as well.  The automatic converter will adjust the names and
-    signatures of a number of methods. Invocations, including
-    `default()`, are not updated and must be manually converted
-    (compile errors). Some method arguments are removed by the
-    converter; if these arguments are used, the implementation must be
-    modified accordingly. In particular, the `memop` arg of
-    various bank and register methods is no longer present. This has
-    been replaced with an argument `void *aux`, which is
-    normally NULL.  If some register in a bank needs a memop, then the
-    `io_memory_access` method can be updated to pass down the
-    memop in the `aux` argument (just call `default`
-    with `memop` in the last arg). An explicit call to a bank
-    method, e.g. a redirection of an access to a different bank,
-    should normally be rewritten as a call to `read` or
-    `write`, usually with NULL in the `aux`
-    argument.
-
-    Bank methods are converted as follows: `access` →
-    `io_memory_access`; `read_access`,
-    `read_access_memop` → `read`;
-    `write_access`, `write_access_memop` →
-    `write`
-
-    Register methods are converted like so: `read_access`
-    → `read_register`, `write_access` →
-    `write_register`
-
-    Field methods are converted thusly: `read_access`
-    → `read_field`, `write_access` →
-    `write_field`
-
-    In `register` and `field` objects, the
-    `set` and
-    `write_register`/`write_field` methods will get
-    an explicit type `uint64`.
-
-    The read and write methods on `bank`, `register`,
-    and `field` objects all take a new `uint64` argument
-    denoting enabled bytes or bits, depending on the context, which
-    may mask an access.
-
-    In `connect` objects, `validate_port` is converted
-    to `validate`; named ports are deprecated in Simics 6, but
-    the port name is available in the `port` session variable.
-
-    In `attribute` objects, the `set` method will get
-    an explicit argument type `attr_value_t`, and a
-    `throws` annotation.
-    """
-    fmt = "override of library method with new name or signature"
-
-class PBITNEQ(PortingMessage):
-    """DML 1.2 permits using 1-bit fields as boolean values. In DML 1.4,
-    field values are 64 bit, and thus require an explicit `!= 0`"""
-    fmt = ""
-
-class PVAL(PortingMessage):
-    """The value of a `register`, `field` or `attribute`
-    object, and the interface struct of a `interface` object, is now
-    accessed through the `.val` member."""
-    fmt = "use .val member to access register/attribute value"
-
-class PNODOLLAR(PortingMessage):
-    """The `$` character is no longer needed when referencing objects."""
-    fmt = "remove $"
-
-class PDOLLAR_QUALIFY(PortingMessage):
-    """In DML 1.4, there is no separate scope for `$`, so local
-    variables can shadow object references. This conversion rule
-    attempts to detect this, and add `this.` or
-    dev.path. where needed."""
-    fmt = "use qualified object reference to escape shadowing"
-
-class PCONSTANT(PortingMessage):
-    """`constant` declarations are removed in 1.4 and should be
-    replaced with `param` declarations. Both are accessible
-    from the top-level scope of a device."""
-    fmt = "change 'constant' to 'param'"
-
-class PPARAMETER(PortingMessage):
-    """The `parameter` keyword has been renamed to `param`."""
-    fmt = "change 'parameter' to 'param'"
-
-class PARRAY_I(PortingMessage):
-    """The syntax for object arrays has changed: Instead of
-    `register r[12]`, you write `register r[i < 12]`"""
-    fmt = "explicit index in object array declaration"
-
-class PARRAY(PortingMessage):
-    """The syntax for object arrays has changed: Instead of
-    `register r[j in 0..size - 1]`, you write
-    `register r[j < size]`"""
-    fmt = "'<' replaces 'in 0..' in object array declaration"
-
-class PHASH(PortingMessage):
-    """`if` statements on top level must be prefixed with a `#`
-    character. The same applies to `if` statement inside a method body
-    if the condition is constant and the dead branch contains errors.
-
-    Similarly, the conditional operator (`? :`) is updated to #? #:
-    when needed, `select` is updated to `#select`, and
-    `foreach` is updated to `#foreach`."""
-    fmt = "insert '#' before 'if'"
-
-class PHASHELSE(PortingMessage):
-    """If an `if` is updated to `#if`, and there is a
-    corresponding `else` clause, then it must be updated to
-    `#else`. The same applies to the `else` clause in
-    `select` statements."""
-    fmt = "insert '#' before 'else'"
-
-class PANDOR(PortingMessage):
-    """DML 1.2 permits the right operand of an `&&` or
-    `||` expression to contain errors, as long as the left
-    operand evaluates to a constant that makes the right operand
-    dead. DML 1.4 does not permit this, so the expression `A
-    && B` must be converted to `A #? B #: false`.
-    One common use case is expressions like
-    `(defined X && X.y == ...)`.
-    """
-    fmt = ''
-
-class PIFAND(PortingMessage):
-    """If statements on the form `if (defined(X) && X.y) { ... }`
-    are converted to a nested `#if` statement"""
-    fmt = ''
-
-class PSTRINGIFY(PortingMessage):
-    """In DML 1.4, `#` is changed to the
-    `stringify` operator"""
-    fmt = "Replace '#(X)' with 'stringify(X)' operator"
-
-class PWUNUSED(PortingMessage):
-    """This message is used to signal to the porting script that a piece
-    of conditional code was not fully covered by the compile. Some
-    portings are never applied on dead code. The porting script
-    can signal a warning for this."""
-    fmt = ""
-    typed_methods = set()
-    # site -> objects.Method
-    inline_methods = {}
-    inlined_methods = set()
-    positive_conds = set()
-    negative_conds = set()
-    satisfied_conds = set()
-    used_templates = set()
-
-class PNO_WUNUSED(PortingMessage):
-    """Used in conjunction with PWUNUSED to signal that a piece of
-    conditional code was indeed used. If using multiple runs of DMLC
-    as input to the porting script, and a piece of code was used in
-    some runs and unused in others, then no warning is shown.
-    """
-    fmt = ""
-
-class PRENAME_TEMPLATE(PortingMessage):
-    """Some templates in `utility.dml` have been renamed; in
-    particular, `unimplemented` has been renamed to
-    `unimpl`.
-    """
-    fmt = ""
-
-class PUNDEFOFFS(PortingMessage):
-    """`undefined` is no longer a valid offset for registers; `unmapped_offset`
-    should be used instead.
-    """
-    fmt = "Use 'unmapped_offset' instead of 'undefined'"
-
-class PINT1(PortingMessage):
-    """Integer types have different semantics in DML 1.2 and DML 1.4;
-    the `int1` type in DML 1.2 is converted to `uint1` in DML 1.4
-    because that is a better match for some common operations. In
-    particular, if the value 1 is assigned to variables of these
-    types, then the value of the variable becomes 1, whereas for
-    `int1` in DML 1.4 the value is -1."""
-    fmt = "Change int1 to uint1"
-
-warnings = {name: cls for (name, cls) in globals().items()
-            if isinstance(cls, type) and issubclass(cls, DMLWarning)
-            and cls is not DMLWarning}
+all_errors = {
+    o.tag(): o for o in globals().values()
+    if isinstance(o, type)
+    and issubclass(o, DMLError)
+    and o is not DMLError}
diff --git a/py/dml/expr.py b/py/dml/expr.py
index d5a225494..80ea95ad3 100644
--- a/py/dml/expr.py
+++ b/py/dml/expr.py
@@ -4,13 +4,13 @@
 import abc
 
 import dml.globals
-from .logging import *
-from .messages import *
-from .output import *
-from .types import *
-from .slotsmeta import *
-
+from . import logging
+from .logging import ICE
+from . import errors as E
 from . import output
+from . import types as tp
+from .slotsmeta import SlotsMeta, auto_init
+
 
 __all__ = (
     'Code',
@@ -36,7 +36,7 @@ def __repr__(self):
                                     for name in self.init_args[2:]))
 
     def linemark(self):
-        site_linemark(self.site)
+        output.site_linemark(self.site)
 
 class Expression(Code):
     '''An Expression can represent either:
@@ -56,7 +56,7 @@ class Expression(Code):
     the composite expression.'''
     slots = ('context',)
 
-    # An instance of DMLType
+    # An instance of tp.DMLType
     #type = None
 
     # If true, this is a constant, with the value stored in .value, as
@@ -123,9 +123,9 @@ class Expression(Code):
     c_lval = False
 
     def __init__(self, site):
-        assert not site or isinstance(site, Site)
+        assert not site or isinstance(site, logging.Site)
         self.site = site
-        self.context = ErrorContext.current()
+        self.context = logging.ErrorContext.current()
 
     def __str__(self):
         "Format the expression in DML form"
@@ -137,7 +137,7 @@ def read(self):
 
     # Produce a C expression but don't worry about the value.
     def discard(self, explicit=False):
-        if not explicit or safe_realtype_shallow(self.ctype()).void:
+        if not explicit or tp.safe_realtype_shallow(self.ctype()).void:
             return self.read()
 
         if self.constant:
@@ -202,7 +202,7 @@ def apply(self, inits, location, scope):
         raise self.exc()
     def exc(self):
         '''Exception to raise when expression appears in an incorrect context'''
-        return ENVAL(self.site, self)
+        return E.NVAL(self.site, self)
 
 class NonValueArrayRef(NonValue):
     '''Reference to an array node before it's indexed. Indexing is the
@@ -215,7 +215,7 @@ def local_indices(self): pass
     def local_dimsizes(self): pass
 
     def exc(self):
-        return EARRAY(self.site, self)
+        return E.ARRAY(self.site, self)
 
 class Lit(Expression):
     "A literal C expression"
@@ -252,7 +252,7 @@ class NullConstant(Expression):
     constant = True
     value = None
     priority = 1000
-    type = TPtr(void, const=True)
+    type = tp.Ptr(tp.void, const=True)
     def __str__(self):
         return 'NULL'
     def read(self):
@@ -265,7 +265,7 @@ def copy(self, site):
 def typecheck_inargs(site, args, inp, kind="function", known_arglen=None):
     arglen = len(args) if known_arglen is None else known_arglen
     if arglen != len(inp):
-        raise EARG(site, kind)
+        raise E.ARG(site, kind)
 
     for (i, (arg, p)) in enumerate(zip(args, inp)):
         if kind == 'method':
@@ -274,18 +274,18 @@ def typecheck_inargs(site, args, inp, kind="function", known_arglen=None):
         else:
             (pname, ptype) = p
             logref = f"'{pname}'"
-        argtype = safe_realtype(arg.ctype())
+        argtype = tp.safe_realtype(arg.ctype())
         if not argtype:
             raise ICE(site, "unknown expression type")
 
-        rtype = safe_realtype(ptype)
+        rtype = tp.safe_realtype(ptype)
         assert rtype
         (ok, trunc, constviol) = rtype.canstore(argtype)
         if ok:
             if constviol:
-                raise ECONSTP(site, logref, kind + " call")
+                raise E.CONSTP(site, logref, kind + " call")
         else:
-            raise EPTYPE(site, arg, rtype, logref, kind)
+            raise E.PTYPE(site, arg, rtype, logref, kind)
 
 # Typecheck a DML method application, where the arguments are given as a list
 # where each element is either an AST of an initializer, or an initializer
@@ -296,7 +296,7 @@ def typecheck_inarg_inits(site, inits, inp, location, scope,
                           allow_undefined_args=False,
                           on_ptr_to_stack=None):
     if (not variadic and len(inits) != len(inp)) or len(inits) < len(inp):
-        raise EARG(site, kind)
+        raise E.ARG(site, kind)
 
     from .expr_util import coerce_if_eint
     from .codegen import eval_initializer, codegen_expression, \
@@ -319,19 +319,19 @@ def typecheck_inarg_inits(site, inits, inp, location, scope,
             else:
                 try:
                     arg = init.as_expr(ptype)
-                except EASTYPE as e:
+                except E.ASTYPE as e:
                     if e.site is init.site:
-                        raise EPTYPE(site, e.source, e.target_type, logref,
+                        raise E.PTYPE(site, e.source, e.target_type, logref,
                                      kind) from e
                     raise
                 # better error message
-                except EDISCONST as e:
+                except E.DISCONST as e:
                     if e.site is init.site:
-                        raise ECONSTP(site, logref, kind + " call") from e
+                        raise E.CONSTP(site, logref, kind + " call") from e
                     raise
         elif ptype is None:
             if init.kind != 'initializer_scalar':
-                raise ESYNTAX(init.site, '{',
+                raise E.SYNTAX(init.site, '{',
                               'the argument for an untyped parameter must be '
                               + 'a simple expression')
             arg = codegen_expression_maybe_nonvalue(init.args[0], location,
@@ -344,35 +344,35 @@ def typecheck_inarg_inits(site, inits, inp, location, scope,
             and init.kind == 'initializer_scalar'):
             arg = coerce_if_eint(codegen_expression(init.args[0],
                                                     location, scope))
-            argtype = safe_realtype(arg.ctype())
+            argtype = tp.safe_realtype(arg.ctype())
             if not argtype:
                 raise ICE(site, "unknown expression type")
 
-            rtype = safe_realtype(ptype)
+            rtype = tp.safe_realtype(ptype)
             assert rtype
             (ok, trunc, constviol) = rtype.canstore(argtype)
 
             if ok:
                 if constviol:
-                    raise ECONSTP(site, logref, kind + " call")
+                    raise E.CONSTP(site, logref, kind + " call")
             else:
-                raise EPTYPE(site, arg, rtype, logref, kind)
+                raise E.PTYPE(site, arg, rtype, logref, kind)
         else:
             try:
                 arg = eval_initializer(init.site, ptype, init, location,
                                        scope, False).as_expr(ptype)
-            except EASTYPE as e:
+            except E.ASTYPE as e:
                 if e.site is init.site:
-                    raise EPTYPE(site, e.source, e.target_type, logref,
+                    raise E.PTYPE(site, e.source, e.target_type, logref,
                                  kind) from e
                 raise
             # better error message
-            except EDISCONST as e:
+            except E.DISCONST as e:
                 if e.site is init.site:
-                    raise ECONSTP(site, logref, kind + " call") from e
+                    raise E.CONSTP(site, logref, kind + " call") from e
                 raise
         if (on_ptr_to_stack
-            and isinstance(safe_realtype_shallow(ptype), TPtr)
+            and isinstance(tp.safe_realtype_shallow(ptype), tp.Ptr)
             and arg.is_pointer_to_stack_allocation):
             on_ptr_to_stack(arg)
         args.append(arg)
@@ -380,7 +380,7 @@ def typecheck_inarg_inits(site, inits, inp, location, scope,
     if variadic and len(inits) > len(inp):
         for init in inits[len(inp):]:
             if init.kind != 'initializer_scalar':
-                raise ESYNTAX(init.site, '{',
+                raise E.SYNTAX(init.site, '{',
                               'variadic arguments must be simple expressions')
             args.append(coerce_if_eint(codegen_expression(init.args[0],
                                                           location, scope)))
@@ -407,18 +407,18 @@ def mkApplyInits(site, fun, inits, location, scope):
     funtype = fun.ctype()
 
     if not funtype:
-        raise EAPPLY(fun)
+        raise E.APPLY(fun)
 
     try:
-        funtype = realtype(funtype)
-        if isinstance(funtype, TPtr) and isinstance(funtype.base, TFunction):
+        funtype = tp.realtype(funtype)
+        if isinstance(funtype, tp.Ptr) and isinstance(funtype.base, tp.Function):
             # Pointers to functions are the same as the functions
-            funtype = realtype(funtype.base)
-    except DMLUnknownType:
-        raise ETYPE(site, funtype)
+            funtype = tp.realtype(funtype.base)
+    except tp.DMLUnknownType:
+        raise E.TYPE(site, funtype)
 
-    if not isinstance(funtype, TFunction):
-        raise EAPPLY(fun)
+    if not isinstance(funtype, tp.Function):
+        raise E.APPLY(fun)
 
     args = typecheck_inarg_inits(
         site, inits,
@@ -432,18 +432,18 @@ def mkApply(site, fun, args):
     funtype = fun.ctype()
 
     if not funtype:
-        raise EAPPLY(fun)
+        raise E.APPLY(fun)
 
     try:
-        funtype = realtype(funtype)
-        if isinstance(funtype, TPtr) and isinstance(funtype.base, TFunction):
+        funtype = tp.realtype(funtype)
+        if isinstance(funtype, tp.Ptr) and isinstance(funtype.base, tp.Function):
             # Pointers to functions are the same as the functions
-            funtype = realtype(funtype.base)
-    except DMLUnknownType:
-        raise ETYPE(site, funtype)
+            funtype = tp.realtype(funtype.base)
+    except tp.DMLUnknownType:
+        raise E.TYPE(site, funtype)
 
-    if not isinstance(funtype, TFunction):
-        raise EAPPLY(fun)
+    if not isinstance(funtype, tp.Function):
+        raise E.APPLY(fun)
 
     if funtype.varargs and len(args) > len(funtype.input_types):
         known_arglen = len(funtype.input_types)
@@ -480,6 +480,6 @@ class StaticIndex(NonValue):
     def __init__(self, site, var):
         pass
     def __str__(self):
-        return dollar(self.site) + ("_" if self.var is None else self.var)
+        return logging.dollar(self.site) + ("_" if self.var is None else self.var)
     def exc(self):
-        return EIDXVAR(self.site, str(self))
+        return E.IDXVAR(self.site, str(self))
diff --git a/py/dml/expr_util.py b/py/dml/expr_util.py
index 8227eb2e3..aa36eec0f 100644
--- a/py/dml/expr_util.py
+++ b/py/dml/expr_util.py
@@ -3,10 +3,10 @@
 
 # Various convenience functions for common operations on expressions
 import dml.globals
-from .logging import report, ICE
-from .messages import *
-from .types import *
-from .expr import *
+from .logging import report, DMLError
+from . import errors as E
+from . import types as tp
+from .expr import Lit, NonValue, NullConstant, StaticIndex
 
 __all__ = (
     'defined', 'undefined',
@@ -62,9 +62,9 @@ def expr_constvalue(expr, pytype, typestr):
     if isinstance(expr, NonValue):
         raise expr.exc()
     if not expr.constant:
-        raise ENCONST(expr.site, expr)
+        raise E.NCONST(expr.site, expr)
     if not isinstance(expr.value, pytype):
-        raise EBTYPE(expr.site, expr.ctype(), typestr)
+        raise E.BTYPE(expr.site, expr.ctype(), typestr)
     return expr.value
 
 
@@ -73,7 +73,7 @@ def expr_strval(expr):
     try:
         return value.decode('utf-8')
     except UnicodeDecodeError:
-        raise EBTYPE(expr.site, expr.ctype(), 'utf-8 encoded string')
+        raise E.BTYPE(expr.site, expr.ctype(), 'utf-8 encoded string')
 
 
 def expr_intval(expr):
@@ -111,7 +111,7 @@ def param_bool(node, name):
 
 def coerce_if_eint(expr):
     from .ctree import as_int
-    e_type = realtype(expr.ctype())
+    e_type = tp.realtype(expr.ctype())
     if e_type.is_int and e_type.is_endian:
         return as_int(expr)
     return expr
diff --git a/py/dml/g_backend.py b/py/dml/g_backend.py
index 15a3a5474..f7c808651 100644
--- a/py/dml/g_backend.py
+++ b/py/dml/g_backend.py
@@ -6,11 +6,10 @@
 __all__ = ('generate',)
 
 import pickle as pickle
-from . import ctree, crep, expr_util, types
+from . import crep, types
 from . import logging
 from .expr import mkLit
-from .logging import dollar
-import dml.globals
+
 
 VERSION = (0, 1)
 
@@ -50,7 +49,7 @@ def enc(expr):
     try:
         with crep.DeviceInstanceContext():
             expr = node.get_expr(tuple(
-                mkLit(node.site, dollar(node.site) + idxvar, types.TInt(32, False))
+                mkLit(node.site, logging.dollar(node.site) + idxvar, types.Int(32, False))
                 for idxvar in node.parent.idxvars()))
     except logging.DMLError:
         import os, sys, traceback
diff --git a/py/dml/info_backend.py b/py/dml/info_backend.py
index b19fe2c4c..e0be8e432 100644
--- a/py/dml/info_backend.py
+++ b/py/dml/info_backend.py
@@ -6,13 +6,11 @@
 import dml.globals
 from itertools import product
 from collections import OrderedDict
+from . import expr_util
 from .ctree import (StringConstant, IntegerConstant, mkIntegerLiteral,
                     all_index_exprs, param_str_fixup)
-from .expr_util import (
-    defined, undefined, param_int, param_defined,
-    static_indices)
-from .messages import *
-from .logging import *
+from .expr_util import defined
+from .logging import report, DMLError
 
 class XMLWriter(object):
     def __init__(self, filename):
@@ -50,7 +48,7 @@ def string_param(node, pname, dimsizes):
     # Allowing index variables to appear in the expression,
     # but requires them all evaluated to the same value.
     try:
-        val = pnode.get_expr(static_indices(node))
+        val = pnode.get_expr(expr_util.static_indices(node))
     except DMLError as e:
         report(e)
         return None
@@ -116,7 +114,7 @@ def reg_info(fmt, node, name, dimsizes):
         attrs = common_attrs(node, name, dimsizes)
         xml_offs = ' '.join([str(o) if offset_defined(o)
                              else '-1' for o in all_offs])
-        attrs.update(offset=xml_offs, size=param_int(node, 'size'))
+        attrs.update(offset=xml_offs, size=expr_util.param_int(node, 'size'))
         fmt.open_element('register', attrs)
         for n in node.get_components('field'):
             if not n.ident:
diff --git a/py/dml/int_register.py b/py/dml/int_register.py
index 0f2753279..95d42b911 100644
--- a/py/dml/int_register.py
+++ b/py/dml/int_register.py
@@ -1,36 +1,35 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from .expr import *
-from .ctree import *
-from .types import *
-from .logging import dbg
-from .symtab import *
+from .expr import Lit, mkApply, mkLit
+from . import ctree as c
+from . import types as tp
+from .symtab import global_scope, Symtab
 from .crep import node_storage_type
 from . import globals
 
-reg_table_type    = TPtr(TNamed('_dml_reg_t', const=True))
-regmap_table_type = TPtr(TNamed('_dml_reg_number_t', const=True))
+reg_table_type    = tp.Ptr(tp.Named('_dml_reg_t', const=True))
+regmap_table_type = tp.Ptr(tp.Named('_dml_reg_number_t', const=True))
 
 make_regname = mkLit(None, '_DML_make_regname',
-                     TFunction([reg_table_type, regmap_table_type],
-                               TPtr(TNamed('char', const=True))))
+                     tp.Function([reg_table_type, regmap_table_type],
+                               tp.Ptr(tp.Named('char', const=True))))
 find_regnum = mkLit(None, '_DML_find_regnum',
-                    TFunction([regmap_table_type,
-                               TInt(32, False),
-                               TInt(32, False)],
+                    tp.Function([regmap_table_type,
+                               tp.Int(32, False),
+                               tp.Int(32, False)],
                               regmap_table_type))
 find_regname = mkLit(None, '_DML_find_regname',
-                    TFunction([regmap_table_type,
-                               TInt(32, False),
-                               TPtr(TNamed('char', const=True)),
+                    tp.Function([regmap_table_type,
+                               tp.Int(32, False),
+                               tp.Ptr(tp.Named('char', const=True)),
                                reg_table_type],
                               regmap_table_type))
 
 def return_success(site):
-    return mkReturn(site, mkBoolConstant(site, False))
+    return c.mkReturn(site, c.mkBoolConstant(site, False))
 
-dml_reg_t = TExternStruct({}, '_dml_reg_t', const=True)
+dml_reg_t = tp.ExternStruct({}, '_dml_reg_t', const=True)
 
 def codegen_get_name(impl, indices, inargs, outargs, site):
     bank = impl.parent
@@ -39,25 +38,25 @@ def codegen_get_name(impl, indices, inargs, outargs, site):
     [name] = outargs
 
     if not bank.numbered_registers:
-        return mkCompound(
-            site, [mkCopyData(site, Lit(None, 'NULL', TPtr(TVoid()), 1), name),
+        return c.mkCompound(
+            site, [c.mkCopyData(site, Lit(None, 'NULL', tp.Ptr(tp.Void()), 1), name),
                    return_success(site)])
 
-    reg_table = mkLit(None, '_DML_R_' + bank.name, TPtr(dml_reg_t))
+    reg_table = mkLit(None, '_DML_R_' + bank.name, tp.Ptr(dml_reg_t))
     regnum_table = mkLit(None, '_DML_RN_' + bank.name,
                          regmap_table_type)
 
     # name = make_regname(reg_table, find_regnum(regnum_table, num))
     regnum_table_len = mkLit(site, 'ALEN(_DML_RN_%s)' % bank.name,
-                             TInt(32, False))
+                             tp.Int(32, False))
     reg = mkApply(site, find_regnum, [regnum_table, regnum_table_len, num])
     regname = mkApply(site, make_regname, [reg_table, reg])
-    return mkCompound(
+    return c.mkCompound(
         site,
-        [mkCopyData(site, regname, name),
-         mkIf(site,
-              mkNot(site, as_bool(name)),
-              log_statement(site, log_object(site, bank, indices), "error",
+        [c.mkCopyData(site, regname, name),
+         c.mkIf(site,
+              c.mkNot(site, c.as_bool(name)),
+              c.log_statement(site, c.log_object(site, bank, indices), "error",
                             None, None, "There is no register with number %d",
                             num)),
          return_success(site)])
@@ -69,42 +68,42 @@ def codegen_get_number(impl, indices, inargs, outargs, site):
     [num] = outargs
 
     if not bank.numbered_registers:
-        return mkCompound(
-            site, [mkCopyData(site, mkIntegerConstant(site, -1, True), num),
+        return c.mkCompound(
+            site, [c.mkCopyData(site, c.mkIntegerConstant(site, -1, True), num),
                    return_success(site)])
 
-    reg_table = mkLit(None, '_DML_R_' + bank.name, TPtr(dml_reg_t))
+    reg_table = mkLit(None, '_DML_R_' + bank.name, tp.Ptr(dml_reg_t))
     regnum_table = mkLit(None, '_DML_RN_' + bank.name,
                          regmap_table_type)
 
     # num = find_regname(regnum_table, name)->num
     regnum_table_len = mkLit(site, 'ALEN(_DML_RN_%s)' % bank.name,
-                             TInt(32, False))
-    reg = ExpressionInitializer(
+                             tp.Int(32, False))
+    reg = c.ExpressionInitializer(
         mkApply(site, find_regname, [regnum_table, regnum_table_len, name,
                                      reg_table]))
 
     scope = Symtab(global_scope)
-    regvar = mkLocalVariable(site, scope.add_variable(
+    regvar = c.mkLocalVariable(site, scope.add_variable(
         'reg',
         type=regmap_table_type,
         init=reg,
         make_unique=True,
         site=site))
 
-    return mkCompound(
+    return c.mkCompound(
         site,
-        [sym_declaration(regvar.sym),
-         mkIf(site,
-              as_bool(regvar),
-              mkCopyData(site,
-                         mkSubRef(site, regvar, 'num', '->'),
+        [c.sym_declaration(regvar.sym),
+         c.mkIf(site,
+              c.as_bool(regvar),
+              c.mkCopyData(site,
+                         c.mkSubRef(site, regvar, 'num', '->'),
                          num),
-              mkCompound(site,
-                         [mkCopyData(site,
-                                     mkIntegerConstant(site, -1, True),
+              c.mkCompound(site,
+                         [c.mkCopyData(site,
+                                     c.mkIntegerConstant(site, -1, True),
                                      num),
-                          log_statement(site, log_object(site, bank, indices),
+                          c.log_statement(site, c.log_object(site, bank, indices),
                                         "error", None, None,
                                         "There is no register with name %s",
                                         name)])),
@@ -116,21 +115,21 @@ def codegen_read(impl, indices, inargs, outargs, site):
     [val] = outargs
 
     if not bank.numbered_registers:
-        return mkCompound(
-            site, [mkCopyData(site, mkIntegerLiteral(site, 0), val),
+        return c.mkCompound(
+            site, [c.mkCopyData(site, c.mkIntegerLiteral(site, 0), val),
                    return_success(site)])
 
-    reg_table = mkLit(None, '_DML_R_' + bank.name, TPtr(dml_reg_t))
+    reg_table = mkLit(None, '_DML_R_' + bank.name, tp.Ptr(dml_reg_t))
     regmap_table = mkLit(None, '_DML_RN_' + bank.name,
                          regmap_table_type)
     regmap_table_len = mkLit(site, 'ALEN(_DML_RN_%s)' % bank.name,
-                             TInt(32, False))
+                             tp.Int(32, False))
 
     scope = Symtab(global_scope)
-    regvar = mkLocalVariable(site, scope.add_variable(
+    regvar = c.mkLocalVariable(site, scope.add_variable(
         'reg',
         type=regmap_table_type,
-        init=ExpressionInitializer(
+        init=c.ExpressionInitializer(
             mkApply(site, find_regnum,
                     [regmap_table, regmap_table_len, num])),
         make_unique=True,
@@ -138,23 +137,23 @@ def codegen_read(impl, indices, inargs, outargs, site):
 
     devtype = node_storage_type(globals.device)
     read_reg = mkLit(None, '_DML_read_reg',
-                     TFunction([devtype,
+                     tp.Function([devtype,
                                 regmap_table_type,
                                 reg_table_type],
-                               TInt(64, False)))
+                               tp.Int(64, False)))
 
-    return mkCompound(
+    return c.mkCompound(
         site,
-        [sym_declaration(regvar.sym),
-         mkIf(site,
-              as_bool(regvar),
-              mkCopyData(site,
+        [c.sym_declaration(regvar.sym),
+         c.mkIf(site,
+              c.as_bool(regvar),
+              c.mkCopyData(site,
                          mkApply(site, read_reg,
                                  [mkLit(site, '_dev', devtype),
                                   regvar,
                                   reg_table]),
                          val),
-              log_statement(site, log_object(site, bank, indices), "error",
+              c.log_statement(site, c.log_object(site, bank, indices), "error",
                             None, None, "There is no register with number %d",
                             num)),
          return_success(site)])
@@ -164,44 +163,44 @@ def codegen_write(impl, indices, inargs, outargs, site):
     [num, val] = inargs
 
     if not bank.numbered_registers:
-        return mkCompound(site, [return_success(site)])
+        return c.mkCompound(site, [return_success(site)])
 
-    reg_table = mkLit(None, '_DML_R_' + bank.name, TPtr(dml_reg_t))
+    reg_table = mkLit(None, '_DML_R_' + bank.name, tp.Ptr(dml_reg_t))
     regmap_table = mkLit(None, '_DML_RN_' + bank.name,
                          regmap_table_type)
     regmap_table_len = mkLit(site, 'ALEN(_DML_RN_%s)' % bank.name,
-                             TInt(32, False))
+                             tp.Int(32, False))
 
     scope = Symtab(global_scope)
-    regvar = mkLocalVariable(site, scope.add_variable(
+    regvar = c.mkLocalVariable(site, scope.add_variable(
         'reg',
         site=site,
         type=regmap_table_type,
-        init=ExpressionInitializer(
+        init=c.ExpressionInitializer(
             mkApply(site, find_regnum,
                     [regmap_table, regmap_table_len, num])),
         make_unique=True))
 
     devtype = node_storage_type(globals.device)
     write_reg = mkLit(None, '_DML_write_reg',
-                     TFunction([devtype,
+                     tp.Function([devtype,
                                 regmap_table_type,
                                 reg_table_type,
-                                TInt(64, False)],
-                               TVoid()))
+                                tp.Int(64, False)],
+                               tp.Void()))
 
-    return mkCompound(
+    return c.mkCompound(
         site,
-        [sym_declaration(regvar.sym),
-         mkIf(site,
-              as_bool(regvar),
-              mkExpressionStatement(site,
+        [c.sym_declaration(regvar.sym),
+         c.mkIf(site,
+              c.as_bool(regvar),
+              c.mkExpressionStatement(site,
                                     mkApply(site, write_reg,
                                             [mkLit(site, '_dev', devtype),
                                              regvar,
                                              reg_table,
                                              val])),
-              log_statement(site, log_object(site, bank, indices), "error",
+              c.log_statement(site, c.log_object(site, bank, indices), "error",
                             None, None, "There is no register with number %d",
                             num)),
          return_success(site)])
diff --git a/py/dml/io_memory.py b/py/dml/io_memory.py
index f11028824..6eb5a0ba0 100644
--- a/py/dml/io_memory.py
+++ b/py/dml/io_memory.py
@@ -1,22 +1,20 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-import operator
-from .ctree import *
-from .expr import *
-from .expr_util import *
-from .types import *
+from . import ctree as c
+from .expr import mkLit
+from .expr_util import param_bool, param_defined, param_str
+from . import types as tp
 from .logging import report
-from .messages import WEXPERIMENTAL_UNMAPPED
-from .symtab import *
-from .codegen import (require_fully_typed, mark_method_referenced,
-                      method_instance, codegen_call_byname, declarations,
-                      ReturnFailure)
+from . import warnings as W
+from .symtab import global_scope, Symtab
+from .codegen import codegen_call_byname, declarations
+from . import codegen
 from . import crep
 import dml.globals
 
 # Emit a warning if the hook methods are overridden, as they are
-# introduced as an experimental feature, at the moment.   
+# introduced as an experimental feature, at the moment.
 def check_unmapped_access_handling(bank, isread):
     if isread:
         meth_node = bank.get_component('_unmapped_read_access', 'method')
@@ -25,7 +23,7 @@ def check_unmapped_access_handling(bank, isread):
 
     overridden = meth_node and meth_node.default_method.node
     if overridden:
-        report(WEXPERIMENTAL_UNMAPPED(meth_node, meth_node.name))
+        report(W.EXPERIMENTAL_UNMAPPED(meth_node, meth_node.name))
 
 def unmapped_access(site, bank, idx, scope, isread, overlapping, bigendian,
                     memop, offset, size, writevalue, size2, value2):
@@ -33,21 +31,21 @@ def unmapped_access(site, bank, idx, scope, isread, overlapping, bigendian,
         # Only pass the first byte of the access to _unmapped_*_access
         if not isread:
             if bigendian:
-                writevalue = mkShR(
-                    site, writevalue, mkMult(
+                writevalue = c.mkShR(
+                    site, writevalue, c.mkMult(
                         site,
-                        mkSubtract(site, size, mkIntegerLiteral(site, 1)),
-                        mkIntegerLiteral(site, 8)))
+                        c.mkSubtract(site, size, c.mkIntegerLiteral(site, 1)),
+                        c.mkIntegerLiteral(site, 8)))
             else:
-                writevalue = mkBitAnd(
-                    site, writevalue, mkIntegerLiteral(site, 0xff))
-        size = mkIntegerLiteral(site, 1)
+                writevalue = c.mkBitAnd(
+                    site, writevalue, c.mkIntegerLiteral(site, 0xff))
+        size = c.mkIntegerLiteral(site, 1)
 
     scope = Symtab(scope)
     code = []
-    success = mkLocalVariable(site, scope.add_variable(
-        'success', type=TBool(), site=site,
-        init=ExpressionInitializer(mkBoolConstant(site, 0)),
+    success = c.mkLocalVariable(site, scope.add_variable(
+        'success', type=tp.Bool(), site=site,
+        init=c.ExpressionInitializer(c.mkBoolConstant(site, 0)),
         make_unique=True))
 
     if isread:
@@ -68,13 +66,13 @@ def unmapped_access(site, bank, idx, scope, isread, overlapping, bigendian,
                 [success]))
 
     code.extend([
-        mkCopyData(
+        c.mkCopyData(
             site,
-            mkIfExpr(site, success, size, mkIntegerLiteral(site, 0)),
+            c.mkIfExpr(site, success, size, c.mkIntegerLiteral(site, 0)),
             size2),
-        mkReturn(site, mkBoolConstant(site, False))])
+        c.mkReturn(site, c.mkBoolConstant(site, False))])
 
-    return mkCompound(site, declarations(scope) + code)
+    return c.mkCompound(site, declarations(scope) + code)
 
 # The basic idea of the register dispatcher is to statically
 # create a static table with one item for each register instance,
@@ -147,9 +145,9 @@ def codegen_access(bank, bank_indices, isread, memop, offset, size, writevalue,
 
     for reg in bank.mapped_registers:
         meth_node = reg.node.get_component(method_name, 'method')
-        require_fully_typed(site, meth_node)
-        func = method_instance(meth_node)
-        mark_method_referenced(func)
+        codegen.require_fully_typed(site, meth_node)
+        func = codegen.method_instance(meth_node)
+        codegen.mark_method_referenced(func)
         cname = func.get_cname()
         by_dims.setdefault(len(reg.layout[0].coord), []).extend(
             (instance, cname) for instance in reg.layout)
@@ -221,8 +219,8 @@ def dim_sort_key(data):
                 regvar, size.read())])
         lines.append(
                 '            %s;' % (
-            size2.write(ExpressionInitializer(mkLit(site, 'bytes',
-                                                    TInt(64, False))))))
+            size2.write(c.ExpressionInitializer(mkLit(site, 'bytes',
+                                                    tp.Int(64, False))))))
         if partial:
             if bigendian:
                 lines.extend([
@@ -247,8 +245,8 @@ def dim_sort_key(data):
                     regvar, indices, memop.read(), bytepos_args),
                 '            if (ret) return true;',
                 '            %s;' % (
-                    value2.write(ExpressionInitializer(
-                        mkLit(site, 'val', TInt(64, False))))),
+                    value2.write(c.ExpressionInitializer(
+                        mkLit(site, 'val', tp.Int(64, False))))),
                 '            return false;'])
         else:
             # Shifting/masking can normally be skipped in banks with
@@ -274,8 +272,8 @@ def dim_sort_key(data):
                 '        if (offset >= %s[last].offset' % (regvar,)
                 + ' && offset < %s[last].offset + %s[last].size) {'
                 % (regvar, regvar),
-                '            %s;' % (size2.write(ExpressionInitializer(
-                    mkIntegerLiteral(site, 0))),),
+                '            %s;' % (size2.write(c.ExpressionInitializer(
+                    c.mkIntegerLiteral(site, 0))),),
                 '            return false;',
                 '        }'])
         lines.extend([
@@ -284,14 +282,14 @@ def dim_sort_key(data):
             '}'])
 
     scope = Symtab(global_scope)
-    code = [mkInline(site, line) for line in lines]
+    code = [c.mkInline(site, line) for line in lines]
     check_unmapped_access_handling(bank, isread)
-    with ReturnFailure(site):
+    with codegen.ReturnFailure(site):
         code.append(unmapped_access(site, bank, bank_indices, scope, isread,
                                     overlapping, bigendian, memop,
                                     offset, size, writevalue, size2, value2))
 
-    return mkCompound(
+    return c.mkCompound(
         site, declarations(scope) + code)
 
 def codegen_write_access(bank, idx, inargs, outargs, site):
diff --git a/py/dml/logging.py b/py/dml/logging.py
index 98cc90979..923eb3847 100644
--- a/py/dml/logging.py
+++ b/py/dml/logging.py
@@ -8,7 +8,6 @@
     'ICE',
 
     'show_porting',
-    'is_warning_tag',
     'ignore_warning',
     'warning_is_ignored',
     'enable_warning',
@@ -26,6 +25,9 @@
     'InEachSite',
 
     'dbg',
+
+    'truncate',
+    'binary_dump',
     )
 
 import sys
@@ -50,11 +52,6 @@ def set_include_tag(val):
     global include_tag
     include_tag = val
 
-def is_warning_tag(tag):
-    from . import messages
-    cls = getattr(messages, tag, None)
-    return isinstance(cls, type) and issubclass(cls, DMLWarning)
-
 # A set of ignored warnings
 ignored_warnings = {}
 def ignore_warning(tag):
@@ -119,6 +116,8 @@ class LogMessage(object):
 
     outfile = sys.stderr
 
+    tag_prefix = ''
+
     def __init__(self, site, *msgargs):
         # The site is the place in the source that this log message
         # refers to.
@@ -156,8 +155,9 @@ def print_site_message(self, site, msg):
             if os.getenv('DMLC_DEBUG'):
                 raise
 
-    def tag(self):
-        return self.__class__.__name__
+    @classmethod
+    def tag(cls):
+        return cls.tag_prefix + cls.__name__
 
     def preprocess(self):
         '''Call before log when reporting. Return True to actually log
@@ -214,6 +214,7 @@ def __init__(self, site, msg):
 # This is a base class for warning messages
 #
 class DMLWarning(LogMessage):
+    tag_prefix = 'W'
     kind = "warning"
     next_warning_yields_error = False
 
@@ -239,6 +240,7 @@ def postprocess(self):
 # This is a base class for error messages
 #
 class DMLError(Exception, LogMessage):
+    tag_prefix = 'E'
     kind = "error"
 
     def __init__(self, site, *msgargs):
@@ -250,6 +252,7 @@ def postprocess(self):
         report_error()
 
 class PortingMessage(LogMessage):
+    tag_prefix = 'P'
     kind = 'porting'
     fmt = ''
 
@@ -487,3 +490,17 @@ def suppress_errors():
         store_errors.append(e)
     finally:
         store_errors = orig
+
+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()))
diff --git a/py/dml/objects.py b/py/dml/objects.py
index 3ac5fc089..d82bb6563 100644
--- a/py/dml/objects.py
+++ b/py/dml/objects.py
@@ -5,7 +5,7 @@
 import abc
 import contextlib
 
-from .logging import dollar
+from . import logging
 from .set import Set
 import dml.globals
 
@@ -268,7 +268,7 @@ def logname(self, indices=(), relative='device'):
         if self.isindexed():
             suff = "".join('[%s]' % i for i in
                            indices[-self.local_dimensions():])
-            suff += "".join(f'[{dollar(self.site)}'
+            suff += "".join(f'[{logging.dollar(self.site)}'
                             + f'{"_" if idxvar is None else idxvar}]'
                             for idxvar in self._idxvars[len(indices):])
             indices = indices[:-self.local_dimensions()]
@@ -296,7 +296,7 @@ def identity(self, indices=(), relative='device'):
         if self.isindexed():
             suff = "".join('[%s]' % i for i in
                            indices[-self.local_dimensions():])
-            suff += "".join(f'[{dollar(self.site)}'
+            suff += "".join(f'[{logging.dollar(self.site)}'
                             + f'{"_" if idxvar is None else idxvar} < {arrlen}]'
                             for (idxvar, arrlen) in
                             itertools.islice(
diff --git a/py/dml/output.py b/py/dml/output.py
index e58173700..4e93e0cab 100644
--- a/py/dml/output.py
+++ b/py/dml/output.py
@@ -6,7 +6,8 @@
 from pathlib import Path
 
 import dml.globals
-from .logging import ICE, SimpleSite
+from . import logging
+from .logging import ICE
 
 __all__ = (
     'NoOutput',
@@ -117,7 +118,7 @@ def close(self):
 
     def commit(self):
         if self.indent:
-            raise ICE(SimpleSite(f"{self.filename}:0"), 'Unbalanced indent')
+            raise ICE(logging.SimpleSite(f"{self.filename}:0"), 'Unbalanced indent')
         try:
             os.remove(self.filename)
         except OSError:
@@ -164,7 +165,7 @@ def quote_filename(filename):
 
 def site_linemark_nocoverity(site, adjust=0):
     if dml.globals.linemarks:
-        if site is not None and not isinstance(site, SimpleSite):
+        if site is not None and not isinstance(site, logging.SimpleSite):
             filename = site.filename()
             lineno = site.lineno
             if lineno + adjust < 0:
@@ -183,7 +184,7 @@ def coverity_marker(event, classification=None, site=None):
     coverity_markers([(event, classification)], site)
 
 def coverity_markers(markers, site=None):
-    site_with_loc = site is not None and not isinstance(site, SimpleSite)
+    site_with_loc = site is not None and not isinstance(site, logging.SimpleSite)
     if dml.globals.coverity and site_with_loc:
         custom_markers = []
         filename = site.filename()
diff --git a/py/dml/porting.py b/py/dml/porting.py
new file mode 100644
index 000000000..0429f5386
--- /dev/null
+++ b/py/dml/porting.py
@@ -0,0 +1,487 @@
+# © 2021 Intel Corporation
+# SPDX-License-Identifier: MPL-2.0
+
+from .logging import PortingMessage
+
+class SHA1(PortingMessage):
+    """The `port-dml` script requires that the DML file has not been
+    changed since the tag file was generated. This is verified by a
+    SHA1 checksum."""
+    fmt = 'SHA1 checksum of DML file'
+
+class VERSION(PortingMessage):
+    """DML 1.4 files should start with `dml 1.4;` instead
+    of `dml 1.2;`"""
+    fmt = "update version statement to 1.4"
+
+class NOTHROW(PortingMessage):
+    """In DML 1.4, it is assumed by default that a method may not throw an
+    exception. Any `nothrow` annotations must be removed."""
+    fmt = "remove nothrow annotation"
+
+class THROWS(PortingMessage):
+    """In DML 1.4, methods that can throw an exception must explicitly
+    declare that with a 'throws' annotation. Such annotation is
+    automatically added for methods that override a throwing method
+    that was declared in a DML 1.4 file."""
+    fmt = "add throws annotation"
+
+class INPARAMLIST(PortingMessage):
+    """If a method has no input arguments, the empty input parameter
+    list `()` is now required in method declarations
+    and `call`/`inline` statements."""
+    fmt = "add () after method"
+
+class STRUCTDECL(PortingMessage):
+    """Struct type definitions can no longer be declared using the
+    labeled struct syntax. The equivalent typedef declaration should
+    be used instead. For example, the following is now disallowed:
+
+    
+    struct xyz { ... }
+    
+ + and should be replaced with the following: + +
+    typedef struct { ... } xyz;
+    
""" + fmt = "use typedef syntax for struct type declaration" + +class FIELDRANGE(PortingMessage): + """In a field declaration, the field range declaration must be + preceded by `@`. In DML 1.4, the syntax `field f[4]` + declares a field array of size 4, while in DML 1.2 it denotes a field + occupying bit 4 in its parent register.""" + fmt = "insert @ before field range declaration" + +class INLINEDECL(PortingMessage): + """Methods with untyped parameters must be explicitly marked 'inline' + in DML 1.4, as in `inline method m(inline x) -> (int y)`""" + fmt = "add inline annotation to method with untyped parameters" + +class RETVAL(PortingMessage): + """Method output parameters are not named in DML 1.4: + ``` + method m() -> (int, int) { + ... + } + ``` + + See also `PRETURNARGS`.""" + fmt = "remove name from method output parameter" + +class RETVAL_END(PortingMessage): + """Methods with output arguments must end with an explicit return + statement in DML 1.4; in DML 1.2, the method would return whatever + value the output argument had upon exit. See also `PRETVAL`. + """ + fmt = "add return statement to end of method" + +class RETURNARGS(PortingMessage): + """In methods with return values, return statements now take arguments: + ``` + method m() -> (int, int) { + return (1, 4); + } + method n() -> (int) { + return 3; + } + ```""" + fmt = "add arguments to return statement" + +class OUTARGRETURN(PortingMessage): + """An assignment to an output argument directly followed by a + return statement is more concisely written as a single return + statement, without an intermediate assignment. For instance, + ``` + dml 1.2; + method four() -> (int x) { + x = 4; + return; + } + ``` + can be expressed as: + ``` + dml 1.4; + method four() -> (int) { + return 4; + } + ``` + """ + fmt = "merge outarg assignment with return statement" + +class TYPEDOUTPARAM(PortingMessage): + """Method output parameters must have explicit types in DML 1.4. The + automatic conversion script will convert untyped output parameters + to `uint64`.""" + fmt = "declare explicit type for output parameter" + +class INARGTYPE(PortingMessage): + """When overriding a method in DML 1.4, the overriding and default + implementation must declare the same arguments as `inline`. + If the override has untyped arguments that are typed in the default + method, then the conversion script will add a type to the override's + argument. + + Note: The inserted type declaration uses C syntax, which in most + cases matches DML syntax; however, there are exceptions where the + inserted declaration will be broken and needs to be fixed manually. + """ + fmt = "" + +class INVOKE(PortingMessage): + """Method invocation syntax changed. Replace + + ``` + call m(x) -> (a, b); + inline n() -> (c); + call o(); + ``` + with: + ``` + (a, b) = m(x); + c = n(); + o(); + ```""" + fmt = "Use assignment syntax for method invocation" + +class LOGKIND(PortingMessage): + """In log statements, the old syntax where log type is denoted by a string + has been removed. Use the new identifier-based syntax instead. E.g., + instead of: + ``` + log "info": "foo"; + log "spec_violation": "foo"; + ``` + you must now write: + ``` + log info: "foo"; + log spec_viol: "foo"; + ``` +""" + fmt = "Don't use string literal syntax for log type" + +class AFTER(PortingMessage): + """The syntax of `after` statements changed: The delay should + be followed by `s` to denote time unit; furthermore, the + `call` keyword should no longer be used, and brackets + around the delay are optional. Example: + ``` + after (1.3) call send_frame(); // DML 1.2 syntax + after 1.3 s: send_frame(); // DML 1.4 syntax + ```""" + fmt = "Remove 'call' and add 's' in 'after' statement" + +class AUTO(PortingMessage): + """The `auto` keyword is deprecated; use the equivalent + `local` instead.""" + fmt = "replace 'auto' with 'local'" + +class SESSION(PortingMessage): + """The `data` and `static` keywords have both been replaced + with `session`: + ``` + session uint32 x; + ```""" + fmt = "replace 'data' and 'static' with 'session'" + +class HARD_RESET_VALUE(PortingMessage): + """The `hard_reset_value` parameter is no longer + recognized. The parameter is automatically renamed to + `init_val`, which has roughly the same effect.""" + fmt = "change hard_reset_value to init_val" + +class SOFT_RESET_VALUE(PortingMessage): + """The `soft_reset_value` parameter is renamed to + `soft_reset_val`, and requires the template + `soft_reset_val` to be instantiated.""" + fmt = "change soft_reset_value to soft_reset_val" + +class MISS_PATTERN(PortingMessage): + """The `miss_pattern` parameter is no longer recognized by + banks, unless the `miss_pattern_bank` template, from utility.dml, is + instantiated. An instantiation is automatically added.""" + fmt = "instantiate miss_pattern_bank to use the miss_pattern parameter" + +class ATTRIBUTE(PortingMessage): + """The `allocate_type` parameter is no longer valid for attributes. + Integer, boolean and floating-point attributes instead use + standard templates such as `uint64_attr`, `int64_attr`, `bool_attr` and + `double_attr`. + + The porting rule will remove `allocate_type`, together with an + explicit type parameter if present. All integer types will be + changed to 64-bit types. Attributes with `allocate_type="string"` + have to be manually rewritten. + """ + fmt = "use uint64_attr template instead of allocate_type parameter" + +class EVENT(PortingMessage): + """Event objects no longer have the `timebase` parameter; + instead you must choose a standard template to instantiate. The + conversion script will pick `custom_time_event`, + `custom_cycle_event`, `simple_time_event`, or `simple_cycle_event`. + """ + +class EVENT_NO_ARG(PortingMessage): + """When `PEVENT` converts an event to `simple_time_event` or + `simple_cycle_event`, the `data` function argument to methods + `post`, `posted`, `next` and `remove` are removed. + """ + +class EVENT_UINT64_ARG(PortingMessage): + """When one of the methods `post`, `posted`, `next` and `remove` + is called with an integer value cast to a pointer in the `data` + arg, that event is converted to a `uint64_time_event` or + `uint64_cycle_event`. The converter removes the cast and + causes the event object to be converted to a + `uint64_time_event` instead of `uint64_custom_event`. + """ + +class EVENT_REMOVE_INFO(PortingMessage): + """When an event is converted to a `uint64_time_event` or + `uint64_cycle_event`, the `set_event_info` and `get_event_info` methods + are removed. + """ + +class OVERRIDE(PortingMessage): + """If a method has exactly one default and one non-default + declaration, and the non-default declaration resides in a + template, then DML 1.4 requires that this template inherits from + the template containing the default declaration. Conversion is done + automatically for the most common case.""" + fmt = "template with method override must instantiate overridden template" + +class OVERRIDE_IMPORT(PortingMessage): + """Similar to POVERRIDE, but if a default method does _not_ + reside in a template, then the file that instantiates the non-default + declaration must import the file containing the default declaration.""" + fmt = "template with method override must import overridden file" + +# TODO: convert
+
+class BEFAFT(PortingMessage):
+    """In objects of type attribute, register and connect, before/after
+    methods (e.g. `before_write`, `after_read`,
+    `after_set`), are no longer called. They are transformed
+    into an override of the corresponding base function
+    (`write_register`, `read_register`, `set`).
+    Note that when a before/after method is implemented by a template,
+    then an additional `is register` declaration may be needed in
+    1.4; this is not automatically added.
+    """
+    fmt = "before / after method no longer called, override base method instead"
+
+class ABSTRACT_TEMPLATE(PortingMessage):
+    """When implementing methods `read` or `write` in a
+    field or register, or `hard_reset` or
+    `soft_reset` in a bank, or `get`, `set`,
+    `read_field`, `write_field` in a field, then this will
+    have no effect unless a template named like the method is instantiated. The
+    automatic converter will add e.g. `is read;` before an
+    implementation of `read`."""
+    fmt = ("method has no effect unless corresponding abstract template is"
+           + " instantiated")
+
+class TRAMPOLINE(PortingMessage):
+    """The methods `miss_read_access` and
+    `miss_write_access` in `bank` objects have been
+    renamed to `unmapped_read` and `unmapped_write`
+    in 1.4. The converter creates methods with the new names, which
+    call the existing unmodified methods."""
+    fmt = "method has been renamed in 1.4, will insert trampoline method"
+
+class IMPORT_DML12COMPAT(PortingMessage):
+    """The `PTRAMPOLINE` porting rule sometimes requires
+    that `dml12-compatibility.dml` is imported."""
+    fmt = ''
+
+class CHANGE_INARGS(PortingMessage):
+    """Many overridable methods in the standard library have changed, and
+    method overrides must be changed accordingly. A method in 1.2
+    usually has a counterpart in 1.4, but its semantics may have
+    changed slightly and quite often the set of arguments has changed
+    as well.  The automatic converter will adjust the names and
+    signatures of a number of methods. Invocations, including
+    `default()`, are not updated and must be manually converted
+    (compile errors). Some method arguments are removed by the
+    converter; if these arguments are used, the implementation must be
+    modified accordingly. In particular, the `memop` arg of
+    various bank and register methods is no longer present. This has
+    been replaced with an argument `void *aux`, which is
+    normally NULL.  If some register in a bank needs a memop, then the
+    `io_memory_access` method can be updated to pass down the
+    memop in the `aux` argument (just call `default`
+    with `memop` in the last arg). An explicit call to a bank
+    method, e.g. a redirection of an access to a different bank,
+    should normally be rewritten as a call to `read` or
+    `write`, usually with NULL in the `aux`
+    argument.
+
+    Bank methods are converted as follows: `access` →
+    `io_memory_access`; `read_access`,
+    `read_access_memop` → `read`;
+    `write_access`, `write_access_memop` →
+    `write`
+
+    Register methods are converted like so: `read_access`
+    → `read_register`, `write_access` →
+    `write_register`
+
+    Field methods are converted thusly: `read_access`
+    → `read_field`, `write_access` →
+    `write_field`
+
+    In `register` and `field` objects, the
+    `set` and
+    `write_register`/`write_field` methods will get
+    an explicit type `uint64`.
+
+    The read and write methods on `bank`, `register`,
+    and `field` objects all take a new `uint64` argument
+    denoting enabled bytes or bits, depending on the context, which
+    may mask an access.
+
+    In `connect` objects, `validate_port` is converted
+    to `validate`; named ports are deprecated in Simics 6, but
+    the port name is available in the `port` session variable.
+
+    In `attribute` objects, the `set` method will get
+    an explicit argument type `attr_value_t`, and a
+    `throws` annotation.
+    """
+    fmt = "override of library method with new name or signature"
+
+class BITNEQ(PortingMessage):
+    """DML 1.2 permits using 1-bit fields as boolean values. In DML 1.4,
+    field values are 64 bit, and thus require an explicit `!= 0`"""
+    fmt = ""
+
+class VAL(PortingMessage):
+    """The value of a `register`, `field` or `attribute`
+    object, and the interface struct of a `interface` object, is now
+    accessed through the `.val` member."""
+    fmt = "use .val member to access register/attribute value"
+
+class NODOLLAR(PortingMessage):
+    """The `$` character is no longer needed when referencing objects."""
+    fmt = "remove $"
+
+class DOLLAR_QUALIFY(PortingMessage):
+    """In DML 1.4, there is no separate scope for `$`, so local
+    variables can shadow object references. This conversion rule
+    attempts to detect this, and add `this.` or
+    dev.path. where needed."""
+    fmt = "use qualified object reference to escape shadowing"
+
+class CONSTANT(PortingMessage):
+    """`constant` declarations are removed in 1.4 and should be
+    replaced with `param` declarations. Both are accessible
+    from the top-level scope of a device."""
+    fmt = "change 'constant' to 'param'"
+
+class PARAMETER(PortingMessage):
+    """The `parameter` keyword has been renamed to `param`."""
+    fmt = "change 'parameter' to 'param'"
+
+class ARRAY_I(PortingMessage):
+    """The syntax for object arrays has changed: Instead of
+    `register r[12]`, you write `register r[i < 12]`"""
+    fmt = "explicit index in object array declaration"
+
+class ARRAY(PortingMessage):
+    """The syntax for object arrays has changed: Instead of
+    `register r[j in 0..size - 1]`, you write
+    `register r[j < size]`"""
+    fmt = "'<' replaces 'in 0..' in object array declaration"
+
+class HASH(PortingMessage):
+    """`if` statements on top level must be prefixed with a `#`
+    character. The same applies to `if` statement inside a method body
+    if the condition is constant and the dead branch contains errors.
+
+    Similarly, the conditional operator (`? :`) is updated to #? #:
+    when needed, `select` is updated to `#select`, and
+    `foreach` is updated to `#foreach`."""
+    fmt = "insert '#' before 'if'"
+
+class HASHELSE(PortingMessage):
+    """If an `if` is updated to `#if`, and there is a
+    corresponding `else` clause, then it must be updated to
+    `#else`. The same applies to the `else` clause in
+    `select` statements."""
+    fmt = "insert '#' before 'else'"
+
+class ANDOR(PortingMessage):
+    """DML 1.2 permits the right operand of an `&&` or
+    `||` expression to contain errors, as long as the left
+    operand evaluates to a constant that makes the right operand
+    dead. DML 1.4 does not permit this, so the expression `A
+    && B` must be converted to `A #? B #: false`.
+    One common use case is expressions like
+    `(defined X && X.y == ...)`.
+    """
+    fmt = ''
+
+class IFAND(PortingMessage):
+    """If statements on the form `if (defined(X) && X.y) { ... }`
+    are converted to a nested `#if` statement"""
+    fmt = ''
+
+class STRINGIFY(PortingMessage):
+    """In DML 1.4, `#` is changed to the
+    `stringify` operator"""
+    fmt = "Replace '#(X)' with 'stringify(X)' operator"
+
+class WUNUSED(PortingMessage):
+    """This message is used to signal to the porting script that a piece
+    of conditional code was not fully covered by the compile. Some
+    portings are never applied on dead code. The porting script
+    can signal a warning for this."""
+    fmt = ""
+    typed_methods = set()
+    # site -> objects.Method
+    inline_methods = {}
+    inlined_methods = set()
+    positive_conds = set()
+    negative_conds = set()
+    satisfied_conds = set()
+    used_templates = set()
+
+class NO_WUNUSED(PortingMessage):
+    """Used in conjunction with PWUNUSED to signal that a piece of
+    conditional code was indeed used. If using multiple runs of DMLC
+    as input to the porting script, and a piece of code was used in
+    some runs and unused in others, then no warning is shown.
+    """
+    fmt = ""
+
+class RENAME_TEMPLATE(PortingMessage):
+    """Some templates in `utility.dml` have been renamed; in
+    particular, `unimplemented` has been renamed to
+    `unimpl`.
+    """
+    fmt = ""
+
+class UNDEFOFFS(PortingMessage):
+    """`undefined` is no longer a valid offset for registers; `unmapped_offset`
+    should be used instead.
+    """
+    fmt = "Use 'unmapped_offset' instead of 'undefined'"
+
+class INT1(PortingMessage):
+    """Integer types have different semantics in DML 1.2 and DML 1.4;
+    the `int1` type in DML 1.2 is converted to `uint1` in DML 1.4
+    because that is a better match for some common operations. In
+    particular, if the value 1 is assigned to variables of these
+    types, then the value of the variable becomes 1, whereas for
+    `int1` in DML 1.4 the value is -1."""
+    fmt = "Change int1 to uint1"
+
+
+all_portings = {
+    o.tag(): o for o in globals().values()
+    if isinstance(o, type)
+    and issubclass(o, PortingMessage)
+    and o is not PortingMessage}
diff --git a/py/dml/provisional.py b/py/dml/provisional.py
index c7c3c5e77..b40554be2 100644
--- a/py/dml/provisional.py
+++ b/py/dml/provisional.py
@@ -3,7 +3,8 @@
 
 import abc
 from . import logging
-from . import messages
+from .logging import Site
+from . import errors as E
 
 class ProvisionalFeature(abc.ABC):
     def tag(self) -> str:
@@ -214,6 +215,6 @@ def parse_provisional(
         if name in features:
             ret[features[name]] = site
         else:
-            logging.report(messages.ENOPROV(
+            logging.report(E.NOPROV(
                 site, name, ', '.join(sorted(features))))
     return ret
diff --git a/py/dml/reginfo.py b/py/dml/reginfo.py
index a9b469cf2..23ac61c58 100644
--- a/py/dml/reginfo.py
+++ b/py/dml/reginfo.py
@@ -1,16 +1,17 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from collections import namedtuple
 import operator
 import itertools
 from functools import reduce
 import dml.globals
-from . import logging
-from .ctree import *
-from .logging import *
-from .messages import *
-from .expr_util import *
+from . import expr_util, logging
+from . import ctree as c
+from . import porting as P
+from .logging import report, DMLError
+from . import errors as E, warnings as W
+from .expr_util import (
+    defined, param_expr, param_expr_site, param_int, static_indices)
 
 __all__ = ('explode_registers',)
 
@@ -54,8 +55,8 @@ def node_instances(self):
         # r1 is a two-dimensional register array, but the partition only
         # contains r1[3][1] and r1[4][5]. Can happen if register offset
         # is undefined for some, but not all, indices.
-        [(r1, (mkIntegerLiteral(3), mkIntegerLiteral(1)), ()),
-         (r1, (mkIntegerLiteral(4), mkIntegerLiteral(5)), ())]
+        [(r1, (c.mkIntegerLiteral(3), c.mkIntegerLiteral(1)), ()),
+         (r1, (c.mkIntegerLiteral(4), c.mkIntegerLiteral(5)), ())]
         # r2 is a two-dimensional register array, and the partition contains
         # all 6 instances
         [(r2, (), (3, 2))]
@@ -64,7 +65,7 @@ def node_instances(self):
         node.dimensions == bank.dimensions + len(indices) + len(dimsizes).
         '''
         if self.dimsizes is None:
-            return ((self.node, tuple(mkIntegerLiteral(self.node.site, i)
+            return ((self.node, tuple(c.mkIntegerLiteral(self.node.site, i)
                                       for i in instance.coord), ())
                     for instance in self.layout)
         else:
@@ -120,11 +121,11 @@ def explode_register(node):
             indices = static_indices(node, param_expr_site(node, 'offset'))
             offset = param_expr(node, 'offset', indices)
             if offset.undefined:
-                report(PUNDEFOFFS(offset.site))
-        except EIDXVAR:
+                report(P.UNDEFOFFS(offset.site))
+        except E.IDXVAR:
             pass
     for indices in itertools.product(*(
-            (mkIntegerLiteral(node.site, idx) for idx in range(dimsize))
+            (c.mkIntegerLiteral(node.site, idx) for idx in range(dimsize))
             for dimsize in dimsizes)):
         coord = tuple(i.value for i in indices)
         roffset, rsize, regnum = one_register(node, indices, n)
@@ -158,9 +159,9 @@ def one_register(node, indices, bank):
     try:
         if dml.globals.dml_version == (1, 2):
             roffset = param_expr(node, 'offset', bank_indices + indices)
-            roffset = expr_intval(roffset) if defined(roffset) else None
+            roffset = expr_util.expr_intval(roffset) if defined(roffset) else None
             regnum = param_expr(node, 'regnum', bank_indices + indices)
-            regnum = expr_intval(regnum) if defined(regnum) else None
+            regnum = expr_util.expr_intval(regnum) if defined(regnum) else None
         else:
             roffset = param_int(node, 'offset', indices=bank_indices + indices)
             # in 1.4, we use the magic constant unmapped_offset to denote
@@ -174,7 +175,7 @@ def one_register(node, indices, bank):
 
         # roffset is undefined for unmapped registers
         if roffset and roffset < 0:
-            report(WNEGOFFS(param_expr_site(node, 'offset'), roffset))
+            report(W.NEGOFFS(param_expr_site(node, 'offset'), roffset))
             roffset &= 0xffffffffffffffff
 
         return (roffset, rsize, regnum)
@@ -190,7 +191,7 @@ def check_overlap(regs):
             [[node1], [node2]] = [
                 [reg.node for reg in regs if ri in reg.layout]
                 for ri in [ri1, ri2]]
-            report(EREGOL(node1, node2, ri1.coord, ri2.coord))
+            report(E.REGOL(node1, node2, ri1.coord, ri2.coord))
 
 def explode_registers(bank):
     """Expand all registers of a bank, and calculate the offsets of every
diff --git a/py/dml/reginfo_test.py b/py/dml/reginfo_test.py
index 3ea6b8d84..12f45a4de 100644
--- a/py/dml/reginfo_test.py
+++ b/py/dml/reginfo_test.py
@@ -2,10 +2,9 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import unittest
-import operator
 import itertools
 
-from dml.reginfo import RegInstance, RegInfo, explode_register
+from dml.reginfo import RegInstance, RegInfo
 from dml.objects import Device, Bank, Group, Register
 
 class TestRegInfo(unittest.TestCase):
diff --git a/py/dml/serialize.py b/py/dml/serialize.py
index 4742a83d9..416501671 100644
--- a/py/dml/serialize.py
+++ b/py/dml/serialize.py
@@ -4,11 +4,11 @@
 # This module contains the functions used to generate methods to convert between
 # dml values and attribute values
 
-from . import ctree, expr, types, logging, symtab, messages, output, logging
+from . import ctree, expr, logging, symtab, errors as E, output
 from . import objects
-from .types import *
-from .logging import *
-from .expr_util import *
+from . import types as tp
+from .logging import ICE
+from .expr_util import expr_intval
 from .set import Set
 import dml.globals
 
@@ -20,14 +20,14 @@
     'lookup_deserialize',
     )
 
-attr_value_t = TNamed('attr_value_t')
-set_error_t = TNamed('set_error_t')
-uint64_t = TInt(64, False)
-const_void = void.clone()
+attr_value_t = tp.Named('attr_value_t')
+set_error_t = tp.Named('set_error_t')
+uint64_t = tp.Int(64, False)
+const_void = tp.void.clone()
 const_void.const = True
 
-serializer_t = TFunction([TPtr(const_void), TPtr(void)], attr_value_t)
-deserializer_t = TFunction([attr_value_t, TPtr(void), TPtr(void)],
+serializer_t = tp.Function([tp.Ptr(const_void), tp.Ptr(tp.void)], attr_value_t)
+deserializer_t = tp.Function([attr_value_t, tp.Ptr(tp.void), tp.Ptr(tp.void)],
                            set_error_t)
 
 # code to insert before body
@@ -49,7 +49,7 @@ def add(self, trait):
 # used to convert dmltype to attr_value_t
 serialize_function_list = []
 def lookup_serialize(lookup_t):
-    lookup_t = safe_realtype(lookup_t)
+    lookup_t = tp.safe_realtype(lookup_t)
     descriptor = type_signature(lookup_t, True)
     for (t, f) in serialize_function_list:
         # we will consider two types equal if they would get the same
@@ -63,7 +63,7 @@ def lookup_serialize(lookup_t):
 # list of tuples (dmltype, mapping fun), used to convert attr_value_t to dmltype
 deserialize_function_list = []
 def lookup_deserialize(lookup_t):
-    lookup_t = safe_realtype(lookup_t)
+    lookup_t = tp.safe_realtype(lookup_t)
     descriptor = type_signature(lookup_t, False)
     for (t, f) in deserialize_function_list:
         # we will consider two types equal if they would get the same
@@ -85,49 +85,41 @@ def declare_variable(site, name, type, init_expr = None):
                 site, symtab.LocalSymbol(name, name, type, site=site)))
 
 def prepare_array_de_serialization(site, t):
-    assert(isinstance(t, TArray))
+    assert(isinstance(t, tp.Array))
     dims = []
     base = t
-    while isinstance(base, TArray):
+    while isinstance(base, tp.Array):
         dims.append(base.size)
         base = base.base
 
     sizeof_base = expr.mkLit(site, f"sizeof({base.declaration('')})",
-                             TNamed('size_t'))
+                             tp.Named('size_t'))
     dimsizes_lit = ('(const uint32 []) { %s }'
                     % ((', '.join(dim.read() for dim in dims)),))
-    dimsizes_expr = expr.mkLit(site, dimsizes_lit, TPtr(TInt(32, False)))
+    dimsizes_expr = expr.mkLit(site, dimsizes_lit, tp.Ptr(tp.Int(32, False)))
     return (base, dims, sizeof_base, dimsizes_expr)
 
 def mkSubRefLit(site, expr, sub, typ, op):
-    real_etype = safe_realtype_shallow(expr.ctype())
+    real_etype = tp.safe_realtype_shallow(expr.ctype())
 
-    if isinstance(real_etype, TPtr):
-        if op == '.':
-            raise ENOSTRUCT(site, expr)
-        basetype = real_etype.base
-        real_basetype = safe_realtype(basetype)
-    else:
-        if op == '->':
-            raise ENOPTR(site, expr)
-        real_basetype = safe_realtype(etype)
-
-    real_basetype = real_basetype.resolve()
+    assert isinstance(real_etype, tp.Ptr), (site, expr)
+    assert op == '->', (site, expr)
+    real_basetype = tp.safe_realtype(real_etype.base).resolve()
 
     return ctree.StructMember(site, expr, sub,
-                              conv_const(real_basetype.const, typ), op)
+                              tp.conv_const(real_basetype.const, typ), op)
 
 
 # This works on the assumption that args do not need to be hard-cast
 # to fit the actual fun signature
 def apply_c_fun(site, fun, args, rettype):
-    function_type = TFunction([a.ctype() for a in args], rettype)
+    function_type = tp.Function([a.ctype() for a in args], rettype)
     lit = expr.mkLit(site, fun, function_type)
     return expr.mkApply(site, lit, args)
 
 def call_c_fun(site, fun, args):
     return ctree.mkExpressionStatement(
-        site, apply_c_fun(site, fun, args, void))
+        site, apply_c_fun(site, fun, args, tp.void))
 
 # serialize current_expr, interpreted as real_type, and assign
 # to target_expr
@@ -145,7 +137,7 @@ def construct_assign_apply(funname, intype):
             funname = "SIM_make_attr_uint64"
         if real_type.is_endian:
             converted_arg = ctree.as_int(current_expr)
-            function_type = TFunction([converted_arg.ctype], attr_value_t)
+            function_type = tp.Function([converted_arg.ctype], attr_value_t)
             apply_expr = expr.Apply(current_site,
                                     expr.mkLit(current_site,
                                                funname,
@@ -159,11 +151,11 @@ def construct_assign_apply(funname, intype):
                                             apply_expr))])
         else:
             return construct_assign_apply(funname, real_type)
-    elif isinstance(real_type, TBool):
+    elif isinstance(real_type, tp.Bool):
         return construct_assign_apply("SIM_make_attr_boolean", real_type)
-    elif isinstance(real_type, TFloat):
+    elif isinstance(real_type, tp.Float):
         return construct_assign_apply("SIM_make_attr_floating", real_type)
-    elif isinstance(real_type, TArray):
+    elif isinstance(real_type, tp.Array):
         (base, dimsizes, sizeof_base,
          dimsizes_expr) = prepare_array_de_serialization(current_site,
                                                          real_type)
@@ -175,7 +167,7 @@ def construct_assign_apply(funname, intype):
                           else lookup_serialize(base))
 
         elem_serializer = expr.mkLit(current_site, serializer_ptr,
-                                     TPtr(serializer_t))
+                                     tp.Ptr(serializer_t))
         apply_expr = apply_c_fun(current_site, '_serialize_array',
                                  [ctree.mkAddressOf(current_site,
                                                     current_expr),
@@ -187,26 +179,26 @@ def construct_assign_apply(funname, intype):
         return ctree.AssignStatement(current_site, target_expr,
                                      ctree.ExpressionInitializer(apply_expr))
 
-    elif isinstance(real_type, (TStruct, TVector)):
+    elif isinstance(real_type, (tp.Struct, tp.Vector)):
         apply_expr = apply_c_fun(
             current_site, lookup_serialize(real_type),
             [ctree.mkAddressOf(current_site, current_expr)], attr_value_t)
         return ctree.AssignStatement(current_site, target_expr,
                                      ctree.ExpressionInitializer(apply_expr))
-    elif isinstance(real_type, TTrait):
+    elif isinstance(real_type, tp.Trait):
         id_infos = expr.mkLit(current_site, '_id_infos',
-                              TPtr(TNamed('_id_info_t', const = True)))
+                              tp.Ptr(tp.Named('_id_info_t', const = True)))
         identity_expr = ctree.StructMember(current_site, current_expr, "id",
-                                           TNamed("_identity_t"), ".")
+                                           tp.Named("_identity_t"), ".")
         apply_expr = apply_c_fun(current_site, "_serialize_identity",
                                  [id_infos, identity_expr], attr_value_t)
         return ctree.AssignStatement(current_site, target_expr,
                                      ctree.ExpressionInitializer(apply_expr))
-    elif isinstance(real_type, THook):
+    elif isinstance(real_type, tp.Hook):
         id_infos = expr.mkLit(current_site,
                               '_hook_id_infos' if objects.Device.hooks
                               else 'NULL',
-                              TPtr(TNamed('_id_info_t', const = True)))
+                              tp.Ptr(tp.Named('_id_info_t', const = True)))
         apply_expr = apply_c_fun(current_site, "_serialize_identity",
                                  [id_infos, current_expr], attr_value_t)
         return ctree.AssignStatement(current_site, target_expr,
@@ -224,23 +216,23 @@ def deserialize(real_type, current_expr, target_expr, error_out):
     current_site = current_expr.site
     def construct_assign_apply(attr_typ, intype, mod_apply_expr=lambda x: x):
         check_expr = apply_c_fun(current_site, 'SIM_attr_is_' + attr_typ,
-                                 [current_expr], TBool())
+                                 [current_expr], tp.Bool())
         apply_expr = mod_apply_expr(apply_c_fun(current_site,
                                                 'SIM_attr_' + attr_typ,
                                                 [current_expr], intype))
         error_stmts = error_out('Sim_Set_Illegal_Type', 'expected ' + attr_typ)
 
         target = target_expr
-        if real_type.const and not realtype(target_expr.ctype()).const:
+        if real_type.const and not tp.realtype(target_expr.ctype()).const:
             # This can happen if constness is inherited from a parent
             # deserialization of a struct type.
             # Rewrite target_expr to an equivalent lvalue with constified type,
-            # so that ExpressionInitializer's deep_const logic kicks in.
+            # so that ExpressionInitializer's tp.deep_const logic kicks in.
             target = ctree.mkDereference(
                 current_site,
                 ctree.mkCast(current_site,
                              ctree.mkAddressOf(current_site, target_expr),
-                             TPtr(real_type)))
+                             tp.Ptr(real_type)))
 
         return ctree.mkIf(current_site,
                           check_expr,
@@ -251,8 +243,8 @@ def construct_assign_apply(attr_typ, intype, mod_apply_expr=lambda x: x):
 
     def addressof_target_unconst():
         base = ctree.mkAddressOf(current_site, target_expr)
-        if deep_const(real_type):
-            base = ctree.mkCast(current_site, base, TPtr(void))
+        if tp.deep_const(real_type):
+            base = ctree.mkCast(current_site, base, tp.Ptr(tp.void))
         return base
 
     def construct_subcall(apply_expr):
@@ -263,7 +255,7 @@ def construct_subcall(apply_expr):
             ctree.ExpressionInitializer(apply_expr))
         check_expr = ctree.mkLit(current_site,
                                  f'{sub_success_arg.read()} != Sim_Set_Ok',
-                                 TBool())
+                                 tp.Bool())
         return ctree.mkCompound(current_site,
                                 [sub_success_decl, assign_stmt,
                                  ctree.mkIf(current_site, check_expr,
@@ -279,18 +271,18 @@ def mod_apply_expr(expr):
         else:
             def mod_apply_expr(expr):
                 return expr
-        return construct_assign_apply("integer", TInt(64, True),
+        return construct_assign_apply("integer", tp.Int(64, True),
                                       mod_apply_expr)
-    elif isinstance(real_type, TBool):
+    elif isinstance(real_type, tp.Bool):
         return construct_assign_apply("boolean", real_type)
-    elif isinstance(real_type, TFloat):
+    elif isinstance(real_type, tp.Float):
         return construct_assign_apply("floating", real_type)
-    elif isinstance(real_type, TArray):
+    elif isinstance(real_type, tp.Array):
         (base, dimsizes, sizeof_base,
          dimsizes_expr) = prepare_array_de_serialization(current_site,
                                                          real_type)
         elem_deserializer = expr.mkLit(current_site, lookup_deserialize(base),
-                                       TPtr(deserializer_t))
+                                       tp.Ptr(deserializer_t))
         # elems_are_bytes informs if the final dimension may either be
         # deserialized as a list or a data attribute value.
         # This is true for all integer types of width 8 bits
@@ -303,19 +295,19 @@ def mod_apply_expr(expr):
              ctree.mkIntegerLiteral(current_site, len(dimsizes)),
              elem_deserializer, elems_are_bytes], set_error_t)
         return construct_subcall(apply_expr)
-    elif isinstance(real_type, (TStruct, TVector)):
+    elif isinstance(real_type, (tp.Struct, tp.Vector)):
         apply_expr = apply_c_fun(
             current_site, lookup_deserialize(real_type),
             [current_expr, addressof_target_unconst()],
             set_error_t)
         return construct_subcall(apply_expr)
-    elif isinstance(real_type, TTrait):
+    elif isinstance(real_type, tp.Trait):
         id_info_ht = expr.mkLit(current_site, '&_id_info_ht',
-                                TPtr(TNamed('ht_str_table_t')))
+                                tp.Ptr(tp.Named('ht_str_table_t')))
         assert dml.globals.object_trait
         if real_type.trait is dml.globals.object_trait:
             object_vtable_array = expr.mkLit(current_site, '_object_vtables',
-                                             TPtr(TPtr(void, const=True)))
+                                             tp.Ptr(tp.Ptr(tp.void, const=True)))
             apply_expr = apply_c_fun(
                 current_site, '_deserialize_object_trait_reference',
                 [id_info_ht, object_vtable_array,
@@ -325,8 +317,8 @@ def mod_apply_expr(expr):
             vtable_name = real_type.trait.name
             vtable_ht = expr.mkLit(current_site,
                                    'NULL' if real_type.trait.empty()
-                                   else f'&_{cident(vtable_name)}_vtable_ht',
-                                   TPtr(TNamed('ht_int_table_t')))
+                                   else f'&_{tp.cident(vtable_name)}_vtable_ht',
+                                   tp.Ptr(tp.Named('ht_int_table_t')))
             apply_expr = apply_c_fun(
                 current_site, '_deserialize_trait_reference',
                 [id_info_ht, vtable_ht,
@@ -334,15 +326,15 @@ def mod_apply_expr(expr):
                  current_expr, addressof_target_unconst()],
                 set_error_t)
         return construct_subcall(apply_expr)
-    elif isinstance(real_type, THook):
+    elif isinstance(real_type, tp.Hook):
         id_info_ht = expr.mkLit(current_site,
                                 '&_hook_id_info_ht'
                                 if objects.Device.hooks else 'NULL',
-                                TPtr(TNamed('ht_str_table_t')))
+                                tp.Ptr(tp.Named('ht_str_table_t')))
         hook_aux_infos = expr.mkLit(current_site,
                                     '_hook_aux_infos'
                                     if objects.Device.hooks else 'NULL',
-                                    TPtr(const_void))
+                                    tp.Ptr(const_void))
         from .codegen import get_type_sequence_info
         expected_typ_uniq = ctree.mkIntegerConstant(
             current_site,
@@ -362,29 +354,29 @@ def mod_apply_expr(expr):
 def map_dmltype_to_attrtype(site, dmltype):
     "return attrtype string describing this dmltype"
     # raw data instead
-    real_type = safe_realtype(dmltype)
+    real_type = tp.safe_realtype(dmltype)
     # tints, endian_ints, and their bitfield variants can all be safely
     # stored in integer attributes
-    if isinstance(real_type, IntegerType):
+    if isinstance(real_type, tp.IntegerType):
         return 'i'
-    if isinstance(real_type, TBool):
+    if isinstance(real_type, tp.Bool):
         return 'b'
-    if isinstance(real_type, TFloat):
+    if isinstance(real_type, tp.Float):
         return 'f'
-    if isinstance(real_type, TStruct):
+    if isinstance(real_type, tp.Struct):
         return '[%s]' % "".join([map_dmltype_to_attrtype(site, mt)
                                  for (_, mt) in real_type.members])
-    if isinstance(real_type, TArray):
+    if isinstance(real_type, tp.Array):
         assert real_type.size.constant
         arr_attr_type = map_dmltype_to_attrtype(site, real_type.base)
         arr_length = expr_intval(real_type.size)
         # Byte arrays may use data values
         or_data = '|d' * (real_type.base.is_int and real_type.base.bits == 8)
         return '[%s{%s}]' % (arr_attr_type, arr_length) + or_data
-    if isinstance(real_type, (TTrait, THook)):
+    if isinstance(real_type, (tp.Trait, tp.Hook)):
         return '[s[i*]]'
     # TODO should be implemented
-    #if isinstance(real_type, TVector):
+    #if isinstance(real_type, tp.Vector):
         # return '[%s*]' % (map_dmltype_to_attrtype(site, real_type.base))
     raise ICE(site, 'unserializable type: %r' % (dmltype,))
 
@@ -392,23 +384,23 @@ def mark_for_serialization(site, dmltype):
     '''check a dml type for serializability and ensure artifacts needed for
     calls of serialize/deserialize to result in valid C are generated
     '''
-    real_type = safe_realtype(dmltype)
-    if isinstance(real_type, TStruct):
+    real_type = tp.safe_realtype(dmltype)
+    if isinstance(real_type, tp.Struct):
         for (_, mt) in real_type.members:
             mark_for_serialization(site, mt)
-    elif isinstance(real_type, TArray):
+    elif isinstance(real_type, tp.Array):
         # Can only serialize constant-size arrays
         if not real_type.size.constant:
-            raise messages.ESERIALIZE(site, dmltype)
+            raise E.SERIALIZE(site, dmltype)
         mark_for_serialization(site, real_type.base)
-    elif isinstance(real_type, TTrait):
+    elif isinstance(real_type, tp.Trait):
         dml.globals.serialized_traits.add(real_type.trait)
-    elif isinstance(real_type, THook):
+    elif isinstance(real_type, tp.Hook):
         real_type.validate(dmltype.declaration_site or site)
         from .codegen import get_type_sequence_info
         get_type_sequence_info(real_type.msg_types, create_new=True)
-    elif not isinstance(real_type, (IntegerType, TBool, TFloat)):
-        raise messages.ESERIALIZE(site, dmltype)
+    elif not isinstance(real_type, (tp.IntegerType, tp.Bool, tp.Float)):
+        raise E.SERIALIZE(site, dmltype)
 
 # generate a part of the function name from a description of the dmltype
 # Each type maps uniquely to a string, obeying the following invariants:
@@ -429,32 +421,32 @@ def mark_for_serialization(site, dmltype):
 # deserialization case the signatures should be separate.
 # Trait references are an example of such a type.
 def type_signature(dmltype, is_for_serialization):
-    dmltype = realtype(dmltype)
-    if isinstance(dmltype, TLong):
+    dmltype = tp.realtype(dmltype)
+    if isinstance(dmltype, tp.Long):
         return f'IL{"s" if dmltype.signed else "u"}'
-    if isinstance(dmltype, TSize):
+    if isinstance(dmltype, tp.Size):
         return f'IS{"s" if dmltype.signed else "u"}'
-    if isinstance(dmltype, IntegerType):
+    if isinstance(dmltype, tp.IntegerType):
         return 'I%d%s%s' % (dmltype.bits,
                             dmltype.byte_order[0] if dmltype.is_endian else "h",
                             "s" if dmltype.signed else "u")
-    if isinstance(dmltype, TBool):
+    if isinstance(dmltype, tp.Bool):
         return 'B'
-    if isinstance(dmltype, TFloat):
+    if isinstance(dmltype, tp.Float):
         return {'double': 'Fd', 'float': 'Fs'}[dmltype.name]
-    if isinstance(dmltype, TStruct):
+    if isinstance(dmltype, tp.Struct):
         return 'S' + dmltype.label
-    if isinstance(dmltype, TArray):
+    if isinstance(dmltype, tp.Array):
         assert dmltype.size.constant
         arr_attr_type = type_signature(dmltype.base, is_for_serialization)
         arr_length = expr_intval(dmltype.size)
         return 'A%d%s' % (arr_length, arr_attr_type)
-    if isinstance(dmltype, TVector):
+    if isinstance(dmltype, tp.Vector):
         return 'V%s' % type_signature(dmltype.base, is_for_serialization)
-    if isinstance(dmltype, TTrait):
-        return 'T' + (cident(dmltype.trait.name)
+    if isinstance(dmltype, tp.Trait):
+        return 'T' + (tp.cident(dmltype.trait.name)
                       if not is_for_serialization else '')
-    if isinstance(dmltype, THook):
+    if isinstance(dmltype, tp.Hook):
         from .codegen import get_type_sequence_info
         suffix = (str(get_type_sequence_info(dmltype.msg_types).uniq)
                   if not is_for_serialization else '')
@@ -498,14 +490,14 @@ def generate_serialize(real_type):
         f"")
     function_name = "DML_serialize_%s" % type_signature(real_type, True)
 
-    in_arg_ty = TPtr(real_type)
-    (_, in_arg_uncasted) = declare_variable(site, "_in", TPtr(const_void))
+    in_arg_ty = tp.Ptr(real_type)
+    (_, in_arg_uncasted) = declare_variable(site, "_in", tp.Ptr(const_void))
     (in_arg_decl, in_arg) = declare_variable(
         site, "in", in_arg_ty, ctree.mkCast(site, in_arg_uncasted, in_arg_ty))
     (out_arg_decl, out_arg) = declare_variable(site, "out", attr_value_t)
     function_decl = "attr_value_t %s(%s)" % (
         function_name,
-        TPtr(const_void).declaration("_in"))
+        tp.Ptr(const_void).declaration("_in"))
     serialize_prototypes.append(function_decl)
 
     func_code = output.StrOutput()
@@ -514,18 +506,18 @@ def generate_serialize(real_type):
         # cast void* inarg to the correct type
         in_arg_decl.toc()
         out_arg_decl.toc()
-        if isinstance(real_type, TStruct):
+        if isinstance(real_type, tp.Struct):
             sources = (
                 (mkSubRefLit(
-                    site, in_arg, name or TStruct.anon_member_cident(i),
+                    site, in_arg, name or tp.Struct.anon_member_cident(i),
                     typ, "->"),
-                 safe_realtype(typ))
+                 tp.safe_realtype(typ))
                 for (i, (name, typ)) in enumerate(real_type.members))
             serialize_sources_to_list(site, sources, out_arg)
-        elif isinstance(real_type, TVector):
+        elif isinstance(real_type, tp.Vector):
             raise ICE(site, "TODO: serialize vector")
-        elif isinstance(real_type, (IntegerType, TBool, TFloat, TTrait,
-                                    TArray, THook)):
+        elif isinstance(real_type, (tp.IntegerType, tp.Bool, tp.Float, tp.Trait,
+                                    tp.Array, tp.Hook)):
             serialize(real_type,
                       ctree.mkDereference(site, in_arg),
                       out_arg).toc()
@@ -569,7 +561,7 @@ def sub_error_out(exc, msg):
             statements.append(sub_deserialize)
         else:
             is_not_nil_expr = expr.mkLit(site, '!SIM_attr_is_nil(_imm_attr)',
-                                         TBool())
+                                         tp.Bool())
             statements.append(ctree.mkIf(
                 site, is_not_nil_expr,
                 ctree.mkCompound(
@@ -581,10 +573,10 @@ def sub_error_out(exc, msg):
                         + f' during {error_context}' * bool(error_context)
                     ))))
     deserialization = ctree.mkCompound(site, statements)
-    attr_is_list = apply_c_fun(site, "SIM_attr_is_list", [val_attr], TBool())
+    attr_is_list = apply_c_fun(site, "SIM_attr_is_list", [val_attr], tp.Bool())
 
     attr_list_size = apply_c_fun(site, "SIM_attr_list_size", [val_attr],
-                                 TInt(32, False))
+                                 tp.Int(32, False))
     attr_list_size_check = ctree.mkEquals(
         site, attr_list_size,
         ctree.mkIntegerConstant(site, len(targets), False))
@@ -607,16 +599,16 @@ def generate_deserialize(real_type):
         f"")
     function_name = "DML_deserialize_%s" % type_signature(real_type, False)
 
-    out_arg_ty = TPtr(real_type)
+    out_arg_ty = tp.Ptr(real_type)
     (_, in_arg) = declare_variable(site, "in", attr_value_t)
-    (_, out_arg_uncasted) = declare_variable(site, "_out", TPtr(void))
+    (_, out_arg_uncasted) = declare_variable(site, "_out", tp.Ptr(tp.void))
     (out_arg_decl, out_arg) = declare_variable(
         site, "out", out_arg_ty,
         ctree.mkCast(site, out_arg_uncasted, out_arg_ty))
     function_decl = "set_error_t %s(%s, %s)" % (
         function_name,
         attr_value_t.declaration("in"),
-        TPtr(void).declaration("_out"))
+        tp.Ptr(tp.void).declaration("_out"))
     serialize_prototypes.append(function_decl)
 
     func_code = output.StrOutput()
@@ -633,19 +625,19 @@ def error_out(exc, msg):
                     ctree.mkInline(site, f'SIM_attribute_error("{msg}");'))
             stmts.append(ctree.mkInline(site, 'goto _exit;'))
             return stmts
-        if isinstance(real_type, TStruct):
+        if isinstance(real_type, tp.Struct):
             (tmp_out_decl, tmp_out_ref) = declare_variable(
-                site, "_tmp_out", TPtr(real_type),
+                site, "_tmp_out", tp.Ptr(real_type),
                 ctree.mkNew(site, real_type))
-            cleanup_ref = (tmp_out_ref if not deep_const(real_type)
-                           else ctree.mkCast(site, tmp_out_ref, TPtr(void)))
+            cleanup_ref = (tmp_out_ref if not tp.deep_const(real_type)
+                           else ctree.mkCast(site, tmp_out_ref, tp.Ptr(tp.void)))
             cleanup.append(ctree.mkDelete(site, cleanup_ref))
             tmp_out_decl.toc()
             targets = tuple(
                 (mkSubRefLit(
                     site, tmp_out_ref,
-                    name or TStruct.anon_member_cident(i), typ, "->"),
-                 conv_const(real_type.const, safe_realtype(typ)))
+                    name or tp.Struct.anon_member_cident(i), typ, "->"),
+                 tp.conv_const(real_type.const, tp.safe_realtype(typ)))
                 for (i, (name, typ)) in enumerate(real_type.members))
             def error_out_at_index(_i, exc, msg):
                 return error_out(exc, msg)
@@ -658,10 +650,10 @@ def error_out_at_index(_i, exc, msg):
                                         ctree.mkDereference(
                                             site, tmp_out_ref))).toc()
 
-        elif isinstance(real_type, TVector):
+        elif isinstance(real_type, tp.Vector):
             raise ICE(site, "TODO: serialize vector")
-        elif isinstance(real_type, (IntegerType, TBool, TFloat, TTrait,
-                                    TArray, THook)):
+        elif isinstance(real_type, (tp.IntegerType, tp.Bool, tp.Float, tp.Trait,
+                                    tp.Array, tp.Hook)):
             deserialize(real_type,
                         in_arg,
                         ctree.mkDereference(site, out_arg),
diff --git a/py/dml/slotsmeta_test.py b/py/dml/slotsmeta_test.py
index a1f27d27e..a4b0828a8 100644
--- a/py/dml/slotsmeta_test.py
+++ b/py/dml/slotsmeta_test.py
@@ -3,7 +3,7 @@
 
 import unittest
 
-from dml.slotsmeta import *
+from dml.slotsmeta import auto_init, SlotsMeta
 
 # Silence 'unused' warnings from fisketur
 def use(o): pass
@@ -88,4 +88,3 @@ class Sub1(Base):
             def __init__(self, x, y):
                 self.x += self.y
         self.assertEqual(Sub1(4, 1).x, 9)
-
diff --git a/py/dml/structure.py b/py/dml/structure.py
index 604f03873..69a8d1ed5 100644
--- a/py/dml/structure.py
+++ b/py/dml/structure.py
@@ -4,28 +4,29 @@
 # Structure stuff
 
 import itertools
-import collections
-import abc
 import re
 from contextlib import ExitStack
 import functools
 import operator
-from . import objects, logging, crep, ast
+from . import objects, expr_util, logging, crep, ast
 from . import traits
-from . import toplevel
 from . import topsort
 from . import slotsmeta
 from . import ctree
-from . import env
 from . import serialize
-from .logging import *
-from .codegen import *
-from .symtab import *
-from .expr import *
-from .ctree import *
-from .expr_util import *
-from .messages import *
-from .types import *
+from .logging import ICE, report, DMLError
+from . import codegen
+from .codegen import eval_type
+from .symtab import global_scope
+from .expr import Expression, mkLit, mkNullConstant, NonValue, StaticIndex
+from . import ctree as c
+from . import porting as P
+from .expr_util import (
+    defined, param_bool, param_defined, param_expr,
+    param_expr_site, param_int, param_str,
+    static_indices)
+from . import errors as E, warnings as W
+from . import types as tp
 import dml.globals
 from . import template
 from .template import Rank, RankDesc, ObjectSpec, InstantiatedTemplateSpec
@@ -54,7 +55,7 @@ def check_constant_expr(expr):
     proper value, or (recursively) a list of proper values; raise an
     error otherwise.'''
     if isinstance(expr, NonValue):
-        if isinstance(expr, List):
+        if isinstance(expr, c.List):
             for sub in expr.value:
                 check_constant_expr(sub)
         else:
@@ -105,7 +106,7 @@ def mkglobals(stmts):
 
         if len(nonextern_clash) > 1 or (extern_clash and nonextern_clash):
             second = extern_clash[0] if extern_clash else nonextern_clash[1]
-            report(ENAMECOLL(nonextern_clash[0].site, second.site, name))
+            report(E.NAMECOLL(nonextern_clash[0].site, second.site, name))
             stmts.remove(nonextern_clash[0])
             # retry with duplicate removed
             mkglobals(stmts)
@@ -117,13 +118,13 @@ def mkglobals(stmts):
         try:
             if stmt[0] == 'constant':
                 _, site, name, expr = stmt
-                expr = codegen_expression_maybe_nonvalue(
+                expr = codegen.codegen_expression_maybe_nonvalue(
                     expr, None, global_scope)
                 check_constant_expr(expr)
                 if expr.constant:
-                    global_scope.add(ExpressionSymbol(name, expr, site))
+                    global_scope.add(c.ExpressionSymbol(name, expr, site))
                 else:
-                    raise ENCONST(expr, expr)
+                    raise E.NCONST(expr, expr)
         except DMLError as e:
             report(e)
 
@@ -132,7 +133,7 @@ def mkglobals(stmts):
     new_symbols = []
     # all non-extern anonymous struct types, str -> type
     anonymous_structs = {}
-    # names of non-extern typedefs
+    # names of non-extern tp.typedefs
     new_typedefs = set()
     # Duplicate extern declarations
     extern_clashes = {}
@@ -180,8 +181,8 @@ def mkglobals(stmts):
                     assert dml.globals.dml_version == (1, 2)
                     if (breaking_changes.dml12_remove_misc_quirks.enabled
                         and not site.filename().endswith('simics-api.dml')):
-                        report(EEXTERN(stmt.site))
-                    typ = TUnknown()
+                        report(E.EXTERN(stmt.site))
+                    typ = tp.Unknown()
                 else:
                     (struct_defs, typ) = eval_type(
                         typ, site, None, global_scope, extern=True,
@@ -191,36 +192,36 @@ def mkglobals(stmts):
                 if name in externs:
                     extern_clashes.setdefault(name, []).append((site, typ))
                 else:
-                    new_symbols.append(LiteralSymbol(name, typ, site))
+                    new_symbols.append(c.LiteralSymbol(name, typ, site))
                     externs[name] = (site, typ)
 
             elif stmt[0] == 'extern_typedef':
                 (_, site, (_, _, name, typ)) = stmt
-                assert not typedefs.get(name, None)
+                assert not tp.typedefs.get(name, None)
                 (struct_defs, typ) = eval_type(
                     typ, site, None, global_scope, typename=name, extern=True,
                     allow_void=True)
                 # any substructs are converted to anonymous extern structs
                 assert not struct_defs
-                typedefs[name] = typ
+                tp.typedefs[name] = typ
             elif stmt[0] == 'dml_typedef':
                 (_, site, (_, _, name, typ)) = stmt
-                assert not typedefs.get(name, None)
+                assert not tp.typedefs.get(name, None)
                 (struct_defs, typ) = eval_type(typ, site, None, global_scope,
                                                typename=name, allow_void=True)
                 for (_, t) in struct_defs:
                     if t is not typ:
                         anonymous_structs[t.label] = t
-                typedefs[name] = typ
+                tp.typedefs[name] = typ
                 assert name not in new_typedefs
                 new_typedefs.add(name)
             elif stmt[0] == 'loggroup':
                 _, site, name = stmt
                 if len(dml.globals.log_groups) >= 63:
-                    report(ELOGGROUPS(site))
+                    report(E.LOGGROUPS(site))
                 dml.globals.log_groups.append(name)
-                new_symbols.append(ExpressionSymbol(
-                    name, LogGroup(site, name), site))
+                new_symbols.append(c.ExpressionSymbol(
+                    name, c.LogGroup(site, name), site))
             elif stmt.kind != 'constant': # handled above
                 raise ICE(stmt.site, 'bad AST kind: %s' % (stmt.kind,))
         except DMLError as e:
@@ -236,38 +237,38 @@ def mkglobals(stmts):
 
     for (tname, tpl) in list(dml.globals.templates.items()):
         if tpl.trait:
-            assert tname not in typedefs
+            assert tname not in tp.typedefs
             trait_type = tpl.trait.type()
             # any name collisions were caught earlier with ENAMECOLL
-            typedefs[tname] = trait_type
+            tp.typedefs[tname] = trait_type
 
     type_declaration_order = sort_type_declarations(new_typedefs,
                                                     anonymous_structs)
-    global_type_declaration_order[:] = type_declaration_order
-    global_anonymous_structs.clear()
-    global_anonymous_structs.update(anonymous_structs)
+    tp.global_type_declaration_order[:] = type_declaration_order
+    tp.global_anonymous_structs.clear()
+    tp.global_anonymous_structs.update(anonymous_structs)
 
     if breaking_changes.forbid_broken_unused_types.enabled:
-        for t in typedefs.values():
+        for t in tp.typedefs.values():
             try:
-                check_named_types(t)
-            except ETYPE as e:
+                tp.check_named_types(t)
+            except E.TYPE as e:
                 report(e)
         for sym in new_symbols:
             try:
-                check_named_types(sym.type)
-            except ETYPE as e:
+                tp.check_named_types(sym.type)
+            except E.TYPE as e:
                 report(e)
     elif dml.globals.dml_version != (1, 2):
-        for t in typedefs.values():
+        for t in tp.typedefs.values():
             try:
-                safe_realtype(t)
-            except ETYPE as e:
+                tp.safe_realtype(t)
+            except E.TYPE as e:
                 report(e)
         for sym in new_symbols:
             try:
-                safe_realtype(sym.type)
-            except ETYPE as e:
+                tp.safe_realtype(sym.type)
+            except E.TYPE as e:
                 report(e)
 
     for t in dml.globals.traits.values():
@@ -276,23 +277,23 @@ def mkglobals(stmts):
     # Resolve duplicate externs
     for (name, clashes) in extern_clashes.items():
         (canonical_site, canonical_t) = externs[name]
-        canonical_rt = safe_realtype(canonical_t)
+        canonical_rt = tp.safe_realtype(canonical_t)
         for (site, typ) in clashes:
             try:
-                if not canonical_rt.eq(safe_realtype(typ)):
-                    report(EEXTERNINCOMP(site, canonical_site, name, typ,
+                if not canonical_rt.eq(tp.safe_realtype(typ)):
+                    report(E.EXTERNINCOMP(site, canonical_site, name, typ,
                                          canonical_t))
-            except ETYPE as e:
+            except E.TYPE as e:
                 report(e)
 
 def type_deps(t, include_structs, expanded_typedefs):
     '''Given that t appears inside a DML typedef, return the set of DML
-    typedefs that need to appear before this typedef in generated C
+    tp.typedefs that need to appear before this typedef in generated C
     code. The location of a named struct ("typedef struct { ... } t;"
     in DML) in the dependency graph refers to the struct definition in
     C code ("struct t { ... }"); the type definition/struct
     declaration ("typedef struct t t;") appears
-    before all other typedefs in generated C code.
+    before all other tp.typedefs in generated C code.
 
     include_structs controls whether named structs count as
     dependencies. They do count for struct members and array types, since
@@ -300,10 +301,10 @@ def type_deps(t, include_structs, expanded_typedefs):
 
     expanded_typedefs is used to avoid infinite recursion.
     '''
-    if isinstance(t, TNamed):
-        if t.c not in typedefs:
-            raise ETYPE(t.declaration_site, t)
-        if isinstance(typedefs[t.c], TStruct):
+    if isinstance(t, tp.Named):
+        if t.c not in tp.typedefs:
+            raise E.TYPE(t.declaration_site, t)
+        if isinstance(tp.typedefs[t.c], tp.Struct):
             if include_structs:
                 if t.c in expanded_typedefs:
                     return [t.c]
@@ -314,13 +315,13 @@ def type_deps(t, include_structs, expanded_typedefs):
                 #  typedef struct { B b; } C;
                 # Here, B does not depend on A, but C
                 # depends on A via B.
-                return [t.c] + type_deps(typedefs[t.c], True,
+                return [t.c] + type_deps(tp.typedefs[t.c], True,
                                          expanded_typedefs + [t.c])
             else:
                 return []
         else:
             return [t.c]
-    elif isinstance(t, TStruct):
+    elif isinstance(t, tp.Struct):
         t.resolve()
         deps = []
         if include_structs:
@@ -328,36 +329,31 @@ def type_deps(t, include_structs, expanded_typedefs):
         for (_, mt) in t.members:
             deps.extend(type_deps(mt, True, expanded_typedefs))
         return deps
-    elif isinstance(t, TArray):
+    elif isinstance(t, tp.Array):
         return type_deps(t.base, True, expanded_typedefs)
-    elif isinstance(t, (TPtr, TVector)):
+    elif isinstance(t, (tp.Ptr, tp.Vector)):
         return type_deps(t.base, False, expanded_typedefs)
-    elif isinstance(t, TFunction):
+    elif isinstance(t, tp.Function):
         return ([dep for pt in t.input_types
                  for dep in type_deps(pt, False, expanded_typedefs)]
                 + type_deps(t.output_type, False, expanded_typedefs))
-    elif isinstance(t, (IntegerType, TVoid, TBool, TFloat, TTrait)):
+    elif isinstance(t, (tp.IntegerType, tp.Void, tp.Bool, tp.Float, tp.Trait)):
         return []
-    elif isinstance(t, TExternStruct):
+    elif isinstance(t, tp.ExternStruct):
         # extern structs are assumed to be self-contained
         return []
     else:
         raise ICE(t.declaration_site, "unknown type %r" % t)
 
-def remove_type(name):
-    del typedefs[name]
-    if name in new_global_types:
-        new_global_types.remove(name)
-
 def sort_type_declarations(new_typedefs, anonymous_structs):
     deps = {}
-    for name in typedefs:
+    for name in tp.typedefs:
         if name in new_typedefs:
             try:
-                deplist = type_deps(typedefs[name], False, [])
+                deplist = type_deps(tp.typedefs[name], False, [])
             except DMLError as e:
                 report(e)
-                del typedefs[name]
+                del tp.typedefs[name]
                 return sort_type_declarations(new_typedefs - {name},
                                               anonymous_structs)
             else:
@@ -374,18 +370,18 @@ def sort_type_declarations(new_typedefs, anonymous_structs):
     try:
         type_order = topsort.topsort(deps)
     except topsort.CycleFound as e:
-        report(ETREC([typedefs[n].declaration_site for n in e.cycle
-                      if n in typedefs],
-                     typedefs[e.cycle[0]]))
+        report(E.TREC([tp.typedefs[n].declaration_site for n in e.cycle
+                      if n in tp.typedefs],
+                     tp.typedefs[e.cycle[0]]))
         for n in e.cycle:
-            del typedefs[n]
+            del tp.typedefs[n]
         # retry with this cycle removed
         return sort_type_declarations(
             new_typedefs.difference(e.cycle), anonymous_structs)
     # TODO: we could check that no extern typedef depends on a
     # non-extern typedef, SIMICS-9987
     return [n for n in type_order
-            # exclude extern typedefs
+            # exclude extern tp.typedefs
             if n in new_typedefs or n in anonymous_structs]
 
 unused_field_methods = {'after_read',
@@ -451,12 +447,12 @@ def check_unused_and_warn(node):
     not used. This usually applies to methods and parameters."""
 
     if node.refcount == 0:
-        if not warning_is_ignored('WUNUSED'):
-            report(WUNUSED(node))
+        if not logging.warning_is_ignored('WUNUSED'):
+            report(W.UNUSED(node))
         elif is_unused_default(node):
-            report(WUNUSEDDEFAULT(node))
+            report(W.UNUSEDDEFAULT(node))
         elif dml.globals.dml_version != (1, 2) and is_dml12_method(node):
-            report(WUNUSED_DML12(node))
+            report(W.UNUSED_DML12(node))
 
     for n in node.get_components():
         check_unused_and_warn(n)
@@ -544,7 +540,7 @@ def add_templates(obj_specs, each_stmts):
                 # stricter checking in 1.2, because that doesn't hurt.
                 breaking_changes.forbid_broken_conditional_is.enabled
                 or not breaking_changes.dml12_remove_misc_quirks.enabled)):
-            report(ENTMPL(site, tpl.name))
+            report(E.NTMPL(site, tpl.name))
             continue
         if tpl in used_templates:
             continue
@@ -553,7 +549,7 @@ def add_templates(obj_specs, each_stmts):
             obj_spec = tpl.spec
         else:
             obj_spec = InstantiatedTemplateSpec(
-                tpl, *wrap_sites(TemplateSite, tpl.spec, site, tpl.name))
+                tpl, *wrap_sites(logging.TemplateSite, tpl.spec, site, tpl.name))
         used_templates[tpl] = obj_spec
 
         for (tpls, orig_tpls, spec) in each_stmts.get(tpl, []):
@@ -571,7 +567,7 @@ def add_templates(obj_specs, each_stmts):
             else:
                 # All templates match; expand the each statement.
                 obj_specs.append(
-                    ObjectSpec(*wrap_sites(InEachSite, spec, spec.site,
+                    ObjectSpec(*wrap_sites(logging.InEachSite, spec, spec.site,
                                            [t.name for t in orig_tpls])))
                 queue.extend(spec.templates)
 
@@ -579,7 +575,7 @@ def add_templates(obj_specs, each_stmts):
         queue.extend(obj_spec.templates)
 
     if logging.show_porting:
-        PWUNUSED.used_templates.update(used_templates)
+        P.WUNUSED.used_templates.update(used_templates)
 
     return (obj_specs, used_templates)
 
@@ -623,9 +619,9 @@ def merge_parameters(params, obj_specs):
         for (_, p) in params:
             (name, _, _, value) = p.args
             if value is not None:
-                raise EAUTOPARAM(p.site, name)
+                raise E.AUTOPARAM(p.site, name)
         if len(autos) != 1:
-            raise EAUTOPARAM(autos[0].site, autos[0].args[0])
+            raise E.AUTOPARAM(autos[0].site, autos[0].args[0])
         return autos[0]
 
     if dml.globals.dml_version == (1, 2):
@@ -643,13 +639,13 @@ def merge_parameters(params, obj_specs):
             decls[rank] = param
         else:
             if rank in defs:
-                raise ENAMECOLL(param.site, defs[rank].site, name)
+                raise E.NAMECOLL(param.site, defs[rank].site, name)
             defs[rank] = param
 
     if not defs:
         [decl, *_] = decls.values()
         (name, _, _, _) = decl.args
-        raise ENPARAM(decl.site, name)
+        raise E.NPARAM(decl.site, name)
 
     all_inferior = set().union(*(rank.inferior for rank in defs))
     superior = [(rank, p) for (rank, p) in defs.items()
@@ -665,7 +661,7 @@ def decl_is_default(decl):
         [(rank1, p1), (rank2, p2)] = sorted(
             superior, key=decl_is_default)[:2]
         (name, _, _, _) = p1.args
-        raise EAMBINH(
+        raise E.AMBINH(
             p1.site, p2.site, name, rank1.desc, rank2.desc,
             decl_is_default((rank1, p1)))
 
@@ -684,14 +680,14 @@ def decl_is_default(decl):
             if not declared_as_override and parent_ranks:
                 [parent, *_] = (parent for (parent_rank, parent) in params
                                 if parent_rank in parent_ranks)
-                report(EOVERRIDEPARAM(type_info.site, parent.site, name,
+                report(E.OVERRIDEPARAM(type_info.site, parent.site, name,
                                       'default' if is_default else '='))
             if not declared_as_override and rank in decls:
-                report(EOVERRIDEPARAM(type_info.site, decls[rank].site, name,
+                report(E.OVERRIDEPARAM(type_info.site, decls[rank].site, name,
                                       'default' if is_default else '='))
             elif (not parent_ranks and declared_as_override
                   and rank not in decls):
-                report(ENOVERRIDEPARAM(
+                report(E.NOVERRIDEPARAM(
                     p.site, name, 'default' if is_default else '='))
 
     [(rank0, param0)] = superior
@@ -700,7 +696,7 @@ def decl_is_default(decl):
         (name, _, is_default, _) = param.args
         if not is_default and rank is not rank0:
             # Attempt to override non-default parameter
-            report(EINVOVER(param0.site, param.site, name))
+            report(E.INVOVER(param0.site, param.site, name))
             return param
 
     if dml.globals.dml_version == (1, 2):
@@ -708,10 +704,10 @@ def decl_is_default(decl):
         if len(defs) == 2:
             (_, _, is_default, _) = param0.args
             if is_default:
-                report(WEXPERIMENTAL(
+                report(W.EXPERIMENTAL(
                     param0.site, "parameter with two default declarations"))
         elif len(defs) > 2:
-            report(WEXPERIMENTAL(
+            report(W.EXPERIMENTAL(
                 param0.site, "more than one level of parameter overrides"))
 
     return param0
@@ -732,9 +728,9 @@ def typecheck_method_override(m1, m2, location):
 
     # We should also check parameter types here (SIMICS-9337)
     if len(inp1) != len(inp2):
-        raise EMETH(m1.site, m2.site, "different number of input parameters")
+        raise E.METH(m1.site, m2.site, "different number of input parameters")
     if len(outp1) != len(outp2):
-        raise EMETH(m1.site, m2.site, "different number of output parameters")
+        raise E.METH(m1.site, m2.site, "different number of output parameters")
     for (idx, (a1, a2)) in enumerate(zip(inp1, inp2)):
         ((n1, t1), (n2, t2)) = (a1.args, a2.args)
         if (t1 is None) != (t2 is None):
@@ -752,17 +748,17 @@ def typecheck_method_override(m1, m2, location):
                         # Not that we really EXPECT the discard identifier here
                         ident = n1.args[0] if n1.kind == 'variable' else '_'
 
-                        report(PINARGTYPE(a1.site, type2.declaration(ident)))
+                        report(P.INARGTYPE(a1.site, type2.declaration(ident)))
             else:
-                raise EMETH(m1.site, m2.site, "different inline args")
+                raise E.METH(m1.site, m2.site, "different inline args")
         if (t1 and t2
             and a1.site.dml_version() != (1, 2)
             and a2.site.dml_version() != (1, 2)):
             # TODO move to caller
             (_, type1) = eval_type(t1, a1.site, location, global_scope)
             (_, type2) = eval_type(t2, a2.site, location, global_scope)
-            type1 = safe_realtype_unconst(type1)
-            type2 = safe_realtype_unconst(type2)
+            type1 = tp.safe_realtype_unconst(type1)
+            type2 = tp.safe_realtype_unconst(type2)
 
             ok = (type1.eq_fuzzy(type2)
                   if not breaking_changes.strict_typechecking.enabled
@@ -770,7 +766,7 @@ def typecheck_method_override(m1, m2, location):
             if not ok:
                 ref = f"'{n1.args[0]}'" if n1.kind == 'variable' else (idx + 1)
 
-                raise EMETH(a1.site, a2.site,
+                raise E.METH(a1.site, a2.site,
                             f"mismatching types in input argument {ref}")
 
     for (i, (a1, a2)) in enumerate(zip(outp1, outp2)):
@@ -778,8 +774,8 @@ def typecheck_method_override(m1, m2, location):
             ((n1, t1), (n2, t2)) = (a1.args, a2.args)
             (_, type1) = eval_type(t1, a1.site, location, global_scope)
             (_, type2) = eval_type(t2, a2.site, location, global_scope)
-            type1 = safe_realtype_unconst(type1)
-            type2 = safe_realtype_unconst(type2)
+            type1 = tp.safe_realtype_unconst(type1)
+            type2 = tp.safe_realtype_unconst(type2)
             ok = (type1.eq_fuzzy(type2)
                   if not breaking_changes.strict_typechecking.enabled
                   else type1.eq(type2))
@@ -787,17 +783,17 @@ def typecheck_method_override(m1, m2, location):
                 msg = "mismatching types in return value"
                 if len(outp1) > 1:
                     msg += f" {i + 1}"
-                raise EMETH(a1.site, a2.site, msg)
+                raise E.METH(a1.site, a2.site, msg)
 
     if (logging.show_porting
         and all(a2.args[1] for a2 in inp2)
         and any(not a1.args[1] for a1 in inp1)):
         # hack to change 'inline method' -> 'method' if needed
-        report(PINARGTYPE(m1.site, 'method'))
+        report(P.INARGTYPE(m1.site, 'method'))
 
     def qualifier_check(qualifier_name, qualifier1, qualifier2):
         if qualifier1 != qualifier2:
-            raise EMETH(m1.site, m2.site,
+            raise E.METH(m1.site, m2.site,
                         (f"one declaration is qualified as {qualifier_name}, "
                          + "but the other is not"))
 
@@ -815,19 +811,19 @@ def report_poverride(sup, inf, obj_specs):
     assert sup_objs
     for sup_obj in sup_objs:
         if inf.desc.kind == 'template':
-            report(POVERRIDE(sup_obj.site, inf.desc.text))
+            report(P.OVERRIDE(sup_obj.site, inf.desc.text))
         else:
-            report(POVERRIDE_IMPORT(sup_obj.site, inf.desc.text))
+            report(P.OVERRIDE_IMPORT(sup_obj.site, inf.desc.text))
 
 def merge_subobj_defs(name, defs, parent):
     specs = [spec for (_, _, _, spec) in defs]
     (objtype, arrayinfo, _, _) = defs[0]
     for (ot, ai, _, spec) in defs[1:]:
         if ot != objtype:
-            report(ENAMECOLL(specs[0].site, spec.site, name))
+            report(E.NAMECOLL(specs[0].site, spec.site, name))
             return merge_subobj_defs(name, defs[1:], parent)
         if len(ai) != len(arrayinfo):
-            raise EAINCOMP(specs[0].site, spec.site, name,
+            raise E.AINCOMP(specs[0].site, spec.site, name,
                            "mixing declarations with different number "
                            "of array dimensions")
 
@@ -836,7 +832,7 @@ def merge_subobj_defs(name, defs, parent):
     # False -> explicit decl
     if all(extension_status is True for (_, _, extension_status, _) in defs):
         for spec in specs:
-            report(EEXTENSION(spec.site, name))
+            report(E.EXTENSION(spec.site, name))
 
     explicit_decls = [
         spec for (_, _, extension_status, spec) in defs if extension_status is False]
@@ -850,11 +846,11 @@ def merge_subobj_defs(name, defs, parent):
                 lowest = other
         for decl in explicit_decls:
             if decl is not lowest:
-                report(EMULTIOBJDECL(decl.site, lowest.site, objtype, name))
+                report(E.MULTIOBJDECL(decl.site, lowest.site, objtype, name))
 
     merged_arrayinfo = []
     if arrayinfo:
-        parent_scope = Location(parent, static_indices(parent))
+        parent_scope = c.Location(parent, static_indices(parent))
         for (dim_i, dim) in enumerate(
                 zip(*(arrayinfo for (_, arrayinfo, _, _) in defs))):
             (idxvar_asts, len_asts) = zip(*dim)
@@ -871,19 +867,19 @@ def merge_subobj_defs(name, defs, parent):
                 [(idxvar, first_asts), *rest] = candidates.items()
                 for (_, conflicting_asts) in rest:
                     for ast in conflicting_asts:
-                        report(EAINCOMP(
+                        report(E.AINCOMP(
                             ast.site, first_asts[0].site, name,
                             "mismatching index variables"))
 
             candidates = {}
             for len_ast in len_asts:
                 if len_ast is not None:
-                    length = eval_arraylen(len_ast, parent_scope)
+                    length = codegen.eval_arraylen(len_ast, parent_scope)
                     candidates.setdefault(length, []).append(len_ast)
             if len(candidates) == 0:
                 idxref = (f" (with index variable '{idxvar}')"
                           if idxvar else "")
-                report(EAUNKDIMSIZE(specs[0].site, dim_i, idxref))
+                report(E.AUNKDIMSIZE(specs[0].site, dim_i, idxref))
                 length = 1
                 lensite = specs[0].site
             else:
@@ -891,7 +887,7 @@ def merge_subobj_defs(name, defs, parent):
                 lensite = asts[0].site
                 for (_, asts) in rest:
                     for ast in asts:
-                        report(EAINCOMP(ast.site, lensite, name,
+                        report(E.AINCOMP(ast.site, lensite, name,
                                         "mismatching array sizes"))
 
             merged_arrayinfo.append((idxvar, length, lensite))
@@ -911,37 +907,37 @@ def method_is_std(node, methname):
 def mkdata(spec, parent):
     site, name, typ, astinit = spec
 
-    parent_scope = Location(parent, static_indices(parent))
+    parent_scope = c.Location(parent, static_indices(parent))
     (struct_defs, dtype) = eval_type(
         typ, site, parent_scope, global_scope)
     dtype = dtype.resolve()
-    add_late_global_struct_defs(struct_defs)
+    tp.add_late_global_struct_defs(struct_defs)
     obj = objects.Session(name, dtype, astinit, site, parent)
     if astinit:
         dml.globals.device.add_init_data(obj)
     try:
-        realtype(crep.node_storage_type(obj))
-    except DMLUnknownType as e:
-        raise ETYPE(obj, e.type)
+        tp.realtype(crep.node_storage_type(obj))
+    except tp.DMLUnknownType as e:
+        raise E.TYPE(obj, e.type)
     return obj
 
 def mksaved(spec, parent):
     site, name, typ, astinit = spec
 
-    parent_scope = Location(parent, static_indices(parent))
+    parent_scope = c.Location(parent, static_indices(parent))
     (struct_defs, dtype) = eval_type(typ, site, parent_scope, global_scope)
-    add_late_global_struct_defs(struct_defs)
+    tp.add_late_global_struct_defs(struct_defs)
     dtype.resolve()
-    if deep_const(dtype):
-        raise ESAVEDCONST(site, dtype)
+    if tp.deep_const(dtype):
+        raise E.SAVEDCONST(site, dtype)
     obj = objects.Saved(name, dtype, astinit, site, parent)
     if astinit:
         dml.globals.device.add_init_data(obj)
     typ = crep.node_storage_type(obj)
     try:
-        realtype(typ)
-    except DMLUnknownType as e:
-        raise ETYPE(obj, e.type)
+        tp.realtype(typ)
+    except tp.DMLUnknownType as e:
+        raise E.TYPE(obj, e.type)
 
     serialize.mark_for_serialization(site, typ)
 
@@ -949,21 +945,21 @@ def mksaved(spec, parent):
 
 def mkhook(spec, parent):
     (_, site, name, arraylen_asts, type_asts) = spec
-    parent_scope = Location(parent, static_indices(parent))
+    parent_scope = c.Location(parent, static_indices(parent))
     types = []
     for type_ast in type_asts:
         (struct_defs, dtype) = eval_type(type_ast, site, parent_scope,
                                          global_scope)
-        add_late_global_struct_defs(struct_defs)
+        tp.add_late_global_struct_defs(struct_defs)
         typ = dtype.resolve()
         try:
-            safe_realtype(typ).key()
-        except DMLUnkeyableType as e:
-            report(EHOOKTYPE(typ.declaration_site or site, typ,
+            tp.safe_realtype(typ).key()
+        except tp.DMLUnkeyableType as e:
+            report(E.HOOKTYPE(typ.declaration_site or site, typ,
                              e.clarification))
         types.append(typ)
 
-    array_lens = tuple(eval_arraylen(len_ast, parent_scope)
+    array_lens = tuple(codegen.eval_arraylen(len_ast, parent_scope)
                        for len_ast in arraylen_asts)
 
     return objects.Hook(name, site, parent, types, array_lens)
@@ -979,7 +975,7 @@ def register_fields(reg):
         # before we can know that the group actually contains a field.
         # For this reason, in DML 1.2 we disallow groups in regs
         # altogether.
-        report(ENALLOW(g.site, reg))
+        report(E.NALLOW(g.site, reg))
     unexpanded = reg.get_components('field')
     for field in unexpanded:
 
@@ -987,16 +983,16 @@ def register_fields(reg):
         for fieldi in itertools.product(
                 *(list(range(sz)) for sz in field.dimsizes[reg.dimensions:])):
             indices = static_indices(reg) + tuple(
-                mkIntegerLiteral(field.site, i) for i in fieldi)
+                c.mkIntegerLiteral(field.site, i) for i in fieldi)
             lsb = param_int(field, 'lsb', indices=indices)
             msb = param_int(field, 'msb', indices=indices)
             if msb < lsb:
-                raise EBITRN(field, msb, lsb)
+                raise E.BITRN(field, msb, lsb)
             yield (field, fieldi, lsb, msb)
             # bitsize is defined in terms of lsb and msb, so we
             # don't need to evaluate it across register indices
             bitsize = param_expr(field, 'bitsize',
-                tuple(mkIntegerLiteral(field.site, i)
+                tuple(c.mkIntegerLiteral(field.site, i)
                       for i in (0,) * reg.dimensions + fieldi))
             if not bitsize.constant:
                 # guaranteed by dml-builtins.dml
@@ -1006,27 +1002,27 @@ def register_fields(reg):
         if any(sz != bitsizes[0] for sz in bitsizes[1:]):
             # bitsize is defined in dml-builtins, so the 'msb'
             # site is probably more relevant
-            report(EFARRSZ(param_expr_site(field, 'msb')))
+            report(E.FARRSZ(param_expr_site(field, 'msb')))
 
 def report_unused_templates():
-    for tpl in PWUNUSED.used_templates:
+    for tpl in P.WUNUSED.used_templates:
         if not tpl.name.startswith('@'):
-            report(PNO_WUNUSED(tpl.site, 'template', tpl.name))
-    for tpl in set(dml.globals.templates.values()) - PWUNUSED.used_templates:
+            report(P.NO_WUNUSED(tpl.site, 'template', tpl.name))
+    for tpl in set(dml.globals.templates.values()) - P.WUNUSED.used_templates:
         if not tpl.name.startswith('@'):
-            report(PWUNUSED(tpl.site, 'template', tpl.name))
+            report(P.WUNUSED(tpl.site, 'template', tpl.name))
 
 def report_unused_conds():
-    for cond in PWUNUSED.positive_conds:
-        if cond in PWUNUSED.satisfied_conds:
-            report(PNO_WUNUSED(cond.site, 'if', None))
+    for cond in P.WUNUSED.positive_conds:
+        if cond in P.WUNUSED.satisfied_conds:
+            report(P.NO_WUNUSED(cond.site, 'if', None))
         else:
-            report(PWUNUSED(cond.site, 'if', None))
-    for cond in PWUNUSED.negative_conds:
-        if cond in PWUNUSED.satisfied_conds:
-            report(PNO_WUNUSED(cond.site, 'else', None))
+            report(P.WUNUSED(cond.site, 'if', None))
+    for cond in P.WUNUSED.negative_conds:
+        if cond in P.WUNUSED.satisfied_conds:
+            report(P.NO_WUNUSED(cond.site, 'else', None))
         else:
-            report(PWUNUSED(cond.site, 'else', None))
+            report(P.WUNUSED(cond.site, 'else', None))
 
 def mkdev(devname, obj_specs):
     dev = mkobj(devname, 'device', (), obj_specs, None, {})
@@ -1052,9 +1048,9 @@ def mkobj(ident, objtype, arrayinfo, obj_specs, parent, each_stmts):
                         arraylens, index_vars)
     num_elems = functools.reduce(operator.mul, obj.dimsizes, 1)
     if num_elems >= 1 << 31:
-        raise EASZLARGE(site, num_elems)
+        raise E.ASZLARGE(site, num_elems)
 
-    with ErrorContext(obj):
+    with logging.ErrorContext(obj):
         (obj_specs, used_templates) = add_templates(obj_specs, each_stmts)
         obj.templates = used_templates
         obj_params = create_parameters(obj, obj_specs, index_vars, index_sites)
@@ -1068,7 +1064,7 @@ def create_object(site, ident, objtype, parent,
     elif objtype == 'bank':
         if (ident is None
             and breaking_changes.dml12_remove_misc_quirks.enabled):
-            report(ESYNTAX(site, 'bank', 'anonymous banks are not allowed'))
+            report(E.SYNTAX(site, 'bank', 'anonymous banks are not allowed'))
         return objects.Bank(ident, site, parent, arraylens, index_vars)
     elif objtype == 'group':
         return objects.Group(ident, site, parent, arraylens, index_vars)
@@ -1103,12 +1099,12 @@ def make_autoparams(obj, index_vars, index_sites):
     autoparams = {}
 
     if dml.globals.dml_version == (1, 2):
-        autoparams['name'] = SimpleParamExpr(
-            mkStringConstant(site, obj.ident) if obj.ident
-            else mkUndefined(site))
+        autoparams['name'] = c.SimpleParamExpr(
+            c.mkStringConstant(site, obj.ident) if obj.ident
+            else c.mkUndefined(site))
     else:
-        autoparams['_ident'] = SimpleParamExpr(
-            mkStringConstant(site, obj.ident))
+        autoparams['_ident'] = c.SimpleParamExpr(
+            c.mkStringConstant(site, obj.ident))
 
     index_params = ()
     # Handle array information
@@ -1137,34 +1133,34 @@ def make_autoparams(obj, index_vars, index_sites):
             # If in a multi-dimensional array, this will be set to undefined
             # So in 1.2 you can verify if you are in a multi-dimensional
             # array by checking if this is defined
-            autoparams['indexvar'] = SimpleParamExpr(
-                mkStringConstant(
+            autoparams['indexvar'] = c.SimpleParamExpr(
+                c.mkStringConstant(
                     # TODO or maybe 'i'?
                     index_site, '' if index_var is None else index_var))
             autoparams['index'] = index_param
         elif index_vars:
-            autoparams['indexvar'] = SimpleParamExpr(mkUndefined(site))
+            autoparams['indexvar'] = c.SimpleParamExpr(c.mkUndefined(site))
             autoparams['index'] = IndexListParamExpr(site, index_params)
         else:
-            autoparams['indexvar'] = SimpleParamExpr(mkUndefined(site))
-            autoparams['index'] = SimpleParamExpr(mkUndefined(site))
+            autoparams['indexvar'] = c.SimpleParamExpr(c.mkUndefined(site))
+            autoparams['index'] = c.SimpleParamExpr(c.mkUndefined(site))
     else:
         autoparams['indices'] = IndexListParamExpr(site, index_params)
 
     if obj.objtype == 'device':
         with crep.DeviceInstanceContext():
-            autoparams['obj'] = SimpleParamExpr(mkDeviceObject(site))
+            autoparams['obj'] = c.SimpleParamExpr(c.mkDeviceObject(site))
         if dml.globals.dml_version == (1, 2):
             autoparams['banks'] = UninitializedParamExpr(site, 'banks')
         else:
             autoparams['NULL'] = NullParamExpr(site)
-            autoparams['_be_bitorder'] = SimpleParamExpr(
-                mkBoolConstant(site, site.bitorder() == 'be'))
-        autoparams['simics_api_version'] = SimpleParamExpr(
-            mkStringConstant(site, dml.globals.api_version.str))
+            autoparams['_be_bitorder'] = c.SimpleParamExpr(
+                c.mkBoolConstant(site, site.bitorder() == 'be'))
+        autoparams['simics_api_version'] = c.SimpleParamExpr(
+            c.mkStringConstant(site, dml.globals.api_version.str))
         for change in breaking_changes.changes.values():
-            autoparams[f'_breaking_change_{change.ident()}'] = SimpleParamExpr(
-                mkBoolConstant(site, change.enabled))
+            autoparams[f'_breaking_change_{change.ident()}'] = c.SimpleParamExpr(
+                c.mkBoolConstant(site, change.enabled))
         dml.globals.device = obj
 
     elif obj.objtype == 'bank':
@@ -1183,13 +1179,13 @@ def make_autoparams(obj, index_vars, index_sites):
             # If this is an automatic field, create msb/lsb parameter from
             # the size of the register
             if obj.ident:
-                autoparams['explicit'] = SimpleParamExpr(
-                    mkBoolConstant(site, True))
+                autoparams['explicit'] = c.SimpleParamExpr(
+                    c.mkBoolConstant(site, True))
             else:
-                autoparams['name'] = SimpleParamExpr(
+                autoparams['name'] = c.SimpleParamExpr(
                     param_expr(obj.parent, 'name'))
-                autoparams['explicit'] = SimpleParamExpr(
-                    mkBoolConstant(site, False))
+                autoparams['explicit'] = c.SimpleParamExpr(
+                    c.mkBoolConstant(site, False))
 
     elif obj.objtype == 'connect':
         if dml.globals.dml_version == (1, 2):
@@ -1216,14 +1212,14 @@ def make_autoparams(obj, index_vars, index_sites):
     if obj.parent:
         autoparams['parent'] = ParentParamExpr(obj)
     else:
-        autoparams['parent'] = SimpleParamExpr(mkUndefined(obj.site))
+        autoparams['parent'] = c.SimpleParamExpr(c.mkUndefined(obj.site))
     if dml.globals.dml_version != (1, 2):
         if obj.nongroup_parent:
             autoparams['_nongroup_parent'] = NongroupParentParamExpr(obj.site,
                                                                      obj)
         else:
-            autoparams['_nongroup_parent'] = SimpleParamExpr(
-                mkUndefined(obj.site))
+            autoparams['_nongroup_parent'] = c.SimpleParamExpr(
+                c.mkUndefined(obj.site))
 
         autoparams['templates'] = TemplatesParamExpr(obj.site, obj)
 
@@ -1234,7 +1230,7 @@ def implicit_params(obj, index_vars, index_sites):
     ivar_sites = {}
     for (var, site) in zip(index_vars, index_sites):
         if var in ivar_sites and var is not None:
-            report(ENAMECOLL(ivar_sites[var], site, var))
+            report(E.NAMECOLL(ivar_sites[var], site, var))
         ivar_sites[var] = site
     params = [ast.param(site, var, ast.auto(site), False, None)
               for (var, site) in zip(index_vars, index_sites) if var is not None]
@@ -1277,21 +1273,21 @@ def create_parameters(obj, obj_specs, index_vars, index_sites):
 
 def eval_precond(cond_ast, obj, global_scope):
     try:
-        with ErrorContext(obj, cond_ast.site):
-            cond = codegen_expression(
-                cond_ast, Location(obj, static_indices(obj, cond_ast.site)),
+        with logging.ErrorContext(obj, cond_ast.site):
+            cond = codegen.codegen_expression(
+                cond_ast, c.Location(obj, static_indices(obj, cond_ast.site)),
                 global_scope)
     except DMLError as e:
         report(e)
         return False # whatever
     else:
-        cond = as_bool(cond)
+        cond = c.as_bool(cond)
         if cond.constant:
-            # guaranteed by as_bool()
-            assert isinstance(cond.ctype(), TBool)
+            # guaranteed by c.as_bool()
+            assert isinstance(cond.ctype(), tp.Bool)
             return cond.value
         else:
-            report(ENCONST(cond, cond))
+            report(E.NCONST(cond, cond))
             return False # whatever
 
 class InvalidDefault(objects.MethodDefault):
@@ -1307,9 +1303,9 @@ class DefaultMethodObj(objects.MethodDefault):
     def __init__(self, node):
         self.node = node
     def default_sym(self, indices):
-        return ExpressionSymbol(
+        return c.ExpressionSymbol(
             'default',
-            mkNodeRef(self.node.site, self.node, indices),
+            c.mkNodeRef(self.node.site, self.node, indices),
             self.node.site)
 
 class DefaultTraitMethod(objects.MethodDefault):
@@ -1332,10 +1328,10 @@ def default_sym(self, indices):
             # This is safe; ancestry paths are tuples
             ancestry_path += default_def_trait.ancestry_paths[
                 self.trait_method.vtable_trait][0]
-        return ExpressionSymbol(
+        return c.ExpressionSymbol(
             'default',
-            TraitMethodDirect(
-                site, ObjTraitRef(
+            c.TraitMethodDirect(
+                site, c.ObjTraitRef(
                     site, self.trait_node, self.trait_method.vtable_trait,
                     indices,
                     ancestry_path=ancestry_path),
@@ -1417,23 +1413,23 @@ def report_pbefaft(obj, method_asts):
 
                         method_decl = method_decl.replace('value', value_arg)
                         default_call = default_call.replace('value', value_arg)
-                    report(PBEFAFT(bef.site, dmlparse.start_site(bef_body.site),
+                    report(P.BEFAFT(bef.site, dmlparse.start_site(bef_body.site),
                                    method_decl, default_call, return_stmt,
                                    bef.site, dmlparse.start_site(bef_body.site),
                                    dmlparse.end_site(bef_body.site),
                                    *aft_args))
                 else:
-                    report(PBEFAFT(aft.site, dmlparse.start_site(aft_body.site),
+                    report(P.BEFAFT(aft.site, dmlparse.start_site(aft_body.site),
                                    method_decl, default_call, return_stmt,
                                    None, None, None,
                                    *aft_args))
                 if obj.objtype == 'register':
                     tramp_site = bef.site if bef else aft.site
                     if before_name == 'before_read':
-                        report(PTRAMPOLINE(tramp_site, None,
+                        report(P.TRAMPOLINE(tramp_site, None,
                                            'is dml12_compat_read_register;'))
                     elif before_name == 'before_write':
-                        report(PTRAMPOLINE(tramp_site, None,
+                        report(P.TRAMPOLINE(tramp_site, None,
                                            'is dml12_compat_write_register;'))
 
 
@@ -1441,7 +1437,7 @@ def wrap_method_body_in_try(site, overridden_site, obj, name, body,
                             rbrace_site):
     if (obj.objtype != 'implement'
         and not site.filename().endswith('dml-builtins.dml')):
-        report(WTHROWS_DML12(site, overridden_site))
+        report(W.THROWS_DML12(site, overridden_site))
     return ast.compound(site, [
         ast.try_(site, body, ast.log(
             site, 'error', ast.int(site, 1), None, ast.int(site, 0),
@@ -1527,7 +1523,7 @@ def process_method_declarations(obj, name, declarations,
         for other in others:
             if not other.abstract:
                 # two conflicting method definitions in the same block
-                raise ENAMECOLL(other.site, impl.site, other.name)
+                raise E.NAMECOLL(other.site, impl.site, other.name)
 
         if (not impl.shared # Handled separately
             and impl.site.provisional_enabled(
@@ -1536,16 +1532,16 @@ def process_method_declarations(obj, name, declarations,
                                   for m in rank_to_methods[anc]]
             if impl.explicit_decl:
                 if existing:
-                    report(EOVERRIDEMETH(impl.site, existing[0].site,
+                    report(E.OVERRIDEMETH(impl.site, existing[0].site,
                                          impl.name,
                                          'default ' * impl.overridable))
             elif not existing:
-                report(ENOVERRIDEMETH(impl.site, impl.name,
+                report(E.NOVERRIDEMETH(impl.site, impl.name,
                                       'default ' * impl.overridable))
 
     (default_map, method_order) = traits.sort_method_implementations(impls)
 
-    location = Location(obj, static_indices(obj))
+    location = c.Location(obj, static_indices(obj))
 
     nonshared_impls = []
 
@@ -1553,7 +1549,7 @@ def process_method_declarations(obj, name, declarations,
         if impl.shared:
             if default_map[impl]:
                 # shared method overrides a non-shared method
-                report(ETMETH(
+                report(E.TMETH(
                     default_map[impl][0].site, impl.site, name))
         else:
             nonshared_impls.append(impl)
@@ -1587,7 +1583,7 @@ def process_method_declarations(obj, name, declarations,
         else:
             # This only done in this path because we favor reporting
             # EABSTEMPLATE (done by the caller) over EABSMETH
-            report(EABSMETH(abstract_decls[0].site, name))
+            report(E.ABSMETH(abstract_decls[0].site, name))
 
     if not nonshared_impls:
         return None
@@ -1626,7 +1622,7 @@ def process_method_declarations(obj, name, declarations,
             throws = False
         for overridden in default_map[impl]:
             if not overridden.overridable:
-                raise EDMETH(impl.site, overridden.site, name)
+                raise E.DMETH(impl.site, overridden.site, name)
             # the override of trait ASTs is checked later, by
             # traits.typecheck_method_override
             if not overridden.shared:
@@ -1660,7 +1656,7 @@ def process_method_declarations(obj, name, declarations,
                     # 1.2 and 1.4,
                     pass
                 else:
-                    raise EMETH(impl.site, overridden.site,
+                    raise E.METH(impl.site, overridden.site,
                                 "different 'throws' annotations")
 
         template = (impl.obj_spec.parent_template
@@ -1684,18 +1680,18 @@ def process_method_declarations(obj, name, declarations,
             (_, msite, _, _, _, exported, _, _) = method_ast
             if exported:
                 if not method.fully_typed:
-                    raise EEXTERN(method.site)
-                func = method_instance(method)
-                mark_method_referenced(func)
-                mark_method_exported(func, crep.cref_method(method), msite)
+                    raise E.EXTERN(method.site)
+                func = codegen.method_instance(method)
+                codegen.mark_method_referenced(func)
+                codegen.mark_method_exported(func, crep.cref_method(method), msite)
                 break
         # Export hard_reset and soft_reset from device objects in 1.2
         # automatically
         if (obj.objtype == 'device' and
             name in {'hard_reset', 'soft_reset'}):
-            func = method_instance(method)
-            mark_method_referenced(func)
-            mark_method_exported(func, crep.cref_method(method), obj.site)
+            func = codegen.method_instance(method)
+            codegen.mark_method_referenced(func)
+            codegen.mark_method_exported(func, crep.cref_method(method), obj.site)
 
     return method
 
@@ -1711,9 +1707,9 @@ def mkobj2(obj, obj_specs, params, each_stmts):
     # to site. For name collision detection.
     symbols = {param.name: param.site for param in params}
     if dml.globals.dml_version == (1, 4):
-        objname = param_str_fixup(obj, 'name', obj.ident)
+        objname = c.param_str_fixup(obj, 'name', obj.ident)
         if not ident_re.match(objname):
-            report(ENAMEID(param_expr_site(obj, 'name'), objname))
+            report(E.NAMEID(param_expr_site(obj, 'name'), objname))
             objname = obj.ident
         obj.name = objname
     else:
@@ -1722,15 +1718,15 @@ def mkobj2(obj, obj_specs, params, each_stmts):
         pnode = obj.get_component('_build_confidentiality')
         if pnode and pnode.objtype == 'parameter':
             val = pnode.get_expr(())
-            if isinstance(val, IntegerConstant) and val.value > 0:
+            if isinstance(val, c.IntegerConstant) and val.value > 0:
                 dml.globals.build_confidentiality = val.value
 
     if obj.objtype == 'register':
         if not param_defined(obj, 'size'):
-            raise EREGNSZ(obj)
+            raise E.REGNSZ(obj)
 
         if param_int(obj, 'size') > 8:
-            raise EREGISZ(obj)
+            raise E.REGISZ(obj)
 
     obj_traits = []
     for obj_spec in obj_specs:
@@ -1745,7 +1741,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
             if all(eval_precond(cond, obj, global_scope)
                    for cond in preconds):
                 if logging.show_porting:
-                    PWUNUSED.satisfied_conds.update(preconds)
+                    P.WUNUSED.satisfied_conds.update(preconds)
                 shallow_subobjs.append((shallow, obj_spec))
                 composite_subobjs.append((composite, obj_spec))
                 for (templates, spec) in in_eachs:
@@ -1766,12 +1762,12 @@ def mkobj2(obj, obj_specs, params, each_stmts):
         for s in stmts:
             if s.kind == 'error':
                 _, esite, msg = s
-                raise EERRSTMT(esite, msg or "explicit error")
+                raise E.ERRSTMT(esite, msg or "explicit error")
             elif s.kind == 'method':
                 (name, _, _, _, _, _) = s.args
                 if name not in method_asts:
                     if name in symbols:
-                        report(ENAMECOLL(s.site, symbols[name], name))
+                        report(E.NAMECOLL(s.site, symbols[name], name))
                     else:
                         symbols[name] = s.site
                         method_asts[name] = [(obj_spec, s)]
@@ -1780,7 +1776,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
             elif s.kind == 'session':
                 (decls, inits) = s.args
                 if inits is not None and len(decls) != len(inits):
-                    report(ESYNTAX(s.site, None,
+                    report(E.SYNTAX(s.site, None,
                                    'wrong number of initializers:\n'
                                    + f'{len(decls)} variables declared\n'
                                    + f'{len(inits)} initializers specified'))
@@ -1790,7 +1786,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
                     for (decl_ast, init_ast) in zip(decls, inits):
                         (name, typ_ast) = decl_ast.args
                         if name in symbols:
-                            report(ENAMECOLL(s.site, symbols[name], name))
+                            report(E.NAMECOLL(s.site, symbols[name], name))
                         else:
                             symbols[name] = s.site
                             sessions[name] = (s.site, name, typ_ast, init_ast)
@@ -1798,7 +1794,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
             elif s.kind == 'saved':
                 (decls, inits) = s.args
                 if inits is not None and len(decls) != len(inits):
-                    report(ESYNTAX(s.site, None,
+                    report(E.SYNTAX(s.site, None,
                                    'wrong number of initializers:\n'
                                    + f'{len(decls)} variables declared\n'
                                    + f'{len(inits)} initializers specified'))
@@ -1808,7 +1804,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
                     for (decl_ast, init_ast) in zip(decls, inits):
                         (name, typ_ast) = decl_ast.args
                         if name in symbols:
-                            report(ENAMECOLL(s.site, symbols[name], name))
+                            report(E.NAMECOLL(s.site, symbols[name], name))
                         else:
                             symbols[name] = s.site
                             saved[name] = (s.site, name, typ_ast, init_ast)
@@ -1834,7 +1830,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
     for (ident, defs) in subobj_spec_by_ident.items():
         if ident in symbols:
             for (_, _, _, subobj_spec) in defs:
-                report(ENAMECOLL(subobj_spec.site, symbols[ident], ident))
+                report(E.NAMECOLL(subobj_spec.site, symbols[ident], ident))
         else:
             subobj_defs[ident] = merge_subobj_defs(ident, defs, obj)
 
@@ -1871,7 +1867,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
     trait_method_impls = traits.merge_method_impl_maps(
         obj.site, explicit_traits)
 
-    obj_scope = Location(obj, static_indices(obj))
+    obj_scope = c.Location(obj, static_indices(obj))
     # Create all method nodes
     for name in sorted(method_asts):
         if dml.globals.dml_version == (1, 2):
@@ -1897,7 +1893,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
             }.get(obj.objtype, set())):
             if dml.globals.traits[name] not in ancestors:
                 (_, mast) = declarations[0]
-                report(WNOIS(mast.site, name))
+                report(W.NOIS(mast.site, name))
 
         trait_impls = trait_method_impls.get(name, [])
         trait_abstract_decls = Set()
@@ -1980,7 +1976,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
             or (dml.globals.dml_version == (1, 2)
                 and obj.objtype != 'device'
                 and objtype == 'bank')):
-            report(ENALLOW(subobj_specs[0].site, obj))
+            report(E.NALLOW(subobj_specs[0].site, obj))
             continue
         try:
             subobj = mkobj(ident, objtype, arrayinfo, subobj_specs, obj,
@@ -1990,7 +1986,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
         else:
             if subobj.name:
                 if subobj.name in subobj_name_defs:
-                    report(ENAMECOLL(subobj.name_site,
+                    report(E.NAMECOLL(subobj.name_site,
                                      subobj_name_defs[subobj.name],
                                      subobj.name))
                     continue
@@ -1998,7 +1994,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
                 # named "dev", as the device object's serialized identity
                 # logname is "dev", and must be unique
                 elif subobj.name == 'dev' and obj.objtype == 'device':
-                    report(ENAMECOLL(subobj.name_site, obj.site, 'dev'))
+                    report(E.NAMECOLL(subobj.name_site, obj.site, 'dev'))
                     continue
                 subobj_name_defs[subobj.name] = (
                     subobj.name_site if
@@ -2009,7 +2005,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
     for o in subobjs:
         obj.add_component(o)
 
-    # Map name to MethodFunc.
+    # Map name to codegen.MethodFunc.
     trait_method_overrides = {}
     # Map name to objects.Parameter.
     trait_param_nodes = {}
@@ -2040,18 +2036,18 @@ def mkobj2(obj, obj_specs, params, each_stmts):
                     assert member_kind in {'method', 'parameter'}
                     for (tsite, t) in obj_traits:
                         if t.implements(decl_trait):
-                            raise EABSTEMPLATE(
+                            raise E.ABSTEMPLATE(
                                 tsite, decl_site, decl_trait.name,
                                 member_kind, member)
                     raise ICE(decl_trait.site,
-                              'no site found for EABSTEMPLATE(%s)' % (member,))
+                              'no site found for E.ABSTEMPLATE(%s)' % (member,))
                 elif len(impl_traits) > 1:
                     # report error: override required to resolve ambiguity
                     assert member_kind == 'method'
                     sm0 = impl_traits[0].method_impls[member]
                     sm1 = impl_traits[1].method_impls[member]
 
-                    raise EAMBINH(sm0.site,
+                    raise E.AMBINH(sm0.site,
                                   sm1.site,
                                   sm0.name,
                                   RankDesc('template', sm0.trait.name),
@@ -2063,7 +2059,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
 
             if override.objtype != decl_trait.member_kind(member):
                 # e.g. an attempt to override a parameter with a method
-                report(ENAMECOLL(override.site, decl_site, member))
+                report(E.NAMECOLL(override.site, decl_site, member))
                 continue
 
             vtable_trait = trait.vtable_trait(member)
@@ -2073,14 +2069,14 @@ def mkobj2(obj, obj_specs, params, each_stmts):
                 if not override.fully_typed:
                     for p in override.inp:
                         if p.inlined:
-                            raise EMETH(
+                            raise E.METH(
                                 override.site, tsite,
                                 'input argument declared without a type')
                     if dml.globals.dml_version == (1, 2):
                         # untyped outputs only exist in 1.2
                         for (n, t) in override.outp:
                             if not t:
-                                raise EMETH(
+                                raise E.METH(
                                     override.site, tsite,
                                     'output argument declared without a type')
                     raise ICE(override.site, 'no untyped args')
@@ -2111,12 +2107,12 @@ def mkobj2(obj, obj_specs, params, each_stmts):
                 obj.site, [(b, (), b.dimsizes) for b in banks]))
 
             for b in banks:
-                for indices in all_index_exprs(b):
+                for indices in c.all_index_exprs(b):
                     funexpr = param_expr(b, 'function', indices)
                     if defined(funexpr):
-                        funnum = expr_intval(funexpr)
+                        funnum = expr_util.expr_intval(funexpr)
                         if funnum in used:
-                            report(EDBFUNC(param_expr(b, 'function'),
+                            report(E.DBFUNC(param_expr(b, 'function'),
                                            param_expr(used[funnum], 'function'),
                                            funnum))
                         else:
@@ -2135,31 +2131,31 @@ def mkobj2(obj, obj_specs, params, each_stmts):
                         and global_scope.lookup(p.name) is None):
                         try:
                             global_scope.add(
-                                ExpressionSymbol(p.name, p.get_expr(()), p.site))
+                                c.ExpressionSymbol(p.name, p.get_expr(()), p.site))
                         except DMLError:
                             # handled later
                             pass
 
         # Evaluate all parameters once, to early smoke out non-existing
         # identifiers. TODO: perhaps this should not be done?
-        zero_index = (mkIntegerLiteral(obj.site, 0),)
+        zero_index = (c.mkIntegerLiteral(obj.site, 0),)
         for param in obj.get_recursive_components('parameter'):
             with ExitStack() as stack:
-                stack.enter_context(ErrorContext(param, None))
+                stack.enter_context(logging.ErrorContext(param, None))
                 stack.enter_context(crep.DeviceInstanceContext())
                 try:
                     try:
                         # Evaluate statically, because it triggers caching
                         # in ASTParamExpr
                         param.get_expr(static_indices(param.parent))
-                    except EIDXVAR as e:
+                    except E.IDXVAR as e:
                         # Dependency on index variable, re-evaluate at one
                         # index to capture errors early
                         param.get_expr(zero_index * param.dimensions)
                 except DMLError as e:
                     if (dml.globals.dml_version == (1, 2)
                         and dml.globals.api_version <= breaking_changes.api_5
-                        and isinstance(e, EREF)):
+                        and isinstance(e, E.REF)):
                         # We forgive some errors in unused parameters, to
                         # avoid the annoyance caused by hard errors from code
                         # that used to compile fine.
@@ -2173,7 +2169,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
                         #
                         # In future versions, we should not forgive
                         # broken dead parameters. This is SIMICS-9886.
-                        WREF.instances.append(WREF(
+                        W.REF.instances.append(W.REF(
                             param.site, param.logname(), e))
                     else:
                         report(e)
@@ -2184,52 +2180,52 @@ def mkobj2(obj, obj_specs, params, each_stmts):
             for p in obj.get_components():
                 sym = global_scope.lookup(p.name)
                 if sym and (
-                        # hacky workaround for the ExpressionSymbol
+                        # hacky workaround for the c.ExpressionSymbol
                         # implicitly added above. Needed when importing 1.4
                         # code from 1.2 with --breaking-change=dml12_remove_misc_quirks
                         dml.globals.dml_version != (1, 2)
                         or p.site.dml_version() == (1, 2)
                         or p.site != sym.site):
-                    report(ENAMECOLL(p.site, sym.site, p.name))
+                    report(E.NAMECOLL(p.site, sym.site, p.name))
 
         # At this point, methods and subobjs are created and we can
         # try to evaluate their exporting
         for export in exports:
             method_ref_ast, name_ast = (export.args)
-            method_ref = codegen_expression_maybe_nonvalue(
+            method_ref = codegen.codegen_expression_maybe_nonvalue(
                 method_ref_ast, obj_scope, global_scope)
-            name_expr = codegen_expression(name_ast, obj_scope, global_scope)
+            name_expr = codegen.codegen_expression(name_ast, obj_scope, global_scope)
             # By continuing we can discover more error, since exports
             # have no effect if invalid
-            if not isinstance(method_ref, NodeRef):
-                report(ENOBJ(method_ref_ast.site, method_ref))
+            if not isinstance(method_ref, c.NodeRef):
+                report(E.NOBJ(method_ref_ast.site, method_ref))
                 continue
             method, indices = method_ref.get_ref()
             if not isinstance(method, objects.Method):
-                report(ENMETH(method_ref_ast.site, method))
+                report(E.NMETH(method_ref_ast.site, method))
                 continue
             if indices:
-                report(EEXPORT(method.site, method))
+                report(E.EXPORT(method.site, method))
                 continue
             if not method.fully_typed:
-                report(EEXPORT(method.site, export.site))
+                report(E.EXPORT(method.site, export.site))
                 continue
-            name = expr_strval(name_expr)
+            name = expr_util.expr_strval(name_expr)
             if not re.match(r"[A-Za-z_][\w_]*", name):
-                report(ENAMEID(name_ast.site, name))
+                report(E.NAMEID(name_ast.site, name))
                 continue
             if method.throws or len(method.outp) > 1:
-                report(EEXPORT(method.site, export.site))
+                report(E.EXPORT(method.site, export.site))
                 continue
-            func = method_instance(method)
-            mark_method_referenced(func)
-            mark_method_exported(func, name, export.site)
+            func = codegen.method_instance(method)
+            codegen.mark_method_referenced(func)
+            codegen.mark_method_exported(func, name, export.site)
 
     elif obj.objtype == 'bank':
         set_confidential_object(obj)
         if logging.show_porting:
             if param_defined(obj, 'function'):
-                report(PABSTRACT_TEMPLATE(symbols['function'],
+                report(P.ABSTRACT_TEMPLATE(symbols['function'],
                                           'function_mapped_bank'))
 
     elif obj.objtype == 'register':
@@ -2243,13 +2239,13 @@ def field_msb(field):
                 register_fields(obj),
                 key = field_msb)
             if obj.wholefield:
-                if not param_bool_fixup(obj, 'allocate', True):
+                if not c.param_bool_fixup(obj, 'allocate', True):
                     if method_is_std(obj, 'set'):
                         obj.writable = False
                     if method_is_std(obj, 'get'):
                         obj.readable = False
             else:
-                if not any(param_bool_fixup(f, 'allocate', True)
+                if not any(c.param_bool_fixup(f, 'allocate', True)
                            for (f, _, _, _) in fields):
                     if all(method_is_std(f, 'set') for (f, _, _, _) in fields):
                         obj.writable = False
@@ -2262,18 +2258,18 @@ def field_msb(field):
                 # Check that the fields don't overlap
                 (lsf, _, lsb, _) = fields[0]
                 if lsb < 0:
-                    raise EBITRR(lsf)
+                    raise E.BITRR(lsf)
                 for ((lsf, li, lsb, _), (msf, mi, _, msb)) in zip(fields[1:],
                                                                   fields[:-1]):
                     if lsb <= msb:
                         reg_indices = (0,) * (lsf.dimensions - len(li))
-                        report(EBITRO(lsf, tuple(mkIntegerLiteral(None, i)
+                        report(E.BITRO(lsf, tuple(c.mkIntegerLiteral(None, i)
                                                  for i in reg_indices + li),
-                                      msf, tuple(mkIntegerLiteral(None, i)
+                                      msf, tuple(c.mkIntegerLiteral(None, i)
                                                  for i in reg_indices + mi)))
                 (msf, _, _, msb) = fields[-1]
                 if msb >= param_int(obj, 'bitsize'):
-                    raise EBITRR(msf)
+                    raise E.BITRR(msf)
 
             # Set the 'fields' parameter
             obj.fields = [field for (field, _, _, _) in fields]
@@ -2281,7 +2277,7 @@ def field_msb(field):
                 obj.site,
                 # Always expand all indices: the list order is
                 # significant, and two field arrays may be interleaved
-                [(f, tuple(mkIntegerLiteral(f.site, i) for i in indices), ())
+                [(f, tuple(c.mkIntegerLiteral(f.site, i) for i in indices), ())
                  for (f, indices, _, _) in fields]))
         else: # DML version >= 1.4
             if not param_bool(obj, 'writable'):
@@ -2292,9 +2288,9 @@ def field_msb(field):
         if not obj.writable or not obj.readable:
             confparam = param_str(obj, 'configuration')
             if not obj.writable and not obj.readable and confparam != "none":
-                raise EANULL(obj.site)
+                raise E.ANULL(obj.site)
             if confparam in {'required', 'optional'}:
-                raise EACHK(obj.site)
+                raise E.ACHK(obj.site)
 
     elif obj.objtype == 'field':
         if dml.globals.dml_version == (1, 2) and obj.ident == None:
@@ -2305,7 +2301,7 @@ def field_msb(field):
         if not param_defined(obj,
                              'attr_type' if dml.globals.dml_version == (1, 2)
                              else '_attr_type'):
-            raise EATYPE(obj)
+            raise E.ATYPE(obj)
 
         if ((dml.globals.dml_version == (1, 2)
              and method_is_std(obj, 'set_attribute')
@@ -2325,15 +2321,15 @@ def field_msb(field):
         if not obj.writable or not obj.readable:
             confparam = param_str(obj, 'configuration')
             if not obj.writable and not obj.readable and confparam != "none":
-                raise EANULL(obj.site)
+                raise E.ANULL(obj.site)
             if confparam in {'required', 'optional'}:
-                raise EACHK(obj.site)
+                raise E.ACHK(obj.site)
 
         if logging.show_porting and dml.globals.dml_version == (1, 2):
             param = obj.get_component('allocate_type')
             atype_expr = param.get_expr(static_indices(obj))
             if defined(atype_expr):
-                atype = expr_strval(atype_expr)
+                atype = expr_util.expr_strval(atype_expr)
                 type_param = obj.get_component('type')
                 # if 'parameter type = "i"' appears together with allocate_type,
                 # then remove that as well
@@ -2350,15 +2346,15 @@ def field_msb(field):
                     # be enum saved as string. Trust that the getter/setter
                     # works in this case, but remove the allocate_type
                     # (SIMICS-23126).
-                    report(PATTRIBUTE(obj.site, None, param.site, None))
+                    report(P.ATTRIBUTE(obj.site, None, param.site, None))
                 elif atype.startswith('uint'):
-                    report(PATTRIBUTE(obj.site, 'uint64_attr', param.site,
+                    report(P.ATTRIBUTE(obj.site, 'uint64_attr', param.site,
                                       type_site))
                 elif atype.startswith('int'):
-                    report(PATTRIBUTE(obj.site, 'int64_attr', param.site,
+                    report(P.ATTRIBUTE(obj.site, 'int64_attr', param.site,
                                       type_site))
                 elif atype in {'double', 'bool'}:
-                    report(PATTRIBUTE(obj.site, atype + '_attr', param.site,
+                    report(P.ATTRIBUTE(obj.site, atype + '_attr', param.site,
                                       type_site))
 
     elif obj.objtype == 'connect':
@@ -2371,17 +2367,17 @@ def field_msb(field):
     elif obj.objtype == 'interface':
         typename = param_str(obj, 'c_type' if dml.globals.dml_version == (1, 2)
                              else '_c_type')
-        t = TPtr(TNamed(typename, const=True))
+        t = tp.Ptr(tp.Named(typename, const=True))
         t.declaration_site = obj.site
         try:
-            realtype(t)
-        except DMLUnknownType:
-            raise EIFTYPE(obj, t)
+            tp.realtype(t)
+        except tp.DMLUnknownType:
+            raise E.IFTYPE(obj, t)
 
     elif obj.objtype == 'event':
         if (dml.globals.dml_version == (1, 2)
             and param_str(obj, 'timebase') == 'stacked'):
-            report(WDEPRECATED(obj.get_component('timebase').site,
+            report(W.DEPRECATED(obj.get_component('timebase').site,
                                "stacked events are deprecated"))
         if logging.show_porting and dml.globals.dml_version == (1, 2):
             timebase = param_str(obj, 'timebase')
@@ -2392,39 +2388,39 @@ def field_msb(field):
                       else '_cycle_event')
             if method_is_std(obj, 'get_event_info'):
                 prefix = 'simple'
-                report(PCHANGE_INARGS(obj.get_component('event').site,
+                report(P.CHANGE_INARGS(obj.get_component('event').site,
                                       'method event()'))
             else:
                 prefix = 'custom'
-            report(PEVENT(obj.site, f'{prefix}{suffix}', param_site, None))
+            report(P.EVENT(obj.site, f'{prefix}{suffix}', param_site, None))
 
     return obj
 
 def set_confidential_object(obj):
     expr = param_expr(obj, '_confidentiality')
-    val = expr_intval(expr) if defined(expr) else 0
+    val = expr_util.expr_intval(expr) if defined(expr) else 0
     if (val - dml.globals.build_confidentiality) > 0:
         obj._confidential = True
         if obj.objtype in {'register', 'field'} and obj.name:
-            setparam(obj, 'name', SimpleParamExpr(mkHiddenName(
+            setparam(obj, 'name', c.SimpleParamExpr(c.mkHiddenName(
                 obj.site, obj.name, obj)))
             setparam(obj, 'qname', HiddenQNameParamExpr(obj))
 
 def get_register_registers(reg, indexvars):
     # Get a flat list of all individual registers in a potential
-    # register array. Return it as list of NodeRef objects
+    # register array. Return it as list of c.NodeRef objects
     # Obtain all combinations of indices into a potentially
     # multi-dimensional array
     index_crossproduct = itertools.product(*(
-        (mkIntegerLiteral(reg.site, i) for i in range(array_len))
+        (c.mkIntegerLiteral(reg.site, i) for i in range(array_len))
         for array_len in reg.arraylens()))
-    return [mkNodeRef(reg.site, reg,
+    return [c.mkNodeRef(reg.site, reg,
                       indexvars +
                       indices) for indices in index_crossproduct]
 
 def get_group_registers(group, indexvars):
     # Get a flat list of all individual registers in a bank/group.
-    # Return it as list of NodeRef objects
+    # Return it as list of c.NodeRef objects
     subnodes = group.get_components('group', 'register')
 
     regs = []
@@ -2433,7 +2429,7 @@ def get_group_registers(group, indexvars):
         # Obtain all combinations of indices into a potentially
         # multi-dimensional array
         index_crossproduct = itertools.product(*(
-            (mkIntegerLiteral(None, i) for i in range(array_len))
+            (c.mkIntegerLiteral(None, i) for i in range(array_len))
             for array_len in group.arraylens()))
         for indices in index_crossproduct:
             subindexvars = indexvars + indices
@@ -2462,7 +2458,7 @@ def param_linear_int(param):
     uint64 or int64.
     '''
     class IndexVar(Expression):
-        type = TInt(64, True)
+        type = tp.Int(64, True)
         @slotsmeta.auto_init
         def __init__(self, site, variables): pass
 
@@ -2504,7 +2500,7 @@ def expr_linear_int(expr):
     except DMLError:
         return None
     try:
-        return tuple(c & ((1 << 64) - 1) for c in expr_linear_int(expr))
+        return tuple(coeff & ((1 << 64) - 1) for coeff in expr_linear_int(expr))
     except NotLinear:
         return None
 
@@ -2553,7 +2549,7 @@ def explode_offsets(reg):
                                    indices=bank_indices + reg_indices), coord)
                         for (reg_indices, coord) in zip(
                                 itertools.product(
-                                    *([mkIntegerLiteral(reg.site, i)
+                                    *([c.mkIntegerLiteral(reg.site, i)
                                        for i in range(dimsize)]
                                       for dimsize in reg.dimsizes[
                                               bank.dimensions:])),
@@ -2583,7 +2579,7 @@ def explode_offsets(reg):
             del all_offsets[-1]
         for (a, b) in zip(all_offsets, all_offsets[1:]):
             if a[1] > b[0]:
-                report(EREGOL(a[2], b[2], a[3], b[3]))
+                report(E.REGOL(a[2], b[2], a[3], b[3]))
 
 def check_register_fields(reg):
     assert dml.globals.dml_version != (1, 2)
@@ -2593,7 +2589,7 @@ def explode_ranges(field):
         assert param.objtype == 'parameter'
         ranges = []
         for field_indices in itertools.product(
-                *([mkIntegerLiteral(field.site, i) for i in range(dimsize)]
+                *([c.mkIntegerLiteral(field.site, i) for i in range(dimsize)]
                   for dimsize in field.dimsizes[reg.dimensions:])):
             reg_indices = tuple(StaticIndex(field.site, var)
                                 for var in reg.idxvars())
@@ -2601,7 +2597,7 @@ def explode_ranges(field):
             try:
                 lsb_expr = param_expr(field, 'lsb', indices)
                 msb_expr = param_expr(field, 'msb', indices)
-            except EIDXVAR:
+            except E.IDXVAR:
                 # msb/lsb expression dependent on bank/register indices.
                 # Disregard this field when checking ranges.
                 return []
@@ -2609,15 +2605,15 @@ def explode_ranges(field):
                 if isinstance(expr, NonValue):
                     raise expr.exc()
                 if expr.constant and not isinstance(expr.value, int):
-                    raise EBTYPE(expr.site, expr.ctype(), "integer")
+                    raise E.BTYPE(expr.site, expr.ctype(), "integer")
 
             if lsb_expr.constant and msb_expr.constant:
                 lsb = lsb_expr.value
                 msb = msb_expr.value
                 if lsb < 0 or bitsize <= msb:
-                    raise EBITRR(field)
+                    raise E.BITRR(field)
                 if msb < lsb:
-                    raise EBITRN(field, msb, lsb)
+                    raise E.BITRN(field, msb, lsb)
                 ranges.append((lsb, msb, indices))
         return ranges
 
@@ -2629,7 +2625,7 @@ def explode_ranges(field):
     all_ranges.sort(key=lambda t: t[0])
     for (a, b) in zip(all_ranges, all_ranges[1:]):
         if a[1] >= b[0]:
-            report(EBITRO(a[2], a[3], b[2],  b[3]))
+            report(E.BITRO(a[2], a[3], b[2],  b[3]))
 
 class ParentParamExpr(objects.ParamExpr):
     def __init__(self, obj):
@@ -2640,7 +2636,7 @@ def mkexpr(self, indices):
         assert len(indices) == self.obj.dimensions
         if self.obj.isindexed():
             indices = indices[:-self.obj.local_dimensions()]
-        return mkNodeRef(self.obj.site, self.obj.parent, indices)
+        return c.mkNodeRef(self.obj.site, self.obj.parent, indices)
 
 class QNameParamExpr(objects.ParamExpr):
     def __init__(self, node, relative):
@@ -2650,7 +2646,7 @@ def __init__(self, node, relative):
     @property
     def site(self): return self.node.site
     def mkexpr(self, indices):
-        return QName(self.node.site, self.node, self.relative, indices)
+        return c.QName(self.node.site, self.node, self.relative, indices)
 
 class HiddenQNameParamExpr(objects.ParamExpr):
     def __init__(self, node):
@@ -2658,16 +2654,16 @@ def __init__(self, node):
     @property
     def site(self): return self.node.site
     def mkexpr(self, indices):
-        return HiddenQName(self.node.site, self.node, indices)
+        return c.HiddenQName(self.node.site, self.node, indices)
 
 class ObjectListParamExpr(objects.ParamExpr):
-    '''List of DML objects, using a common parent'''
+    '''c.List of DML objects, using a common parent'''
     __slots__ = ('site', 'instances')
     def __init__(self, site, instances):
         self.site = site
         self.instances = instances
     def mkexpr(self, indices):
-        return mkObjectList(
+        return c.mkObjectList(
             self.site,
             [(node, indices + parent_relative_indices, dimsizes)
              for (node, parent_relative_indices, dimsizes) in self.instances])
@@ -2685,7 +2681,7 @@ def site(self): return self.node.site
     def mkexpr(self, indices):
         if self.cached is not None:
             return self.cached
-        self.cached = mkStringConstant(
+        self.cached = c.mkStringConstant(
             self.node.site,
             self.node.logname_anonymized(relative=self.relative))
         return self.cached
@@ -2704,12 +2700,12 @@ def mkexpr(self, indices):
         if self.cached:
             return self.cached
         if self in self.params_on_stack:
-            raise ERECPARAM([pe.ast.site for pe in self.params_on_stack[
+            raise E.RECPARAM([pe.ast.site for pe in self.params_on_stack[
                 self.params_on_stack.index(self):]])
         self.params_on_stack.append(self)
         try:
-            expr = codegen_expression_maybe_nonvalue(
-                self.ast, Location(self.parent, indices), global_scope)
+            expr = codegen.codegen_expression_maybe_nonvalue(
+                self.ast, c.Location(self.parent, indices), global_scope)
         finally:
             popped = self.params_on_stack.pop()
             assert popped is self
@@ -2724,11 +2720,11 @@ def __init__(self, site, name):
         self.site = site
         self.name = name
     def mkexpr(self, indices):
-        raise EUNINITIALIZED(self.site, self.name)
+        raise E.UNINITIALIZED(self.site, self.name)
 
 class EventClassExpr(ctree.LValue):
     slots = ('node', 'indices')
-    type = TPtr(TNamed('event_class_t'), const=True)
+    type = tp.Ptr(tp.Named('event_class_t'), const=True)
     @auto_init
     def __init__(self, site, node, indices): pass
     def __str__(self):
@@ -2777,7 +2773,7 @@ def __init__(self, site, params):
         self.params = params
         self.site = site
     def mkexpr(self, indices):
-        return mkList(self.site,
+        return c.mkList(self.site,
                       [param.mkexpr(indices) for param in self.params])
 
 class NullParamExpr(objects.ParamExpr):
@@ -2800,7 +2796,7 @@ def __init__(self, site, node):
         self.node = node
 
     def mkexpr(self, indices):
-        return mkNodeRef(self.site, self.node.nongroup_parent,
+        return c.mkNodeRef(self.site, self.node.nongroup_parent,
                          indices[:self.node.nongroup_parent.dimensions])
 
 
@@ -2813,7 +2809,7 @@ def __init__(self, site, node):
         self.node = node
 
     def mkexpr(self, indices):
-        return mkTemplatesRef(self.site, self.node, indices)
+        return c.mkTemplatesRef(self.site, self.node, indices)
 
 def port_class_ident(port):
     '''The C identifier used for a port class within the device class
@@ -2864,7 +2860,7 @@ def mkexpr(self, indices):
             prefix = parent.name + "_" + prefix
             parent = parent.parent
 
-        self.cached = mkStringConstant(self.site,
+        self.cached = c.mkStringConstant(self.site,
                                        get_attr_name(prefix, self.node))
         return self.cached
 
@@ -2888,7 +2884,7 @@ def mkexpr(self, indices):
             lit = f'&{port_class_ident(object_parent)}'
         else:
             lit = 'NULL'
-        self.cached = mkLit(self.site, lit, TPtr(TPtr(TNamed('conf_class_t'))))
+        self.cached = mkLit(self.site, lit, tp.Ptr(tp.Ptr(tp.Named('conf_class_t'))))
         return self.cached
 
 def need_port_proxy_attrs(port):
@@ -2925,12 +2921,12 @@ def mkexpr(self, indices):
                 '(_dml_attr_parent_obj_proxy_info_t) { .valid = true,'
                 + f'.is_bank = {is_bank}, .is_array = {is_array}, '
                 + f'.portname = "{object_parent.name}" }}',
-                TNamed('_dml_attr_parent_obj_proxy_info_t'))
+                tp.Named('_dml_attr_parent_obj_proxy_info_t'))
         else:
             self.cached = mkLit(
                 self.site,
                 '(_dml_attr_parent_obj_proxy_info_t) { .valid = false }',
-                TNamed('_dml_attr_parent_obj_proxy_info_t'))
+                tp.Named('_dml_attr_parent_obj_proxy_info_t'))
         return self.cached
 
 class InterfacesDocParamExpr(objects.ParamExpr):
@@ -2959,9 +2955,9 @@ def mkexpr(self, indices):
                     text += (f'\n\n{req} interface{s}: '
                              + ', '.join(f'{iface}'
                                          for iface in sorted(ifaces)))
-            self.cached = mkStringConstant(self.site, text)
+            self.cached = c.mkStringConstant(self.site, text)
         else:
-            self.cached = mkUndefined(self.site)
+            self.cached = c.mkUndefined(self.site)
         return self.cached
 
 def mkparam(obj, autoparams, param):
@@ -2978,7 +2974,7 @@ def mkparam(obj, autoparams, param):
             name, site, obj, autoparams[name])
     elif auto:
         # user-supplied 'auto' declaration
-        raise EAUTOPARAM(site, name)
+        raise E.AUTOPARAM(site, name)
 
     # caught earlier, ENPARAM
     assert value is not None
@@ -2994,7 +2990,7 @@ def port_builtin_method_overrides(name, site, inp_ast, parent_obj):
             and parent_obj.objtype in {'bank', 'device'})):
         tpl_name = {'read_access': 'read_field',
                     'write_access': 'write_field'}.get(name, name)
-        report(PABSTRACT_TEMPLATE(site, tpl_name))
+        report(P.ABSTRACT_TEMPLATE(site, tpl_name))
 
     known_signatures = {
         'bank': {
@@ -3058,7 +3054,7 @@ def port_builtin_method_overrides(name, site, inp_ast, parent_obj):
             else:
                 n = old_idx
             new_inp.append(new_type + n)
-        report(PCHANGE_INARGS(site, 'method %s(%s)%s' % (
+        report(P.CHANGE_INARGS(site, 'method %s(%s)%s' % (
             new_name, ', '.join(new_inp), ' throws' if throws else '')))
     # Mapping objkind -> (1.4 trampoline, 1.2 trampoline)
     # Two cases:
@@ -3226,11 +3222,11 @@ def port_builtin_method_overrides(name, site, inp_ast, parent_obj):
     if name in trampoline_methods:
         (tramp14, tramp12) = trampoline_methods[name]
         if 'is dml12_compat' in tramp12:
-            report(PIMPORT_DML12COMPAT(site))
+            report(P.IMPORT_DML12COMPAT(site))
         else:
             tramp12 = ('#if (dml_1_2) {\n    %s\n}'
                        % (tramp12.replace('\n', '\n    ')))
-        report(PTRAMPOLINE(site, tramp14, tramp12))
+        report(P.TRAMPOLINE(site, tramp14, tramp12))
 
 
 def mkmethod(site, rbrace_site, location, parent_obj, name, inp_ast,
@@ -3245,7 +3241,7 @@ def mkmethod(site, rbrace_site, location, parent_obj, name, inp_ast,
     argnames = set()
     for (_, tsite, n, t) in named_args:
         if n in argnames:
-            raise EARGD(tsite, n)
+            raise E.ARGD(tsite, n)
         argnames.add(n)
 
     if logging.show_porting and body.site.dml_version() == (1, 2):
@@ -3256,26 +3252,26 @@ def mkmethod(site, rbrace_site, location, parent_obj, name, inp_ast,
         # non-integer outputs seem to be rather uncommon.
         for (_, psite, pname, ptype) in outp_ast:
             if not ptype:
-                report(PTYPEDOUTPARAM(psite, 'uint64'))
+                report(P.TYPEDOUTPARAM(psite, 'uint64'))
         if not isinstance(default, InvalidDefault):
             port_builtin_method_overrides(name, site, inp_ast, parent_obj)
             if (default.node and default.node.throws
                 and default.node.site.dml_version() == (1, 4)):
-                report(PTHROWS(body.site))
+                report(P.THROWS(body.site))
 
-    inp = eval_method_inp(inp_ast, location, global_scope)
-    outp = eval_method_outp(outp_ast, location, global_scope)
+    inp = codegen.eval_method_inp(inp_ast, location, global_scope)
+    outp = codegen.eval_method_outp(outp_ast, location, global_scope)
 
     for t in [p.typ for p in inp] + [t for (_, t) in outp]:
         if t:
-            check_named_types(t)
-            t = realtype(t)
+            tp.check_named_types(t)
+            t = tp.realtype(t)
             if t.is_int and t.is_endian:
-                raise EEARG(site)
+                raise E.EARG(site)
 
     for (n, t) in outp:
         # See SIMICS-19028
-        if t and deep_const(t):
+        if t and tp.deep_const(t):
             raise ICE(site,
                       'Methods with (partially) const output/return '
                       + 'values are not yet supported.')
@@ -3289,12 +3285,12 @@ def mkmethod(site, rbrace_site, location, parent_obj, name, inp_ast,
                             body, default, rbrace_site)
     if startup:
         (memoized_startups if memoized else startups).append(method)
-        func = method_instance(method)
-        mark_method_referenced(func)
+        func = codegen.method_instance(method)
+        codegen.mark_method_referenced(func)
 
     if logging.show_porting:
         if method.fully_typed:
-            PWUNUSED.typed_methods.add(method)
+            P.WUNUSED.typed_methods.add(method)
         else:
-            PWUNUSED.inline_methods[method.site] = method
+            P.WUNUSED.inline_methods[method.site] = method
     return method
diff --git a/py/dml/structure_test.py b/py/dml/structure_test.py
index 78a9a48d1..96f735875 100644
--- a/py/dml/structure_test.py
+++ b/py/dml/structure_test.py
@@ -78,12 +78,12 @@ def test(self):
             self.assertEqual(
                 param_linear_int(self.p(
                     lambda indices:
-                    ctree.mkCast(site, indices[0], types.TInt(64, signed)),
+                    ctree.mkCast(site, indices[0], types.Int(64, signed)),
                     (2,))),
                 (1, 0))
             self.assertEqual(
                 param_linear_int(self.p(
                     lambda indices:
-                    ctree.mkCast(site, indices[0], types.TInt(63, signed)),
+                    ctree.mkCast(site, indices[0], types.Int(63, signed)),
                     (2,))),
                 None)
diff --git a/py/dml/symtab.py b/py/dml/symtab.py
index b136ad432..9860877bb 100644
--- a/py/dml/symtab.py
+++ b/py/dml/symtab.py
@@ -12,8 +12,7 @@
     'global_scope',
     )
 
-from .logging import report, ICE, SimpleSite, dbg
-import dml.globals
+from .logging import ICE
 
 class Symbol(object):
     "a symbol in a symbol table"
diff --git a/py/dml/template.py b/py/dml/template.py
index 122f220d7..0c49a9c75 100644
--- a/py/dml/template.py
+++ b/py/dml/template.py
@@ -7,8 +7,8 @@
 import functools
 from . import ast, logging
 from . import breaking_changes
-from .logging import *
-from .messages import *
+from .logging import ICE, report
+from . import errors as E, porting as P
 from .set import Set
 import dml.globals
 import dml.traits
@@ -230,9 +230,9 @@ def flatten_ifs(in_each_specs, templates, stmts, preconds):
                                           f, preconds + [neg]))
             if logging.show_porting:
                 if t:
-                    PWUNUSED.positive_conds.add(cond)
+                    P.WUNUSED.positive_conds.add(cond)
                 if f:
-                    PWUNUSED.negative_conds.add(neg)
+                    P.WUNUSED.negative_conds.add(neg)
         elif stmt.kind == 'object':
             composite.append(stmt)
         elif stmt.kind == 'in_each':
@@ -280,7 +280,7 @@ def obj_from_asts(site, stmts):
                                         '_write_unimplemented': 'write_unimpl',}
                     for (issite, name) in template_refs:
                         if name in template_renames:
-                            report(PRENAME_TEMPLATE(issite, name,
+                            report(P.RENAME_TEMPLATE(issite, name,
                                                     template_renames[name]))
                 is_stmts.extend([(issite, templates[name])
                                  for (issite, name) in template_refs])
@@ -380,7 +380,7 @@ def process_templates(template_decls):
                     # delay error until template instantiation
                     dml.globals.missing_templates.add(missing)
                 else:
-                    report(ENTMPL(site, missing))
+                    report(E.NTMPL(site, missing))
                 template_decls[missing] = (site, [], None)
             return process_templates(template_decls)
     try:
@@ -393,9 +393,9 @@ def process_templates(template_decls):
             (ref_asts, _, _) = rank_structure(asts)
             is_sites.append(ref_asts[p].site)
         if any(name.startswith('@') for name in e.cycle):
-            report(ECYCLICIMP(is_sites))
+            report(E.CYCLICIMP(is_sites))
         else:
-            report(ECYCLICTEMPLATE(is_sites))
+            report(E.CYCLICTEMPLATE(is_sites))
         for name in e.cycle:
             # prune the templates that created a cycle
             (site, _, _) = template_decls[name]
diff --git a/py/dml/toplevel.py b/py/dml/toplevel.py
index 8e2e347ab..c12603607 100644
--- a/py/dml/toplevel.py
+++ b/py/dml/toplevel.py
@@ -14,13 +14,12 @@
 
 from ply import lex, yacc
 
-from . import objects, logging, codegen, ctree, ast
+from . import logging, codegen, ctree, ast
 from . import breaking_changes
 from . import symtab
-from .messages import *
-from .logging import *
+from . import errors as E, warnings as W, porting as P
+from .logging import ICE, DMLError, report
 import dml.globals
-import dml.dmllex
 import dml.dmlparse
 
 __all__ = ('produce_dmlast', 'get_parser', 'parse_main_file')
@@ -72,7 +71,7 @@ def determine_version(filestr, filename):
         column = ver_start - filestr.rfind('\n', 0, ver_start)
         m = check_version.match(filestr, pos=ver_start)
         if not m:
-            raise ESYNTAX(SimpleSite(f"{filename}:{lineno}:{column}"),
+            raise E.SYNTAX(logging.SimpleSite(f"{filename}:{lineno}:{column}"),
                           None, "malformed DML version tag")
         version = (int(m.group('major')), int(m.group('minor')))
         # Remove the language version tag, but preserve the correct
@@ -84,30 +83,30 @@ def determine_version(filestr, filename):
         filestr = ' ' * ver_end + filestr[ver_end:]
     else:
         if not breaking_changes.require_version_statement.enabled:
-            report(WNOVER(SimpleSite(f"{filename}:1")))
+            report(W.NOVER(logging.SimpleSite(f"{filename}:1")))
             version = (1, 2)
             lineno = 1
             column = 1
         else:
-            raise ESYNTAX(
-                SimpleSite(f"{filename}:1"), None,
+            raise E.SYNTAX(
+                logging.SimpleSite(f"{filename}:1"), None,
                 "missing DML version statement")
 
     if (not breaking_changes.require_version_statement.enabled
         and version == (1, 3)):
-        report(WDEPRECATED(
-            SimpleSite(f"{filename}:{lineno}:{column}"),
+        report(W.DEPRECATED(
+            logging.SimpleSite(f"{filename}:{lineno}:{column}"),
             "'dml 1.3' is a deprecated alias of dml 1.4"))
         version = (1, 4)
 
     if version not in supported_versions:
-        raise ESYNTAX(SimpleSite(f"{filename}:{lineno}:{column}"), None,
+        raise E.SYNTAX(logging.SimpleSite(f"{filename}:{lineno}:{column}"), None,
                       "DML version %s not supported; allowed: %s"
                       % (fmt_version(version),
                          ", ".join(map(fmt_version, supported_versions))))
 
     if logging.show_porting and version == (1, 2):
-        report(PVERSION(SimpleSite(f"{filename}:{lineno}:{column}")))
+        report(P.VERSION(logging.SimpleSite(f"{filename}:{lineno}:{column}")))
 
     return (version, filestr)
 
@@ -123,7 +122,7 @@ def parse(s, file_info, filename, version):
         ast = parser.parse(s, lexer = lexer, tracking = True,
                            tokenfunc = dml.dmlparse.mk_get_token(lexer))
     except dml.dmlparse.UnexpectedEOF:
-        raise ESYNTAX(DumpableSite(file_info, file_info.size()),
+        raise E.SYNTAX(logging.DumpableSite(file_info, file_info.size()),
                        None, "unexpected end-of-file")
     return ast
 
@@ -151,7 +150,7 @@ def scan_statements(filename, site, stmts):
         elif s.kind == 'toplevel_if':
             [cond, tbranch, fbranch, bad_stmts] = s.args
             scope = symtab.Symtab()
-            bsite = SimpleSite('',
+            bsite = logging.SimpleSite('',
                                dml_version=dml.globals.dml_version)
             # HACK Add constants to scope typically defined by dml-builtins,
             # which is not accessible here
@@ -168,10 +167,10 @@ def scan_statements(filename, site, stmts):
                 expr = ctree.as_bool(codegen.codegen_expression(
                     cond, None, scope))
                 if not expr.constant:
-                    raise ENCONST(expr.site, expr)
-            except EIDENT:
+                    raise E.NCONST(expr.site, expr)
+            except E.IDENT:
                 for stmt in bad_stmts:
-                    report(EBADCONDSTMT(stmt.site, stmt.kind))
+                    report(E.BADCONDSTMT(stmt.site, stmt.kind))
             except DMLError as e:
                 report(e)
             else:
@@ -203,7 +202,7 @@ def check_bidi(filename, filestr):
     for m in bidi_re.finditer(filestr):
         lineno = filestr[:m.start()].count('\n') + 1
         col = m.start() - filestr.rfind('\n', 0, m.start())
-        report(ESYNTAX(SimpleSite(f"{filename}:{lineno}:{col}"),
+        report(E.SYNTAX(logging.SimpleSite(f"{filename}:{lineno}:{col}"),
                        repr(m.group())[1:-1],
                        "Unicode BiDi character not allowed"))
 
@@ -222,7 +221,7 @@ def parse_pragma(filename, start_lineno, end_lineno, pragma, data):
     if pragma == 'COVERITY':
         data = data and pragma_coverity_data_re.match(data)
         if data is None:
-            report(ESYNTAX(SimpleSite(f"{filename}:{start_lineno}"),
+            report(E.SYNTAX(logging.SimpleSite(f"{filename}:{start_lineno}"),
                            None,
                            "COVERITY pragma must specify event to suppress, "
                            + "and optionally classification"))
@@ -230,7 +229,7 @@ def parse_pragma(filename, start_lineno, end_lineno, pragma, data):
             return ('COVERITY',
                     (filename, start_lineno, end_lineno + 1, data.groups()))
     else:
-        report(EPRAGMA(SimpleSite(f"{filename}:{start_lineno}"), pragma))
+        report(E.PRAGMA(logging.SimpleSite(f"{filename}:{start_lineno}"), pragma))
         return None
 
 def process_pragma(t):
@@ -251,15 +250,15 @@ def parse_file(dml_filename):
         with open(dml_filename, 'r') as f:
             filestr = f.read()
     except IOError as msg:
-        raise EIMPORT(SimpleSite(f"{dml_filename}:0"), f"{dml_filename}: {msg}")
+        raise E.IMPORT(logging.SimpleSite(f"{dml_filename}:0"), f"{dml_filename}: {msg}")
     except UnicodeDecodeError:
         with open(dml_filename, 'rb') as f:
             for (lineno, line) in enumerate(f):
                 try:
                     line.decode('utf-8')
                 except UnicodeDecodeError as e:
-                    raise ESYNTAX(
-                        SimpleSite(
+                    raise E.SYNTAX(
+                        logging.SimpleSite(
                             f"{dml_filename}:{lineno + 1}:{e.start + 1}"),
                         repr(line[e.start:e.end]),
                         'utf-8 decoding error: ' + e.reason)
@@ -275,7 +274,7 @@ def parse_file(dml_filename):
     if version == (1, 2) and logging.show_porting:
         with open(dml_filename, 'rb') as f:
             sha1 = hashlib.sha1(f.read()).hexdigest()  # nosec
-        report(PSHA1(SimpleSite(f'{dml_filename}:1:0'), sha1))
+        report(P.SHA1(logging.SimpleSite(f'{dml_filename}:1:0'), sha1))
     ast = parse(contents, file_info, dml_filename, version)
     return ast
 
@@ -284,7 +283,7 @@ def load_dmlast(ast_filename):
     try:
         return pickle.loads(bz2.BZ2File(ast_filename).read())  # nosec
     except Exception as e:
-        raise ICE(SimpleSite(ast_filename),
+        raise ICE(logging.SimpleSite(ast_filename),
                    "Failed to load AST from %r: %s"
                    % (ast_filename, e))
 
@@ -318,7 +317,7 @@ def parse_dmlast_or_dml(dml_filename):
             # This detects a common error: after getting a compile
             # error in dml-builtins.dml, one accidentally edits the
             # copy in [host]/bin/dml/, instead of the one in the repo.
-            report(WOLDAST(dml_filename))
+            report(W.OLDAST(dml_filename))
         else:
             file_info, pragmas, parsedata = load_dmlast(ast_filename)
             if file_info.name is None:
@@ -341,7 +340,7 @@ def import_file(importsite, path):
     version = site.dml_version()
     if (version != dml.globals.dml_version
         and (version, dml.globals.dml_version) != ((1, 4), (1, 2))):
-        raise EVERS(SimpleSite(f"{path}:0"),
+        raise E.VERS(logging.SimpleSite(f"{path}:0"),
                      importsite,
                      fmt_version(version),
                      fmt_version(importsite.dml_version()))
@@ -350,7 +349,7 @@ def import_file(importsite, path):
     assert version in ((1, 2), (1, 4))
 
     if name is not None:
-        raise EDEVIMP(importsite)
+        raise E.DEVIMP(importsite)
     return (site, stmts)
 
 def exists(filename):
@@ -362,7 +361,7 @@ def exists(filename):
 
 def parse_main_file(inputfilename, explicit_import_path):
     if not exists(inputfilename):
-        raise ENOFILE(SimpleSite(f"{inputfilename}:0"))
+        raise E.NOFILE(logging.SimpleSite(f"{inputfilename}:0"))
     (kind, site, name, stmts) = parse_dmlast_or_dml(
         str(Path(inputfilename).resolve()))
     # guaranteed by grammar
@@ -387,7 +386,7 @@ def parse_main_file(inputfilename, explicit_import_path):
     global_defs.append(ast.template_dml12(site, '@' + inputfilename, spec_asts))
 
     if name is None:
-        raise EDEVICE(site)
+        raise E.DEVICE(site)
 
     # Also look in a subdir named like the DML version
     import_path = [
@@ -399,7 +398,7 @@ def parse_main_file(inputfilename, explicit_import_path):
     # we may want to bump last version to 8 if we want to postpone the
     # deprecation of DML 1.2
     if version == (1, 2) and dml.globals.api_version > breaking_changes.api_7:
-        raise ESIMAPI(site, fmt_version(version), dml.globals.api_version.str)
+        raise E.SIMAPI(site, fmt_version(version), dml.globals.api_version.str)
 
     # Map normalized, absolute path of an imported file, to list of
     # seen spellings. One spelling is a string in an import statement which
@@ -423,7 +422,7 @@ def parse_main_file(inputfilename, explicit_import_path):
             path = find_file_in_dirs(importfile, import_path)
         try:
             if path is None:
-                raise EIMPORT(importsite, importfile)
+                raise E.IMPORT(importsite, importfile)
 
             deps.setdefault(path, set()).add(importfile)
 
diff --git a/py/dml/traits.py b/py/dml/traits.py
index 6be9de04f..fead3b2d7 100644
--- a/py/dml/traits.py
+++ b/py/dml/traits.py
@@ -8,17 +8,18 @@
 import contextlib
 import abc
 import os
-from . import objects, logging, crep, codegen, toplevel, topsort
+from . import crep, codegen, symtab, topsort
+from .symtab import global_scope
 from . import breaking_changes, provisional
-from .logging import *
-from .codegen import *
-from .symtab import *
-from .ctree import *
-from .expr import *
-from .expr_util import *
-from .messages import *
+from . import logging
+from .template import Rank
+from .logging import ICE, DMLError, report
+from .codegen import c_extra_inargs, c_rettype, eval_type
+from . import ctree as c
+from .expr import mkLit, NonValue
+from . import errors as E, warnings as W
 from .slotsmeta import auto_init
-from .types import *
+from . import types as tp
 from .set import Set
 import dml.globals
 
@@ -27,7 +28,6 @@
     'merge_ancestor_vtables',
     'typecheck_method_override',
     'ObjTraits',
-    'TraitObjMethod',
     'mktrait',
     'NoDefaultSymbol',
     'AmbiguousDefaultSymbol',
@@ -42,16 +42,16 @@ def process_trait(site, name, subasts, ancestors, template_symbols):
     def check_namecoll(name, site):
         if name in methods:
             (othersite, _, _, _, _, _, _, _, _, _, _) = methods[name]
-            raise ENAMECOLL(site, othersite, name)
+            raise E.NAMECOLL(site, othersite, name)
         if name in params:
             (othersite, _) = params[name]
-            raise ENAMECOLL(site, othersite, name)
+            raise E.NAMECOLL(site, othersite, name)
         if name in sessions:
             (othersite, _) = sessions[name]
-            raise ENAMECOLL(site, othersite, name)
+            raise E.NAMECOLL(site, othersite, name)
         if name in hooks:
             (othersite, _, _) = hooks[name]
-            raise ENAMECOLL(site, othersite, name)
+            raise E.NAMECOLL(site, othersite, name)
 
     for ast in subasts:
         try:
@@ -62,13 +62,13 @@ def check_namecoll(name, site):
                 startup = 'startup' in qualifiers
                 memoized = 'memoized' in qualifiers
                 if (startup and not independent) or (memoized and not startup):
-                    raise ICE(impl.site,
+                    raise ICE(ast.site,
                               'Invalid qualifier combination: '
                               + ' '.join(['independent']*independent
                                          + ['startup']*startup
                                          + ['memoized']*memoized))
-                inp = eval_method_inp(inp_asts, None, global_scope)
-                outp = eval_method_outp(outp_asts, None, global_scope)
+                inp = codegen.eval_method_inp(inp_asts, None, global_scope)
+                outp = codegen.eval_method_outp(outp_asts, None, global_scope)
                 check_namecoll(mname, ast.site)
                 methods[mname] = (ast.site, inp, outp, throws, independent,
                                   startup, memoized, overridable,
@@ -79,7 +79,7 @@ def check_namecoll(name, site):
                     (sname, type_ast) = decl_ast.args
                     (struct_defs, stype) = eval_type(
                         type_ast, ast.site, None, global_scope)
-                    add_late_global_struct_defs(struct_defs)
+                    tp.add_late_global_struct_defs(struct_defs)
                     check_namecoll(sname, ast.site)
                     sessions[sname] = (ast.site, stype)
             elif ast.kind == 'param':
@@ -90,7 +90,7 @@ def check_namecoll(name, site):
                                                  global_scope)
                 # this would be trivial to support, but completely meaningless
                 for (err_site, _) in struct_defs:
-                    report(EANONSTRUCT(err_site, "parameter type"))
+                    report(E.ANONSTRUCT(err_site, "parameter type"))
                 check_namecoll(pname, ast.site)
                 params[pname] = (ast.site, ptype)
             elif ast.kind == 'hook':
@@ -100,10 +100,10 @@ def check_namecoll(name, site):
                 for type_ast in type_asts:
                     (struct_defs, dtype) = eval_type(type_ast, ast.site, None,
                                                      global_scope)
-                    add_late_global_struct_defs(struct_defs)
-                    # TODO maybe realtype?
+                    tp.add_late_global_struct_defs(struct_defs)
+                    # TODO maybe tp.realtype?
                     msg_types.append(dtype)
-                array_lens = tuple(eval_arraylen(len_ast, global_scope)
+                array_lens = tuple(codegen.eval_arraylen(len_ast, global_scope)
                                    for len_ast in arraylen_asts)
                 check_namecoll(hname, ast.site)
                 hooks[hname] = (ast.site, array_lens, msg_types)
@@ -114,7 +114,7 @@ def check_namecoll(name, site):
     return mktrait(site, name, ancestors, methods, params, sessions, hooks,
                    template_symbols)
 
-class NoDefaultSymbol(Symbol):
+class NoDefaultSymbol(symtab.Symbol):
     """A broken reference to 'default' inside a method that has no default
     method. This is represented as an explicit symbol in order to
     report ENDEFAULT instead of the slightly less informative
@@ -122,9 +122,9 @@ class NoDefaultSymbol(Symbol):
     def __init__(self, site):
         super(NoDefaultSymbol, self).__init__('default', site=site)
     def expr(self, site):
-        raise ENDEFAULT(site)
+        raise E.NDEFAULT(site)
 
-class AmbiguousDefaultSymbol(Symbol):
+class AmbiguousDefaultSymbol(symtab.Symbol):
     """A broken reference to 'default' inside a method that has two
     possible parent methods. This is represented as an explicit
     symbol in order to report EAMBDEFAULT instead of the slightly
@@ -134,7 +134,7 @@ def __init__(self, default_method_sites):
             'default', site=default_method_sites[0])
         self.default_method_sites = default_method_sites
     def expr(self, site):
-        raise EAMBDEFAULT(site, self.default_method_sites)
+        raise E.AMBDEFAULT(site, self.default_method_sites)
 
 class TraitVTableItem(metaclass=abc.ABCMeta):
     '''A value for a struct field in a vtable instance'''
@@ -180,10 +180,10 @@ def memo_outs_struct(self):
         assert self.memoized
         if self._memo_outs_struct is None:
             memo_dict = {'p_' + name: typ for (name, typ) in self.outp}
-            memo_dict['ran'] = TInt(8, True)
+            memo_dict['ran'] = tp.Int(8, True)
             if self.throws:
-                memo_dict['threw'] = TBool()
-            self._memo_outs_struct = TStruct(
+                memo_dict['threw'] = tp.Bool()
+            self._memo_outs_struct = tp.Struct(
                 memo_dict, label=f'_memo_{self.trait.name}__{self.name}')
         return self._memo_outs_struct
 
@@ -224,9 +224,9 @@ def declaration(self):
     def codegen_body(self):
         with (crep.DeviceInstanceContext()
               if not self.independent else contextlib.nullcontext()):
-            scope = MethodParamScope(self.trait.scope(global_scope))
+            scope = symtab.MethodParamScope(self.trait.scope(global_scope))
             implicit_inargs = self.vtable_trait.implicit_args()
-            site = SimpleSite(self.site.loc())
+            site = logging.SimpleSite(self.site.loc())
             if len(self.default_traits) > 1:
                 default = AmbiguousDefaultSymbol(
                     [trait.method_impls[self.name].site
@@ -235,11 +235,11 @@ def codegen_body(self):
                 [default_trait] = self.default_traits
                 default_method = default_trait.method_impls[self.name]
                 [(name, typ)] = implicit_inargs
-                default = ExpressionSymbol(
+                default = c.ExpressionSymbol(
                     'default',
-                    TraitMethodDirect(
+                    c.TraitMethodDirect(
                         default_method.site,
-                        mkLit(site, cident(name), typ),
+                        mkLit(site, tp.cident(name), typ),
                         default_method),
                     site)
             else:
@@ -247,7 +247,7 @@ def codegen_body(self):
 
             for (n, t) in self.outp:
                 # See SIMICS-19028
-                if deep_const(t):
+                if tp.deep_const(t):
                     raise ICE(self.site,
                               'Methods with (partially) const output/return '
                               + 'values are not yet supported.')
@@ -257,21 +257,21 @@ def codegen_body(self):
                 memoization = codegen.SharedIndependentMemoized(self)
             else:
                 memoization = None
-            body = codegen_method(
+            body = codegen.codegen_method(
                 self.astbody.site, self.inp, self.outp, self.throws,
                 self.independent, memoization, self.astbody, default,
-                Location(dml.globals.device, ()), scope, self.rbrace_site)
+                c.Location(dml.globals.device, ()), scope, self.rbrace_site)
 
             downcast_path = self.downcast_path()
             if downcast_path:
-                trait_decl = mkInline(
+                trait_decl = c.mkInline(
                     site,
                     '%s UNUSED = DOWNCAST(%s, %s, %s);' % (
-                        self.trait.type().declaration('_' + cident(self.trait.name)),
-                        '_' + cident(self.vtable_trait.name),
-                        cident(self.trait.name),
-                        '.'.join(cident(t.name) for t in downcast_path)))
-                body = mkCompound(site, [trait_decl, body])
+                        self.trait.type().declaration('_' + tp.cident(self.trait.name)),
+                        '_' + tp.cident(self.vtable_trait.name),
+                        tp.cident(self.trait.name),
+                        '.'.join(tp.cident(t.name) for t in downcast_path)))
+                body = c.mkCompound(site, [trait_decl, body])
             return body
 
 def merge_ancestor_vtables(ancestors, site):
@@ -285,7 +285,7 @@ def merge_ancestor_vtables(ancestors, site):
                 # This may mean that an abstract method or parameter is
                 # defined in two traits. We could allow this, as long
                 # as types match, and it's overridden in an unambiguous way.
-                report(EAMBINH(site, None, name,
+                report(E.AMBINH(site, None, name,
                                ancestor.name, ancestor_vtables[name].name))
             else:
                 ancestor_vtables[name] = ancestor
@@ -308,7 +308,7 @@ def mktrait(site, tname, ancestors, methods, params, sessions, hooks,
             if coll:
                 (orig_site, _) = coll
                 (param_site, _) = params[name]
-                report(ENAMECOLL(param_site, orig_site, name))
+                report(E.NAMECOLL(param_site, orig_site, name))
                 bad_params.append(name)
     for name in bad_params:
         del params[name]
@@ -320,7 +320,7 @@ def mktrait(site, tname, ancestors, methods, params, sessions, hooks,
             if coll:
                 (orig_site, _) = coll
                 (session_site, _) = sessions[name]
-                report(ENAMECOLL(session_site, orig_site, name))
+                report(E.NAMECOLL(session_site, orig_site, name))
                 bad_sessions.append(name)
     for name in bad_sessions:
         del sessions[name]
@@ -333,7 +333,7 @@ def mktrait(site, tname, ancestors, methods, params, sessions, hooks,
         for p in inp:
             if p.ident:
                 if p.ident in argnames:
-                    report(EARGD(msite, p.ident))
+                    report(E.ARGD(msite, p.ident))
                     bad_methods.add(name)
                 argnames.add(p.ident)
 
@@ -345,7 +345,7 @@ def mktrait(site, tname, ancestors, methods, params, sessions, hooks,
                 (orig_site, orig_trait) = coll
                 if orig_trait.member_kind(name) != 'method':
                     # cannot override non-method with method
-                    report(ENAMECOLL(msite, orig_site, name))
+                    report(E.NAMECOLL(msite, orig_site, name))
                     bad_methods.add(name)
 
                 elif body is None and name in ancestor_vtables:
@@ -354,28 +354,28 @@ def mktrait(site, tname, ancestors, methods, params, sessions, hooks,
                     # declarations would make no sense, because the
                     # only sensible interpretation would be to ignore
                     # the declaration.
-                    report(EAMETH(msite, orig_site, name))
+                    report(E.AMETH(msite, orig_site, name))
                     bad_methods.add(name)
 
                 elif (name in orig_trait.method_impls
                       and not orig_trait.method_impls[name].overridable):
-                    report(EDMETH(msite, orig_trait.method_impls[name].site,
+                    report(E.DMETH(msite, orig_trait.method_impls[name].site,
                                   name))
                     bad_methods.add(name)
                 elif explicit_decl:
-                    report(EOVERRIDEMETH(msite, orig_site, name,
+                    report(E.OVERRIDEMETH(msite, orig_site, name,
                                          'default ' * overridable))
                     bad_methods.add(name)
                 elif name not in ancestor_vtables:
                     raise ICE(msite,
                               'ancestor is overridable but not in vtable')
-                # Type-checking of overrides is done later, after typedefs
+                # Type-checking of overrides is done later, after tp.typedefs
                 # have been populated with all template types.
                 # See Trait.typecheck_methods()
 
         if (body is not None and not some_coll and not explicit_decl
             and msite.provisional_enabled(provisional.explicit_method_decls)):
-            report(ENOVERRIDEMETH(msite, name, 'default ' * overridable))
+            report(E.NOVERRIDEMETH(msite, name, 'default ' * overridable))
             bad_methods.add(name)
 
     for name in bad_methods:
@@ -388,7 +388,7 @@ def mktrait(site, tname, ancestors, methods, params, sessions, hooks,
             if coll:
                 (orig_site, _) = coll
                 (session_site, _, _) = hooks[name]
-                report(ENAMECOLL(session_site, orig_site, name))
+                report(E.NAMECOLL(session_site, orig_site, name))
                 bad_hooks.append(name)
     for name in bad_hooks:
         del hooks[name]
@@ -411,33 +411,33 @@ def typecheck_method_override(left, right):
     (site0, inp0, outp0, throws0, independent0, startup0, memoized0) = left
     (site1, inp1, outp1, throws1, independent1, startup1, memoized1) = right
     if len(inp0) != len(inp1):
-        raise EMETH(site0, site1, "different number of input arguments")
+        raise E.METH(site0, site1, "different number of input arguments")
     if len(outp0) != len(outp1):
-        raise EMETH(site0, site1, "different number of output arguments")
+        raise E.METH(site0, site1, "different number of output arguments")
     if throws0 != throws1:
-        raise EMETH(site0, site1, "different 'throws' annotations")
+        raise E.METH(site0, site1, "different 'throws' annotations")
     for (p0, p1) in zip(inp0, inp1):
-        t0 = safe_realtype_unconst(p0.typ)
-        t1 = safe_realtype_unconst(p1.typ)
+        t0 = tp.safe_realtype_unconst(p0.typ)
+        t1 = tp.safe_realtype_unconst(p1.typ)
         ok = (t0.eq_fuzzy(t1)
               if not breaking_changes.strict_typechecking.enabled
               else t0.eq(t1))
         if not ok:
-            raise EMETH(site0, site1,
+            raise E.METH(site0, site1,
                         f"mismatching types in input argument {p0.logref}")
     for (i, ((_, t0), (_, t1))) in enumerate(zip(outp0, outp1)):
-        t0 = safe_realtype_unconst(t0)
-        t1 = safe_realtype_unconst(t1)
+        t0 = tp.safe_realtype_unconst(t0)
+        t1 = tp.safe_realtype_unconst(t1)
         ok = (t0.eq_fuzzy(t1)
               if not breaking_changes.strict_typechecking.enabled
               else t0.eq(t1))
         if not ok:
-            raise EMETH(site0, site1,
+            raise E.METH(site0, site1,
                         "mismatching types in output argument %d" % (i + 1,))
 
     def qualifier_check(qualifier_name, qualifier0, qualifier1):
         if qualifier0 != qualifier1:
-            raise EMETH(site0, site1,
+            raise E.METH(site0, site1,
                         (f"one declaration is qualified as {qualifier_name}, "
                          + "but the other is not"))
 
@@ -500,7 +500,7 @@ def merge_method_impl_maps(site, parents):
                                 and (len(existing_impls) != 1
                                      or existing_impls[0].method_impls[
                                          mname].overridable))):
-                            report(EAMBINH(
+                            report(E.AMBINH(
                                 site, None, mname,
                                 unmerged_impl.name,
                                 existing_impls[0].name))
@@ -587,7 +587,7 @@ def is_default(r):
             return rank_to_method[r].overridable
 
         [r1, r2] = sorted(minimal_ancestry[None], key=is_default)[:2]
-        raise EAMBINH(rank_to_method[r1].site,
+        raise E.AMBINH(rank_to_method[r1].site,
                       rank_to_method[r2].site,
                       rank_to_method[r1].name,
                       r1.desc, r2.desc,
@@ -604,10 +604,10 @@ def is_default(r):
     if (dml.globals.dml_version == (1, 2)
         and os.path.basename(m.site.filename()) != 'dml12-compatibility.dml'):
         if len(implementations) > 2:
-            report(WEXPERIMENTAL(
+            report(W.EXPERIMENTAL(
                 m.site, "more than one level of method overrides"))
         if len(implementations) == 2 and m.overridable:
-            report(WEXPERIMENTAL(
+            report(W.EXPERIMENTAL(
                 m.site, "method with two default declarations"))
 
     return (method_map, method_order)
@@ -692,7 +692,7 @@ def lookup_shared_method_impl(self, site, name, indices):
         assert isinstance(indices, tuple)
         for trait in self.direct_parents:
             if name in trait.method_impl_traits:
-                ref = ObjTraitRef(site, self.node, trait, indices)
+                ref = c.ObjTraitRef(site, self.node, trait, indices)
                 method = trait.lookup(name, ref, site)
                 assert method
                 return method
@@ -716,7 +716,7 @@ def exc(self):
                # template type, but not if declared inside #if
                'subobj': 'subobject %s',
                }[self.kind] % (self.name,)
-        return ENSHARED(self.site, fmt, self.template, self.decl_site)
+        return E.NSHARED(self.site, fmt, self.template, self.decl_site)
 
 class Trait(SubTrait):
     '''A trait, as defined by a top-level 'trait' statement'''
@@ -761,7 +761,7 @@ def __init__(self, site, name, ancestors, methods, params, sessions, hooks,
             if overridable and name not in ancestor_vtables}
         self.vtable_params = params
         self.vtable_sessions = sessions
-        self.vtable_hooks = {name: (hooks[name], THook(hooks[name][2]))
+        self.vtable_hooks = {name: (hooks[name], tp.Hook(hooks[name][2]))
                              for name in hooks}
         self.vtable_memoized_outs = {
             '_memo_outs_' + name: method.memo_outs_struct
@@ -782,7 +782,7 @@ def __lt__(self, other):
         return self.name < other.name
 
     def type(self):
-        return TTrait(self)
+        return tp.Trait(self)
 
     def typecheck_members(self):
         self.typecheck_methods()
@@ -791,7 +791,7 @@ def typecheck_members(self):
             bad_members = []
             for (name, (_, typ)) in table.items():
                 try:
-                    check_named_types(typ)
+                    tp.check_named_types(typ)
                 except DMLError as e:
                     report(e)
                     bad_members.append(name)
@@ -810,7 +810,7 @@ def typecheck_methods(self):
         for (_, inp, outp, _, _, _, _) in self.vtable_methods.values():
             for t in [p.typ for p in inp] + [t for (_, t) in outp]:
                 try:
-                    check_named_types(t)
+                    tp.check_named_types(t)
                 except DMLError as e:
                     report(e)
 
@@ -820,7 +820,7 @@ def typecheck_methods(self):
             if sm.name not in self.vtable_methods:
                 for t in [p.typ for p in sm.inp] + [t for (_, t) in sm.outp]:
                     try:
-                        check_named_types(t)
+                        tp.check_named_types(t)
                     except DMLError as e:
                         bad = True
                         report(e)
@@ -842,17 +842,17 @@ def typecheck_methods(self):
 
     def scope(self, global_scope):
         '''Return a scope for looking up sibling objects in this trait'''
-        s = Symtab(global_scope)
-        selfref = mkLit(self.site, '_' + cident(self.name), self.type())
+        s = symtab.Symtab(global_scope)
+        selfref = mkLit(self.site, '_' + tp.cident(self.name), self.type())
         for name in self.members():
             # This is very hacky, but works well
             try:
-                expr = mkSubRef(self.site, selfref, name, '.')
-            except EINDEPENDENTVIOL:
-                expr = InvalidSymbol(self.site, name, EINDEPENDENTVIOL)
-            s.add(ExpressionSymbol(name, expr, self.site))
+                expr = c.mkSubRef(self.site, selfref, name, '.')
+            except E.INDEPENDENTVIOL:
+                expr = c.InvalidSymbol(self.site, name, E.INDEPENDENTVIOL)
+            s.add(c.ExpressionSymbol(name, expr, self.site))
         # grammar prohibits name collision on 'this'
-        s.add(ExpressionSymbol('this', selfref, self.site))
+        s.add(c.ExpressionSymbol('this', selfref, self.site))
         return s
 
     def empty(self):
@@ -914,7 +914,7 @@ def lookup(self, name, expr, site):
         '''Look up a member of this trait; return a referencing expression or
         None. expr is an expression referencing this trait.'''
         if name == 'templates':
-            return mkTraitTemplatesRef(site, self, expr)
+            return c.mkTraitTemplatesRef(site, self, expr)
         if name in self.method_impl_traits:
             impl_traits = self.method_impl_traits[name]
             if not all(impl_trait.method_impls[name].overridable
@@ -929,42 +929,42 @@ def lookup(self, name, expr, site):
                 [impl_trait] = impl_traits
                 impl = impl_trait.method_impls[name]
                 if self is not impl_trait:
-                    expr = TraitUpcast(site, expr, impl_trait)
+                    expr = c.TraitUpcast(site, expr, impl_trait)
                 if impl_trait is not impl.vtable_trait:
-                    expr = TraitUpcast(site, expr, impl.vtable_trait)
-                return TraitMethodDirect(site, expr, impl)
+                    expr = c.TraitUpcast(site, expr, impl.vtable_trait)
+                return c.TraitMethodDirect(site, expr, impl)
         if name in self.vtable_methods:
             (_, inp, outp, throws, independent, _, _) = \
                 self.vtable_methods[name]
-            return TraitMethodIndirect(site, expr, name, inp, outp, throws,
+            return c.TraitMethodIndirect(site, expr, name, inp, outp, throws,
                                        independent)
         if name in self.vtable_params:
             (_, ptype) = self.vtable_params[name]
-            return TraitParameter(site, expr, name, ptype)
+            return c.TraitParameter(site, expr, name, ptype)
         if name in self.vtable_sessions:
             (_, ptype) = self.vtable_sessions[name]
-            return mkDereference(site, TraitSessionRef(site, expr, name, ptype))
+            return c.mkDereference(site, c.TraitSessionRef(site, expr, name, ptype))
         if name in self.vtable_hooks:
             ((_, dimsizes, _), hooktyp) = self.vtable_hooks[name]
             if dimsizes:
-                return TraitHookArrayRef(site, dimsizes, hooktyp, expr, name,
+                return c.TraitHookArrayRef(site, dimsizes, hooktyp, expr, name,
                                          ())
             else:
-                return TraitHookRef(site, (), hooktyp, expr, name, ())
+                return c.TraitHookRef(site, (), hooktyp, expr, name, ())
         vtable_trait = self.ancestor_vtables.get(name, None)
         if vtable_trait:
             return vtable_trait.lookup(
-                name, TraitUpcast(site, expr, vtable_trait), site)
+                name, c.TraitUpcast(site, expr, vtable_trait), site)
         if name in self.reserved_symbols:
             (kind, decl_site) = self.reserved_symbols[name]
             return ReservedSymbol(site, name, kind, self.name, decl_site)
         return None
 
     def implicit_args(self):
-        return [("_" + cident(self.name), self.type())]
+        return [("_" + tp.cident(self.name), self.type())]
 
     def vtable_method_type(self, inp, outp, throws, independent):
-        return TPtr(TFunction(
+        return tp.Ptr(tp.Function(
             [t for (_, t) in
              crep.maybe_dev_arg(independent) + self.implicit_args()]
             + [p.typ for p in inp]
diff --git a/py/dml/traits_test.py b/py/dml/traits_test.py
index 34f24d6d1..eb601365e 100644
--- a/py/dml/traits_test.py
+++ b/py/dml/traits_test.py
@@ -11,7 +11,6 @@
 import dml.ctree
 from dml import crep
 from dml import types
-from dml import traits
 from dml import serialize
 
 class Test_traits(unittest.TestCase):
@@ -52,4 +51,4 @@ def test_one_default_method(self):
         self.assertTrue(ref)
         # does not crash
         with crep.DeviceInstanceContext(), self.dev.use_for_codegen():
-            ref.call_expr([], types.TVoid()).read()
+            ref.call_expr([], types.Void()).read()
diff --git a/py/dml/types.py b/py/dml/types.py
index c1e2c13e2..c4fdc8384 100644
--- a/py/dml/types.py
+++ b/py/dml/types.py
@@ -24,40 +24,38 @@
     'add_late_global_struct_defs',
     'TypeSequence',
     'DMLType',
-    'TVoid',
-    'TUnknown',
-    'TDevice',
-    'TNamed',
+    'Void',
+    'Unknown',
+    'Device',
+    'Named',
     'IntegerType',
-    'TBool',
-    'TInt',
-    'TEndianInt',
-    'TLong',
-    'TSize',
-    'TFloat',
-    'TArray',
-    'TPtr',
-    'TVector',
-    'TTrait',
-    'TTraitList',
+    'Bool',
+    'Int',
+    'EndianInt',
+    'Long',
+    'Size',
+    'Float',
+    'Array',
+    'Ptr',
+    'Vector',
+    'Trait',
+    'TraitList',
     'StructType',
-    'TExternStruct',
-    'TStruct',
-    'TLayout',
-    'TFunction',
-    'THook',
+    'ExternStruct',
+    'Struct',
+    'Layout',
+    'Function',
+    'Hook',
     'cident',
     'void',
 )
 
-import sys
 import re
-from itertools import *
 
 from .env import is_windows
 from .output import out
-from .messages import *
-from .logging import *
+from . import errors as E
+from .logging import ICE, report, DMLError
 from . import breaking_changes
 from . import output
 import dml .globals
@@ -91,28 +89,28 @@ def __str__(self):
 
 def check_named_types(t):
     '''Checks that a type does not reference a non-existing type'''
-    if isinstance(t, TNamed):
+    if isinstance(t, Named):
         if t.c not in typedefs:
-            raise ETYPE(t.declaration_site, t)
+            raise E.TYPE(t.declaration_site, t)
     elif isinstance(t, StructType):
         t.resolve()
         for (mn, mt) in t.members:
             check_named_types(mt)
-    elif isinstance(t, (TPtr, TVector, TArray)):
+    elif isinstance(t, (Ptr, Vector, Array)):
         check_named_types(t.base)
-    elif isinstance(t, TFunction):
+    elif isinstance(t, Function):
         for pt in t.input_types:
             check_named_types(pt)
         check_named_types(t.output_type)
-    elif isinstance(t, TTraitList):
+    elif isinstance(t, TraitList):
         if t.traitname not in dml.globals.traits:
-            raise ETYPE(t.declaration_site, t)
-    elif isinstance(t, THook):
+            raise E.TYPE(t.declaration_site, t)
+    elif isinstance(t, Hook):
         for msg_t in t.msg_types:
             check_named_types(msg_t)
-    elif isinstance(t, (TVoid, IntegerType, TBool, TFloat, TTrait)):
+    elif isinstance(t, (Void, IntegerType, Bool, Float, Trait)):
         pass
-    elif dml.globals.dml_version == (1, 2) and isinstance(t, TUnknown):
+    elif dml.globals.dml_version == (1, 2) and isinstance(t, Unknown):
         pass
     else:
         raise ICE(t.declaration_site, "unknown type %r" % t)
@@ -122,7 +120,7 @@ def realtype_shallow(t):
     "Lookup a named type"
     #assert isinstance(t, DMLType)
     seen = set()
-    while isinstance(t, TNamed):
+    while isinstance(t, Named):
         if t in seen:
             raise ICE(t.declaration_site,
                        "recursive type definition of %r" % t)
@@ -132,8 +130,8 @@ def realtype_shallow(t):
         if not t2:
             raise DMLUnknownType(t)
         if t.const and not t2.const:
-            if isinstance(t2, TFunction):
-                raise ECONSTFUN(t.declaration_site)
+            if isinstance(t2, Function):
+                raise E.CONSTFUN(t.declaration_site)
             t = t2.clone()
             t.const = True
         else:
@@ -143,11 +141,11 @@ def realtype_shallow(t):
 def realtype(t):
     t = realtype_shallow(t)
 
-    if isinstance(t, TPtr):
+    if isinstance(t, Ptr):
         t2 = realtype(t.base)
         if t2 != t:
-            return TPtr(t2, t.const)
-    if isinstance(t, TTraitList):
+            return Ptr(t2, t.const)
+    if isinstance(t, TraitList):
         # in 'sequence(t)' and 'each t in (...)', t refers to the
         # template name rather than the type; this is a misplaced check
         # that there is a template named t.
@@ -157,23 +155,23 @@ def realtype(t):
         if (t.traitname not in dml.globals.templates
             or not dml.globals.templates[t.traitname].trait):
             raise DMLUnknownType(t)
-    elif isinstance(t, TArray):
+    elif isinstance(t, Array):
         t2 = realtype(t.base)
         if t2 != t:
-            return TArray(t2, t.size, t.const)
-    elif isinstance(t, TVector):
+            return Array(t2, t.size, t.const)
+    elif isinstance(t, Vector):
         t2 = realtype(t.base)
         if t2 != t:
-            return TVector(t2, t.const, t.uniq)
-    elif isinstance(t, TFunction):
+            return Vector(t2, t.const, t.uniq)
+    elif isinstance(t, Function):
         input_types = tuple(realtype(sub) for sub in t.input_types)
         output_type = realtype(t.output_type)
         if input_types != t.input_types or output_type != t.output_type:
-            return TFunction(input_types, output_type, t.varargs, t.const)
-    elif isinstance(t, THook):
+            return Function(input_types, output_type, t.varargs, t.const)
+    elif isinstance(t, Hook):
         msg_types = tuple(realtype(sub) for sub in t.msg_types)
         if msg_types != t.msg_types:
-            return THook(msg_types, t.validated, t.const)
+            return Hook(msg_types, t.validated, t.const)
 
     return t
 
@@ -181,19 +179,19 @@ def safe_realtype(t):
     try:
         return realtype(t)
     except DMLUnknownType as e:
-        raise ETYPE(e.type.declaration_site or None, e.type)
+        raise E.TYPE(e.type.declaration_site or None, e.type)
 
 def safe_realtype_shallow(t):
     try:
         return realtype_shallow(t)
     except DMLUnknownType as e:
-        raise ETYPE(e.type.declaration_site or None, e.type)
+        raise E.TYPE(e.type.declaration_site or None, e.type)
 
 def conv_const(const, t):
     # Functions cannot be const. Usually function types cannot happen
     # where conv_const is called, but if they can, then that deserves
     # that the caller handles it explicitly.
-    assert not isinstance(t, TFunction)
+    assert not isinstance(t, Function)
     if const and not t.const:
         t = t.clone()
         t.const = True
@@ -201,7 +199,7 @@ def conv_const(const, t):
 
 def safe_realtype_unconst(t0):
     def sub(t):
-        if isinstance(t, TArray):
+        if isinstance(t, Array):
             base = sub(t.base)
             if t.const or base is not t.base:
                 t = t.clone()
@@ -215,7 +213,7 @@ def sub(t):
 
 def shallow_const(t):
     t = safe_realtype_shallow(t)
-    while not t.const and isinstance(t, TArray):
+    while not t.const and isinstance(t, Array):
         t = safe_realtype_shallow(t.base)
 
     return t.const
@@ -226,7 +224,7 @@ def deep_const(origt):
         st = safe_realtype_shallow(subtypes.pop())
         if st.const:
             return True
-        if isinstance(st, TArray):
+        if isinstance(st, Array):
             subtypes.append(st.base)
         elif isinstance(st, StructType):
             subtypes.extend(t for (_, t) in st.members)
@@ -262,7 +260,7 @@ class DMLType(metaclass=abc.ABCMeta):
     void = False
     # shorthand for isinstance(x, IntegerType)
     is_int = False
-    # shorthand for isinstance(x, TFloat)
+    # shorthand for isinstance(x, Float)
     is_float = False
     # shorthand for (is_int or is_float)
     is_arith = False
@@ -322,8 +320,8 @@ def eq_fuzzy(self, other):
         (1) and (2) of 'eq', and does away with criteria (3) entirely.
         For example, using eq_fuzzy to compare any bitfields with its base
         integer type will return True, but also,
-        TPtr(void).eq_fuzzy(TPtr(TBool())) is allowed to return True, as is
-        TPtr(TBool()).eq_fuzzy(TArray(TBool())).
+        Ptr(void).eq_fuzzy(Ptr(Bool())) is allowed to return True, as is
+        Ptr(Bool()).eq_fuzzy(Array(Bool())).
 
         Most notably, cmp_fuzzy does not take const-qualification into account.
 
@@ -390,19 +388,19 @@ def resolve(self):
            return self"""
         return self
 
-class TVoid(DMLType):
+class Void(DMLType):
     __slots__ = ()
     void = True
     def __repr__(self):
-        return 'TVoid()'
+        return 'Void()'
     def describe(self):
         return 'void'
     def declaration(self, var):
         return 'void ' + self.const_str + ' ' + var
     def clone(self):
-        return TVoid(self.const)
+        return Void(self.const)
 
-class TUnknown(DMLType):
+class Unknown(DMLType):
     '''A type unknown to DML. Typically used for a generic C macro
     imported to DML with an untyped 'extern' declaration, where some
     argument or return value cannot be simply expressed as a C type.
@@ -417,7 +415,7 @@ def describe(self):
     def clone(self):
         raise ICE(self.declaration_site, "cannot clone unknown type")
 
-class TDevice(DMLType):
+class Device(DMLType):
     """The type of the device object
 
     This is the type of $dev. No other values have this type.
@@ -427,7 +425,7 @@ def __init__(self, name, const=False):
         DMLType.__init__(self, const)
         self.name = name
     def __repr__(self):
-        return 'TDevice(%s)' % repr(self.name)
+        return 'Device(%s)' % repr(self.name)
     def c_name(self):
         return f'{self.name} *'
     def describe(self):
@@ -438,11 +436,11 @@ def canstore(self, other):
         constviol = False
         if not self.const and other.const:
             constviol = True
-        if isinstance(other, TDevice):
+        if isinstance(other, Device):
             return (True, False, constviol)
         return (False, False, constviol)
     def clone(self):
-        return TDevice(self.name, self.const)
+        return Device(self.name, self.const)
     def declaration(self, var):
         return f'{self.c_name()}{self.const_str}{var}'
 
@@ -472,7 +470,7 @@ def cident(name):
     # Extern typedefs would have to be excluded, though.
     return cident_renames.get(name, name)
 
-class TNamed(DMLType):
+class Named(DMLType):
     __slots__ = ('c',)
     def __init__(self, name, const = False):
         DMLType.__init__(self, const)
@@ -494,15 +492,15 @@ def hashed(self):
         assert False, 'need realtype before hashed'
 
     def clone(self):
-        return TNamed(self.c, self.const)
+        return Named(self.c, self.const)
 
     def declaration(self, var):
         return cident(self.c) + ' ' + self.const_str + var
 
-class TBool(DMLType):
+class Bool(DMLType):
     __slots__ = ()
     def __repr__(self):
-        return 'TBool(%r)' % self.const
+        return 'Bool(%r)' % self.const
     def describe(self):
         return 'bool'
     def declaration(self, var):
@@ -510,14 +508,14 @@ def declaration(self, var):
 
     def canstore(self, other):
         constviol = False
-        if type(other) is TBool:
+        if type(other) is Bool:
             return (True, False, constviol)
         if (other.is_int
             and other.bits == 1 and not other.signed):
             return (True, False, constviol)
         return (False, False, constviol)
     def clone(self):
-        return TBool(self.const)
+        return Bool(self.const)
 
 class IntegerType(DMLType):
     '''Type that can contain an integer value
@@ -531,7 +529,7 @@ def __init__(self, bits, signed, members=None, const=False):
         self.bits = bits
         assert isinstance(signed, bool)
         if members is not None:
-            assert all(isinstance(m, TInt) for (m, _, _) in members.values())
+            assert all(isinstance(m, Int) for (m, _, _) in members.values())
             assert not signed
         self.signed = signed
         self.members = members
@@ -641,18 +639,18 @@ def canstore(self, other):
         else:
             return (False, False, False)
 
-class TInt(IntegerType):
+class Int(IntegerType):
     '''An integer. In a declaration, the corresponding C type is the
     smallest type with the same sign, in which the type fits.
 
     When looking at the types of rvalues, it is slightly unclear how
-    TInt maps to C integers. It seems that the bitsize of the TInt of
+    Int maps to C integers. It seems that the bitsize of the Int of
     an expression maintains an approximate upper bound of the possible
     values of the expression, and that the corresponding C type is (often)
     the first of [int32, uint32, int64, uint64] in which the DML type fits.
 
     DMLC does not seem to maintain consistency between signedness of
-    TInt and the corresponding C type. This seldom makes a difference,
+    Int and the corresponding C type. This seldom makes a difference,
     because it means that C's operational semantics is what's used in
     practice.
     '''
@@ -667,7 +665,7 @@ def describe(self):
     def describe_backing_type(self):
         return f'{"u"*(not self.signed)}int{self.bits}'
     def __repr__(self):
-        return 'TInt(%r,%r,%r,%r)' % (self.bits, self.signed,
+        return 'Int(%r,%r,%r,%r)' % (self.bits, self.signed,
                                       self.members, self.const)
 
     def apitype(self):
@@ -697,7 +695,7 @@ def canstore(self, other):
         if other.is_int:
             trunc = (other.bits > self.bits)
             if (not breaking_changes.dml12_remove_misc_quirks.enabled
-                and isinstance(other, TBool)):
+                and isinstance(other, Bool)):
                 return (False, False, constviol)
             return (True, trunc, constviol)
         if other.is_float and not self.is_bitfields:
@@ -705,7 +703,7 @@ def canstore(self, other):
         return (False, False, constviol)
 
     def clone(self):
-        return TInt(self.bits, self.signed, self.members, self.label,
+        return Int(self.bits, self.signed, self.members, self.label,
                     self.const)
 
     def declaration(self, var):
@@ -716,7 +714,7 @@ def declaration(self, var):
         else:
             return 'uint8 ' + self.const_str + var + '[' + str(self.bytes) + ']'
 
-class TLong(IntegerType):
+class Long(IntegerType):
     '''The 'long' type from C'''
     __slots__ = ()
     def __init__(self, signed, const=False):
@@ -730,15 +728,15 @@ def describe_backing_type(self):
         return self.c_name()
 
     def __repr__(self):
-        return 'TLong(%r, %r)' % (self.signed, self.const)
+        return 'Long(%r, %r)' % (self.signed, self.const)
 
     def clone(self):
-        return TLong(self.signed, self.const)
+        return Long(self.signed, self.const)
 
     def declaration(self, var):
         return f'{self.const_str}{self.c_name()} {var}'
 
-class TSize(IntegerType):
+class Size(IntegerType):
     '''The 'size_t' type from C'''
     __slots__ = ()
     def __init__(self, signed, const=False):
@@ -751,15 +749,15 @@ def describe_backing_type(self):
         return self.c_name()
 
     def __repr__(self):
-        return 'TSize(%r, %r)' % (self.signed, self.const)
+        return 'Size(%r, %r)' % (self.signed, self.const)
 
     def clone(self):
-        return TSize(self.signed, self.const)
+        return Size(self.signed, self.const)
 
     def declaration(self, var):
         return f'{self.const_str}{self.c_name()} {var}'
 
-class TInt64_t(IntegerType):
+class Int64_t(IntegerType):
     '''The '[u]int64_t' type from ISO C. For compatibility with C
     APIs, e.g., calling an externally defined C function that takes a
     `uint64_t *` arg. We find `uint64` a generally more useful type
@@ -777,15 +775,15 @@ def describe_backing_type(self):
         return self.c_name()
 
     def __repr__(self):
-        return 'TInt64_t(%r, %r)' % (self.signed, self.const)
+        return 'Int64_t(%r, %r)' % (self.signed, self.const)
 
     def clone(self):
-        return TInt64_t(self.signed, self.const)
+        return Int64_t(self.signed, self.const)
 
     def declaration(self, var):
         return f'{self.const_str}{self.c_name()} {var}'
 
-class TEndianInt(IntegerType):
+class EndianInt(IntegerType):
     '''An integer where the byte storage order is defined.
     Corresponds to the (u)?intX_[be|le] family of types defined in
     dmllib.h
@@ -813,13 +811,13 @@ def describe_backing_type(self):
         return self.c_name()
 
     def __repr__(self):
-        return 'TEndianInt(%r,%r,%r,%r,%r)' % (
+        return 'EndianInt(%r,%r,%r,%r,%r)' % (
             self.bits, self.signed, self.byte_order, self.members, self.const)
 
     @property
     def access_type(self):
         """Integer type used for read/write access"""
-        return TInt(64, self.signed or self.bits != 64)
+        return Int(64, self.signed or self.bits != 64)
 
     def dmllib_fun(self, fun):
         """translate a function name to the c dmllib function"""
@@ -848,22 +846,22 @@ def get_store_fun(self):
         """function reference to dmllib function used to store values to an
         endianint"""
         return (self.dmllib_store,
-                TFunction([self.access_type], self))
+                Function([self.access_type], self))
 
     def get_load_fun(self):
         """function reference to dmllib function used to load values from an
         endianint"""
         return (self.dmllib_load,
-                TFunction([self], self.access_type))
+                Function([self], self.access_type))
 
     def clone(self):
-        return TEndianInt(self.bits, self.signed,
+        return EndianInt(self.bits, self.signed,
                           self.byte_order, self.members, self.const)
 
     def declaration(self, var):
         return f'{self.const_str}{self.c_name()} {var}'
 
-class TFloat(DMLType):
+class Float(DMLType):
     __slots__ = ('name',)
     is_float = True
     is_arith = True
@@ -879,22 +877,22 @@ def eq(self, other):
                 and other.is_float and self.name == other.name)
 
     def hashed(self):
-        return hash((TFloat, self.const, self.name))
+        return hash((Float, self.const, self.name))
 
     def canstore(self, other):
         constviol = False
         if other.is_float:
             return (True, False, constviol)
-        if isinstance(other, TInt):
+        if isinstance(other, Int):
             return (True, True, constviol)
         return (False, False, constviol)
 
     def declaration(self, var):
         return self.name + ' ' + self.const_str + var
     def clone(self):
-        return TFloat(self.name, self.const)
+        return Float(self.name, self.const)
 
-class TArray(DMLType):
+class Array(DMLType):
     __slots__ = ('base', 'size')
     def __init__(self, base, size, const = False):
         DMLType.__init__(self, const)
@@ -903,7 +901,7 @@ def __init__(self, base, size, const = False):
         self.base = base
         self.size = size
     def __repr__(self):
-        return "TArray(%r,%r,%r)" % (self.base, self.size, self.const)
+        return "Array(%r,%r,%r)" % (self.base, self.size, self.const)
     def key(self):
         if not self.size.constant:
             raise DMLUnkeyableType(self, "array of non-constant size")
@@ -934,7 +932,7 @@ def sizeof(self):
         return self.size.value * elt_size
 
     def eq(self, other):
-        if not isinstance(other, TArray):
+        if not isinstance(other, Array):
             return False
         if not (self.size is other.size
                 or (self.size.constant and other.size.constant
@@ -944,25 +942,25 @@ def eq(self, other):
             conv_const(other.const, other.base))
 
     def eq_fuzzy(self, other):
-        if isinstance(other, (TArray, TPtr)):
+        if isinstance(other, (Array, Ptr)):
             return other.base.void or self.base.eq_fuzzy(other.base)
         return False
 
     def hashed(self):
         size = self.size.value if self.size.constant else self.size
-        return hash((TArray,
+        return hash((Array,
                      size,
                      conv_const(self.const, self.base).hashed()))
 
     def canstore(self, other):
         return (False, False, False)
     def clone(self):
-        return TArray(self.base, self.size, self.const)
+        return Array(self.base, self.size, self.const)
     def resolve(self):
         self.base.resolve()
         return self
 
-class TPtr(DMLType):
+class Ptr(DMLType):
     __slots__ = ('base',)
     def __init__(self, base, const = False):
         DMLType.__init__(self, const)
@@ -970,7 +968,7 @@ def __init__(self, base, const = False):
             raise DMLTypeError("base is not a type: %r" % (base,))
         self.base = base
     def __repr__(self):
-        return "TPtr(%r,%r)" % (self.base, self.const)
+        return "Ptr(%r,%r)" % (self.base, self.const)
     def key(self):
         return f'{self.const_str}pointer({self.base.key()})'
     def describe(self):
@@ -980,20 +978,20 @@ def eq(self, other):
         return DMLType.eq(self, other) and self.base.eq(other.base)
 
     def eq_fuzzy(self, other):
-        if isinstance(other, (TPtr, TArray)):
+        if isinstance(other, (Ptr, Array)):
             if self.base.void or other.base.void:
                 return True
             return self.base.eq_fuzzy(other.base)
         return False
 
     def hashed(self):
-        return hash((TPtr, self.const, self.base.hashed()))
+        return hash((Ptr, self.const, self.base.hashed()))
 
     def canstore(self, other):
         ok = False
         trunc = False
         constviol = False
-        if isinstance(other, (TPtr, TArray)):
+        if isinstance(other, (Ptr, Array)):
             constviol = (not shallow_const(self.base)
                          and shallow_const(other.base))
             if self.base.void or other.base.void:
@@ -1010,21 +1008,21 @@ def canstore(self, other):
                           and unconst_other_base.is_int)
                       else unconst_self_base.eq)(unconst_other_base)
 
-        elif isinstance(other, TFunction):
+        elif isinstance(other, Function):
             ok = (not breaking_changes.strict_typechecking.enabled
                   or safe_realtype_unconst(self.base).eq(other))
         # TODO gate this behind dml.globals.dml_version == (1, 2) or
         # remove_misc_quirks?
-        if self.base.void and isinstance(other, TDevice):
+        if self.base.void and isinstance(other, Device):
             ok = True
-        #dbg('TPtr.canstore %r %r => %r' % (self, other, ok))
+        #dbg('Ptr.canstore %r %r => %r' % (self, other, ok))
         return (ok, trunc, constviol)
 
     def clone(self):
-        return TPtr(self.base, self.const)
+        return Ptr(self.base, self.const)
 
     def declaration(self, var):
-        if isinstance(self.base, (TFunction, TArray)):
+        if isinstance(self.base, (Function, Array)):
             var = f'(*{self.const_str}{var})'
         else:
             var = f'*{self.const_str}{var}'
@@ -1033,20 +1031,20 @@ def resolve(self):
         self.base.resolve()
         return self
 
-class TVector(DMLType):
+class Vector(DMLType):
     count = 0
     __slots__ = ('base', 'uniq',)
     def __init__(self, base, const=False, uniq=None):
         DMLType.__init__(self, const)
         if uniq is None:
-            uniq = TVector.count
-            TVector.count += 1
+            uniq = Vector.count
+            Vector.count += 1
         self.uniq = uniq
         if not base:
             raise DMLTypeError("Null base")
         self.base = base
     def __repr__(self):
-        return "TVector(%r,%r)" % (self.base, self.const)
+        return "Vector(%r,%r)" % (self.base, self.const)
     def key(self):
         raise DMLUnkeyableType(self)
     def describe(self):
@@ -1054,21 +1052,21 @@ def describe(self):
     def eq(self, other):
         return DMLType.eq(self, other) and self.uniq == other.uniq
     def eq_fuzzy(self, other):
-        if isinstance(other, TVector):
+        if isinstance(other, Vector):
             # Can only compare for voidness or equality
             if self.base.void or other.base.void:
                 return True
             return self.base.eq_fuzzy(other.base)
         return False
     def hashed(self):
-        return hash((TVector, self.const, self.uniq))
+        return hash((Vector, self.const, self.uniq))
     def clone(self):
-        return TVector(self.base, self.const, self.uniq)
+        return Vector(self.base, self.const, self.uniq)
     def declaration(self, var):
         s = self.base.declaration('')
         return 'VECT(%s) %s%s' % (s, self.const_str, var)
 
-class TTrait(DMLType):
+class Trait(DMLType):
     '''A run-time reference to a trait. Represented in C as a pointer
     to a trait vtable struct, together with an object identity'''
     __slots__ = ('trait',)
@@ -1078,10 +1076,10 @@ def __init__(self, trait, const=False):
         self.trait = trait
 
     def __repr__(self):
-        return "TTrait(%s)" % (self.trait.name,)
+        return "Trait(%s)" % (self.trait.name,)
 
     def clone(self):
-        return TTrait(self.trait, self.const)
+        return Trait(self.trait, self.const)
 
     def eq(self, other):
         return DMLType.eq(self, other) and self.trait is other.trait
@@ -1090,7 +1088,7 @@ def key(self):
         return f'{self.const_str}trait({self.trait.name})'
 
     def hashed(self):
-        return hash((TTrait, self.const, self.trait))
+        return hash((Trait, self.const, self.trait))
 
     def c_name(self):
         return cident(self.trait.name)
@@ -1101,7 +1099,7 @@ def describe(self):
     def declaration(self, var):
         return f'{self.const_str}{self.c_name()} {var}'
 
-class TTraitList(DMLType):
+class TraitList(DMLType):
     __slots__ = ('traitname')
 
     def __init__(self, traitname, const=False):
@@ -1109,10 +1107,10 @@ def __init__(self, traitname, const=False):
         self.traitname = traitname
 
     def __repr__(self):
-        return "TTraitList(%s)" % (self.traitname,)
+        return "TraitList(%s)" % (self.traitname,)
 
     def clone(self):
-        return TTraitList(self.traitname, self.const)
+        return TraitList(self.traitname, self.const)
 
     def eq(self, other):
         return DMLType.eq(self, other) and self.traitname == other.traitname
@@ -1121,7 +1119,7 @@ def key(self):
         return f'{self.const_str}sequence({self.traitname})'
 
     def hashed(self):
-        return hash((TTraitList, self.const, self.traitname))
+        return hash((TraitList, self.const, self.traitname))
 
     def c_type(self):
         return f'{self.const_str}_each_in_t'
@@ -1156,7 +1154,7 @@ def get_member_qualified(self, member):
         t = self.named_members.get(member)
         return t if t is None else conv_const(self.const, t)
 
-class TExternStruct(StructType):
+class ExternStruct(StructType):
     '''A struct-like type defined by code outside DMLC's control.
     'members' is the potential right operands of binary '.',
     and 'label' is the typedef:ed type name.'''
@@ -1164,7 +1162,7 @@ class TExternStruct(StructType):
     count = 0
 
     def __init__(self, named_members, id, typename=None, const=False):
-        super(TExternStruct, self).__init__(named_members, const)
+        super(ExternStruct, self).__init__(named_members, const)
         # unique object (wrt ==) representing this type in type comparisons
         # integer for anonymous structs, string for named types
         self.id = id
@@ -1172,13 +1170,13 @@ def __init__(self, named_members, id, typename=None, const=False):
         self.typename = typename
 
     def __repr__(self):
-        return 'TExternStruct(%r,%r,%r,%r)' % (
+        return 'ExternStruct(%r,%r,%r,%r)' % (
             self.named_members, self.id, self.typename, self.const)
 
     @staticmethod
     def unique_id():
-        TExternStruct.count += 1
-        return TExternStruct.count
+        ExternStruct.count += 1
+        return ExternStruct.count
 
     def key(self):
         if not self.typename:
@@ -1191,24 +1189,24 @@ def describe(self):
 
     def declaration(self, var):
         if not self.typename:
-            raise EANONEXT(self.declaration_site)
+            raise ICE(self.declaration_site, 'no typename')
         return "%s %s%s" % (self.typename, self.const_str, var)
 
     def eq(self, other):
         return DMLType.eq(self, other) and self.id == other.id
 
     def hashed(self):
-        return hash((TExternStruct, self.const, self.id))
+        return hash((ExternStruct, self.const, self.id))
 
     def clone(self):
-        return TExternStruct(self.named_members,
+        return ExternStruct(self.named_members,
                              self.id, self.typename, self.const)
 
 def add_late_global_struct_defs(decls):
-    TStruct.late_global_struct_defs.extend((site, t.resolve())
+    Struct.late_global_struct_defs.extend((site, t.resolve())
                                            for (site, t) in decls)
 
-class TStruct(StructType):
+class Struct(StructType):
     __slots__ = ('label', 'anonymous')
     # Anonymous struct types defined in global scope, but outside typedef
     # declarations, e.g. 'session struct { int x; } y;'.
@@ -1219,13 +1217,13 @@ def __init__(self, members, label=None, const=False):
         assert members is None or members
         self.anonymous = label is None
         if self.anonymous:
-            label = '_anon_struct_%d' % (TStruct.num_anon_structs,)
-            TStruct.num_anon_structs += 1
+            label = '_anon_struct_%d' % (Struct.num_anon_structs,)
+            Struct.num_anon_structs += 1
         self.label = label
         super().__init__(members, const)
 
     def __repr__(self):
-        return 'TStruct(%r,%r,%r)' % (self.named_members, self.label,
+        return 'Struct(%r,%r,%r)' % (self.named_members, self.label,
                                       self.const)
 
     def key(self):
@@ -1255,7 +1253,7 @@ def print_struct_definition(self):
             output.site_linemark(t.declaration_site)
             t.print_declaration(n
                                 if n is not None else
-                                TStruct.anon_member_cident(i))
+                                Struct.anon_member_cident(i))
         output.site_linemark(self.declaration_site)
         out("};\n", preindent = -1)
 
@@ -1263,25 +1261,25 @@ def eq(self, other):
         return DMLType.eq(self, other) and self.label == other.label
 
     def hashed(self):
-        return hash((TStruct, self.const, self.label))
+        return hash((Struct, self.const, self.label))
 
     def clone(self):
-        return TStruct(self.named_members, self.label, self.const)
+        return Struct(self.named_members, self.label, self.const)
 
-class TLayout(TStruct):
+class Layout(Struct):
     __slots__= ('endian', 'member_decls', 'size', 'discarded')
 
     def __init__(self, endian, member_decls, label=None, const=False):
         # Intentionally wait with setting member types until
         # resolve is finished
-        super(TLayout, self).__init__(None, label, const)
+        super(Layout, self).__init__(None, label, const)
         self.member_decls = member_decls
         self.endian = endian
         self.size = None
         self.discarded = None
 
     def __repr__(self):
-        return 'TLayout(%r, %r, %r, %r)' % (self.endian, self.member_decls,
+        return 'Layout(%r, %r, %r, %r)' % (self.endian, self.member_decls,
                                             self.label, self.const)
     def key(self):
         if self.anonymous:
@@ -1315,34 +1313,34 @@ def check_layout_member_type(site, t, memberref):
             rt = t
             # We cannot use non-shallow instead of this loop because we need
             # to keep track of when we move through arrays
-            while isinstance(rt, TNamed):
+            while isinstance(rt, Named):
                 rt = safe_realtype_shallow(rt)
             rt.resolve()
-            if isinstance(rt, TLayout):
+            if isinstance(rt, Layout):
                 # In the case of a layout, we need to keep the member type as
                 # the original declared type to prevent dis-aliasing a typedef.
                 return t, rt
             if rt.is_int:
                 if (rt.bits % 8) != 0:
-                    raise ELAYOUT(site,
+                    raise E.LAYOUT(site,
                                   f"size of {memberref} is not a whole byte")
-            if (isinstance(rt, TInt)
+            if (isinstance(rt, Int)
                 or (dml.globals.compat_dml12_int(site)
-                    and isinstance(rt, TSize))):
-                toret = TEndianInt(rt.bits, rt.signed,
+                    and isinstance(rt, Size))):
+                toret = EndianInt(rt.bits, rt.signed,
                                    self.endian, rt.members, rt.const)
                 return (toret, toret)
-            if isinstance(rt, TEndianInt):
+            if isinstance(rt, EndianInt):
                 return (rt, rt)
-            if isinstance(rt, TArray):
+            if isinstance(rt, Array):
                 # In the case of an array, we return one array that respects
                 # the original declaration when necessary, and one array
                 # that is the fully resolved type
                 new_base, real_base = check_layout_member_type(
                     site, rt.base, memberref)
-                return (TArray(new_base, rt.size, rt.const),
-                        TArray(real_base, rt.size, rt.const),)
-            raise ELAYOUT(site, "illegal layout member type: %s" % t)
+                return (Array(new_base, rt.size, rt.const),
+                        Array(real_base, rt.size, rt.const),)
+            raise E.LAYOUT(site, "illegal layout member type: %s" % t)
 
         self.size = 0
         self.named_members = {}
@@ -1365,7 +1363,7 @@ def check_layout_member_type(site, t, memberref):
                 size = rt.sizeof()
                 if size is None:
                     # variable-sized array
-                    raise ELAYOUT(site, "unknown layout size")
+                    raise E.LAYOUT(site, "unknown layout size")
                 else:
                     self.size += size
             except DMLError as e:
@@ -1380,7 +1378,7 @@ def sizeof(self):
         return self.size
 
     def clone(self):
-        cloned = TLayout(self.endian, self.member_decls, self.label,
+        cloned = Layout(self.endian, self.member_decls, self.label,
                          self.const)
         if self.named_members is not None:
             cloned.named_members = self.named_members
@@ -1390,7 +1388,7 @@ def clone(self):
 
 
 
-class TFunction(DMLType):
+class Function(DMLType):
     __slots__ = ('input_types', 'output_type', 'varargs')
     def __init__(self, input_types, output_type,
                  varargs = False, const = False):
@@ -1400,7 +1398,7 @@ def __init__(self, input_types, output_type,
         self.output_type = output_type
         self.varargs = varargs
     def __repr__(self):
-        return "TFunction(%r,%r)" % (self.input_types, self.output_type)
+        return "Function(%r,%r)" % (self.input_types, self.output_type)
 
     @property
     def const(self): return False
@@ -1426,7 +1424,7 @@ def describe(self):
                 % (inparams, self.output_type.describe()))
 
     def eq(self, other):
-        return (isinstance(other, TFunction)
+        return (isinstance(other, Function)
                 and len(self.input_types) == len(other.input_types)
                 and all(
                     safe_realtype_unconst(arg1).eq(safe_realtype_unconst(arg2))
@@ -1437,7 +1435,7 @@ def eq(self, other):
                 and self.varargs == other.varargs)
 
     def eq_fuzzy(self, other):
-        return (isinstance(other, TFunction)
+        return (isinstance(other, Function)
                 and len(self.input_types) == len(other.input_types)
                 and all(arg1.eq_fuzzy(arg2)
                         for (arg1, arg2)
@@ -1446,7 +1444,7 @@ def eq_fuzzy(self, other):
                 and self.varargs == other.varargs)
 
     def hashed(self):
-        return hash((TFunction,
+        return hash((Function,
                      tuple(safe_realtype_unconst(typ).hashed()
                            for typ in self.input_types),
                      safe_realtype_unconst(self.output_type).hashed(),
@@ -1456,7 +1454,7 @@ def canstore(self, other):
         return (False, False, False)
 
     def clone(self):
-        return TFunction(self.input_types, self.output_type, self.varargs,
+        return Function(self.input_types, self.output_type, self.varargs,
                          self.const)
 
     def declaration(self, var):
@@ -1466,7 +1464,7 @@ def declaration(self, var):
             arglist += ", ..."
         return self.output_type.declaration(f'{var}({arglist})')
 
-class THook(DMLType):
+class Hook(DMLType):
     __slots__ = ('msg_types', 'validated')
 
     def __init__(self, msg_types, validated=False, const=False):
@@ -1475,10 +1473,10 @@ def __init__(self, msg_types, validated=False, const=False):
         self.validated = validated
 
     def __repr__(self):
-        return 'THook(%s)' % (', '.join(repr(typ) for typ in self.msg_types),)
+        return 'Hook(%s)' % (', '.join(repr(typ) for typ in self.msg_types),)
 
     def clone(self):
-        return THook(self.msg_types, self.validated, self.const)
+        return Hook(self.msg_types, self.validated, self.const)
 
     def eq(self, other):
         return (DMLType.eq(self, other)
@@ -1488,7 +1486,7 @@ def eq(self, other):
                                                           other.msg_types)))
 
     def hashed(self):
-        return hash((THook,
+        return hash((Hook,
                      self.const,
                      tuple(comp.hashed() for comp in self.msg_types)))
 
@@ -1510,7 +1508,7 @@ def validate(self, fallback_site):
                 try:
                     safe_realtype(typ).key()
                 except DMLUnkeyableType as e:
-                    raise EHOOKTYPE(self.declaration_site or fallback_site,
+                    raise E.HOOKTYPE(self.declaration_site or fallback_site,
                                     typ, e.clarification) from e
 
 
@@ -1523,47 +1521,47 @@ def parse_type(typename):
         bits = int(m.group(2))
         byte_order = m.group(3)
         if byte_order:
-            return TEndianInt(
+            return EndianInt(
                 bits, signed,
                 "big-endian" if byte_order == "_be_t" else "little-endian")
         else:
-            return TInt(bits, signed)
+            return Int(bits, signed)
     elif typename in {'double', 'float'}:
-        return TFloat(typename)
+        return Float(typename)
     elif typename == 'bool':
-        return TBool()
+        return Bool()
     elif typename == 'void':
-        return TVoid()
+        return Void()
     elif typename == 'integer_t' and dml.globals.api_version < breaking_changes.api_7:
-        return TInt(64, True)
+        return Int(64, True)
     elif typename == 'uinteger_t' and dml.globals.api_version < breaking_changes.api_7:
-        return TInt(64, False)
+        return Int(64, False)
     else:
-        return TNamed(typename)
+        return Named(typename)
 
 def type_union(type1, type2):
     "Return the greater of two types"
-    if (type1.is_float or isinstance(type1, TUnknown)
+    if (type1.is_float or isinstance(type1, Unknown)
         or (type1.is_int and type2.is_int
             and type1.bits > type2.bits)):
         return type1
     return type2
 
-void = TVoid()
+void = Void()
 # These are the named types used.  This includes both "imported"
 # typedefs for types declared in C header files, and types defined in
 # the DML file.
 typedefs = {}
 for (name, typ) in [
         ('void', void),
-        ('int', TInt(32, True)),
-        ('char', TInt(8, True)),
-        ('long', TLong(True)),
-        ('ulong', TLong(False)),
-        ('ssize_t', TSize(True)),
-        ('size_t', TSize(False)),
-        ('int64_t', TInt64_t(True)),
-        ('uint64_t', TInt64_t(False))]:
+        ('int', Int(32, True)),
+        ('char', Int(8, True)),
+        ('long', Long(True)),
+        ('ulong', Long(False)),
+        ('ssize_t', Size(True)),
+        ('size_t', Size(False)),
+        ('int64_t', Int64_t(True)),
+        ('uint64_t', Int64_t(False))]:
     typedefs[name] = typ
 
 for sym in __all__:
diff --git a/py/dml/types_test.py b/py/dml/types_test.py
index 27970800a..24fff4afc 100644
--- a/py/dml/types_test.py
+++ b/py/dml/types_test.py
@@ -1,7 +1,7 @@
 # © 2024 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from dml.types import *
+import dml.types as tp
 import dml.globals
 from dml import ctree
 from dml import expr
@@ -14,48 +14,48 @@
 class TestClone(unittest.TestCase):
     def test(self):
         # types which support clone
-        typ0 = TVoid()
-        for typ in (TVoid(),
-                    TNamed("int"),
-                    TBool(),
-                    TInt(8, False, {}),
-                    TEndianInt(8, False, 'big-endian', {}),
-                    TFloat("a"),
-                    TArray(typ0, ctree.mkIntegerLiteral(0, 2)),
-                    TPtr(typ0),
-                    TVector(typ0),
-                    TTrait(object()),
-                    TStruct({"name": TInt(32, False)}),
-                    TLayout("big-endian", []),
-                    TDevice("a")):
+        typ0 = tp.Void()
+        for typ in (tp.Void(),
+                    tp.Named("int"),
+                    tp.Bool(),
+                    tp.Int(8, False, {}),
+                    tp.EndianInt(8, False, 'big-endian', {}),
+                    tp.Float("a"),
+                    tp.Array(typ0, ctree.mkIntegerLiteral(0, 2)),
+                    tp.Ptr(typ0),
+                    tp.Vector(typ0),
+                    tp.Trait(object()),
+                    tp.Struct({"name": tp.Int(32, False)}),
+                    tp.Layout("big-endian", []),
+                    tp.Device("a")):
             typ_clone = typ.clone()
             self.assertTrue(
-                realtype(typ_clone).eq(realtype(typ)))
+                tp.realtype(typ_clone).eq(tp.realtype(typ)))
             self.assertTrue(
-                realtype(typ).eq(realtype(typ_clone)))
+                tp.realtype(typ).eq(tp.realtype(typ_clone)))
             typ_clone.const = True
             self.assertFalse(typ.const)
             typ = typ_clone.clone()
             self.assertTrue(typ.const)
 
-        # special case for TraitList, because realtype requires global
+        # special case for tp.TraitList, because tp.realtype requires global
         # state (typedefs)
-        typ = TTraitList("a")
+        typ = tp.TraitList("a")
         typ_clone = typ.clone()
         self.assertTrue(typ.eq(typ_clone))
         self.assertTrue(typ_clone.eq(typ))
         dml.globals.dml_version = (1, 2)
         # types which do not support clone
         with self.assertRaises(logging.ICE):
-            TUnknown().clone()
+            tp.Unknown().clone()
 
-class Typ1(DMLType):
+class Typ1(tp.DMLType):
     def describe(self):
         return 'Typ1'
     def clone(self):
         return Typ1(self.const)
 
-class Typ2(DMLType):
+class Typ2(tp.DMLType):
     def describe(self):
         return 'Typ2'
     def clone(self):
@@ -68,7 +68,7 @@ def assert_eq(self, t1, t2):
         self.assertEqual(t1.hashed(), t2.hashed())
         try:
             self.assertEqual(t1.key(), t2.key())
-        except DMLUnkeyableType:
+        except tp.DMLUnkeyableType:
             pass
 
     def assert_neq(self, t1, t2, hash_collision=False):
@@ -78,7 +78,7 @@ def assert_neq(self, t1, t2, hash_collision=False):
             self.assertNotEqual(t1.hashed(), t2.hashed())
             try:
                 self.assertNotEqual(t1.key(), t2.key())
-            except DMLUnkeyableType:
+            except tp.DMLUnkeyableType:
                 pass
 
     def test_DMLType(self):
@@ -87,22 +87,22 @@ def test_DMLType(self):
         self.assert_neq(Typ1(), Typ2())
 
     def test_IntegerType(self):
-        self.assert_eq(TInt(8, False), TInt(8, False))
-        self.assert_neq(TInt(16, False), TInt(8, False))
+        self.assert_eq(tp.Int(8, False), tp.Int(8, False))
+        self.assert_neq(tp.Int(16, False), tp.Int(8, False))
         # Not equivalent even though the C representations of uint16 and uint13
         # are compatible
-        self.assert_neq(TInt(16, False), TInt(13, False))
+        self.assert_neq(tp.Int(16, False), tp.Int(13, False))
         # Signedness
-        self.assert_neq(TInt(8, True), TInt(8, False))
+        self.assert_neq(tp.Int(8, True), tp.Int(8, False))
 
         # bitfields
-        self.assert_neq(TInt(8, False), TInt(8, False, members={}))
+        self.assert_neq(tp.Int(8, False), tp.Int(8, False, members={}))
 
         def bitfields():
-            return TInt(32, False, { 'a': (TInt(8, False), 13, 6),
-                                     'b': (TInt(13, False), 27, 15) })
+            return tp.Int(32, False, { 'a': (tp.Int(8, False), 13, 6),
+                                     'b': (tp.Int(13, False), 27, 15) })
 
-        self.assert_eq(TInt(8, False, members={}), TInt(8, False, members={}))
+        self.assert_eq(tp.Int(8, False, members={}), tp.Int(8, False, members={}))
         self.assert_eq(bitfields(), bitfields())
 
         @contextmanager
@@ -134,19 +134,19 @@ def neq_bitfields_testcase():
             del t.members['b']
 
     def test_TEndianInt(self):
-        self.assert_eq(TEndianInt(8, False, 'big-endian'),
-                       TEndianInt(8, False, 'big-endian'))
-        self.assert_neq(TEndianInt(8, False, 'big-endian'),
-                        TEndianInt(8, False, 'little-endian'))
+        self.assert_eq(tp.EndianInt(8, False, 'big-endian'),
+                       tp.EndianInt(8, False, 'big-endian'))
+        self.assert_neq(tp.EndianInt(8, False, 'big-endian'),
+                        tp.EndianInt(8, False, 'little-endian'))
 
     def test_TFloat(self):
-        self.assert_eq(TFloat('double'), TFloat('double'))
-        self.assert_neq(TFloat('double'), TFloat('float'))
+        self.assert_eq(tp.Float('double'), tp.Float('double'))
+        self.assert_neq(tp.Float('double'), tp.Float('float'))
 
     def mkTArray(self, size, signed=False):
         size = (ctree.mkIntegerConstant(None, size, signed) if size is not None
-                else expr.mkLit(None, 'lit', TInt(32, False)))
-        return TArray(TInt(32, False), size)
+                else expr.mkLit(None, 'lit', tp.Int(32, False)))
+        return tp.Array(tp.Int(32, False), size)
 
     def test_TArray(self):
         # Arrays of constant size need the sizes be equal to be equal.
@@ -193,92 +193,92 @@ def neq_array_testcase(): return array_testcase(self.assert_neq)
             b.const = True
 
         # Pointers are not equivalent to arrays
-        self.assert_neq(self.mkTArray(4), TPtr(TInt(32, False)))
+        self.assert_neq(self.mkTArray(4), tp.Ptr(tp.Int(32, False)))
 
     def test_TPtr(self):
-        self.assert_eq(TPtr(Typ1()), TPtr(Typ1()))
-        self.assert_neq(TPtr(Typ1()), TPtr(Typ2()))
-        self.assert_neq(TPtr(Typ1(), const=True), TPtr(Typ1()))
-        self.assert_neq(TPtr(Typ1(const=True)), TPtr(Typ1()))
-        self.assert_neq(TPtr(Typ1(), const=True),
-                        TPtr(Typ1(const=True)))
+        self.assert_eq(tp.Ptr(Typ1()), tp.Ptr(Typ1()))
+        self.assert_neq(tp.Ptr(Typ1()), tp.Ptr(Typ2()))
+        self.assert_neq(tp.Ptr(Typ1(), const=True), tp.Ptr(Typ1()))
+        self.assert_neq(tp.Ptr(Typ1(const=True)), tp.Ptr(Typ1()))
+        self.assert_neq(tp.Ptr(Typ1(), const=True),
+                        tp.Ptr(Typ1(const=True)))
 
         # void pointers are not special
-        self.assert_neq(TPtr(Typ1()), TPtr(TVoid()))
+        self.assert_neq(tp.Ptr(Typ1()), tp.Ptr(tp.Void()))
 
     def test_TVector(self):
-        v1 = TVector(Typ1())
+        v1 = tp.Vector(Typ1())
         self.assert_eq(v1, v1.clone())
         v2 = v1.clone()
         v2.const = True
         self.assert_neq(v1, v2)
-        self.assert_neq(v1, TVector(Typ1()))
+        self.assert_neq(v1, tp.Vector(Typ1()))
 
     def test_TTrait(self):
         tr1 = traits.Trait(None, 't1', set(), {}, {}, {}, {}, {}, {}, {})
         tr2 = traits.Trait(None, 't2', set(), {}, {}, {}, {}, {}, {}, {})
 
-        self.assert_eq(TTrait(tr1), TTrait(tr1))
-        self.assert_neq(TTrait(tr1), TTrait(tr2))
+        self.assert_eq(tp.Trait(tr1), tp.Trait(tr1))
+        self.assert_neq(tp.Trait(tr1), tp.Trait(tr2))
 
     def test_TTraitList(self):
-        self.assert_eq(TTraitList('t1'), TTraitList('t1'))
-        self.assert_neq(TTraitList('t1'), TTraitList('t2'))
+        self.assert_eq(tp.TraitList('t1'), tp.TraitList('t1'))
+        self.assert_neq(tp.TraitList('t1'), tp.TraitList('t2'))
 
 
     def test_TStruct(self):
         members = {'a': Typ1()}
-        t1 = TStruct(members, label="a_struct")
-        t2 = TStruct(members)
+        t1 = tp.Struct(members, label="a_struct")
+        t2 = tp.Struct(members)
 
-        self.assert_eq(t1, TStruct(members, label="a_struct"))
+        self.assert_eq(t1, tp.Struct(members, label="a_struct"))
         self.assert_neq(t1, t2)
         self.assert_eq(t2, t2.clone())
-        self.assert_neq(t2, TStruct(members))
+        self.assert_neq(t2, tp.Struct(members))
 
     def test_TExternStruct(self):
-        self.assert_eq(TExternStruct({}, 0), TExternStruct({}, 0))
-        self.assert_eq(TExternStruct({}, "str"), TExternStruct({}, "str"))
-        self.assert_neq(TExternStruct({}, 0), TExternStruct({}, "str"))
+        self.assert_eq(tp.ExternStruct({}, 0), tp.ExternStruct({}, 0))
+        self.assert_eq(tp.ExternStruct({}, "str"), tp.ExternStruct({}, "str"))
+        self.assert_neq(tp.ExternStruct({}, 0), tp.ExternStruct({}, "str"))
 
     def test_TFunction(self):
-        self.assert_eq(TFunction((), TVoid()), TFunction((), TVoid()))
-        self.assert_neq(TFunction((Typ1(),), TVoid()), TFunction((), TVoid()))
-
-        self.assert_eq(TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2())),
-                       TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2())))
-        self.assert_neq(TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ1())),
-                        TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2())))
-        self.assert_neq(TFunction((Typ2(), TPtr(TVoid())), TPtr(Typ2())),
-                        TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2())))
-        self.assert_neq(TFunction((TPtr(TVoid()), Typ1()), TPtr(Typ2())),
-                        TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2())))
+        self.assert_eq(tp.Function((), tp.Void()), tp.Function((), tp.Void()))
+        self.assert_neq(tp.Function((Typ1(),), tp.Void()), tp.Function((), tp.Void()))
+
+        self.assert_eq(tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())),
+                       tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())))
+        self.assert_neq(tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ1())),
+                        tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())))
+        self.assert_neq(tp.Function((Typ2(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())),
+                        tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())))
+        self.assert_neq(tp.Function((tp.Ptr(tp.Void()), Typ1()), tp.Ptr(Typ2())),
+                        tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())))
 
         # Direct constness doesn't matter
-        self.assert_eq(TFunction((Typ1(True), TPtr(TVoid(), True)),
-                                 TPtr(Typ2(), True)),
-                       TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2())))
+        self.assert_eq(tp.Function((Typ1(True), tp.Ptr(tp.Void(), True)),
+                                 tp.Ptr(Typ2(), True)),
+                       tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())))
 
         # Constness behind indirection does
-        self.assert_neq(TFunction((Typ1(), TPtr(TVoid(True))), TPtr(Typ2())),
-                        TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2())))
-        self.assert_neq(TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2(True))),
-                        TFunction((Typ1(), TPtr(TVoid())), TPtr(Typ2())))
+        self.assert_neq(tp.Function((Typ1(), tp.Ptr(tp.Void(True))), tp.Ptr(Typ2())),
+                        tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())))
+        self.assert_neq(tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2(True))),
+                        tp.Function((Typ1(), tp.Ptr(tp.Void())), tp.Ptr(Typ2())))
 
         # Variadicity matters
-        self.assert_eq(TFunction((), TVoid(), varargs=True),
-                       TFunction((), TVoid(), varargs=True))
-        self.assert_neq(TFunction((), TVoid()),
-                        TFunction((), TVoid(), varargs=True))
+        self.assert_eq(tp.Function((), tp.Void(), varargs=True),
+                       tp.Function((), tp.Void(), varargs=True))
+        self.assert_neq(tp.Function((), tp.Void()),
+                        tp.Function((), tp.Void(), varargs=True))
 
     def test_THook(self):
-        self.assert_eq(THook(()), THook(()))
-        self.assert_neq(THook(()), THook((Typ1(),)))
+        self.assert_eq(tp.Hook(()), tp.Hook(()))
+        self.assert_neq(tp.Hook(()), tp.Hook((Typ1(),)))
 
-        self.assert_eq(THook((Typ1(), Typ2())), THook((Typ1(), Typ2())))
+        self.assert_eq(tp.Hook((Typ1(), Typ2())), tp.Hook((Typ1(), Typ2())))
 
         # Order matters
-        self.assert_neq(THook((Typ1(), Typ2())), THook((Typ2(), Typ1())))
+        self.assert_neq(tp.Hook((Typ1(), Typ2())), tp.Hook((Typ2(), Typ1())))
 
         # Direct constness matters (for now; might change with tuple types)
-        self.assert_neq(THook((Typ1(True), Typ2())), THook((Typ1(), Typ2())))
+        self.assert_neq(tp.Hook((Typ1(True), Typ2())), tp.Hook((Typ1(), Typ2())))
diff --git a/py/dml/warnings.py b/py/dml/warnings.py
new file mode 100644
index 000000000..57dce83b9
--- /dev/null
+++ b/py/dml/warnings.py
@@ -0,0 +1,433 @@
+# © 2021 Intel Corporation
+# SPDX-License-Identifier: MPL-2.0
+
+from .logging import DMLWarning, binary_dump, dollar, SimpleSite
+
+class NOVER(DMLWarning):
+    """
+    A DML file must start with a version statement, such as `dml 1.4;`
+    """
+    fmt = "file has no version tag, assuming version 1.2"
+
+class SHALL(DMLWarning):
+    """
+    The result of the shift operation will always be zero.
+    (This warning is disabled by default.)
+    """
+    fmt = "shifting away all data\n%s"
+    def __init__(self, node, lh, rh):
+        DMLWarning.__init__(self, node, binary_dump(lh, rh))
+
+class NDOC(DMLWarning):
+    """
+    No documentation string was specified for the attribute.
+    (This warning is disabled by default.)
+    """
+    fmt = "no documentation for '%s'"
+    def __init__(self, node, member):
+        DMLWarning.__init__(self, node, member)
+
+class NSHORTDESC(DMLWarning):
+    """
+    No short description string was specified using the 'desc' parameter.
+    (This warning is disabled by default.)
+    """
+    fmt = "no 'desc' parameter specified for device"
+    def __init__(self, node):
+        DMLWarning.__init__(self, node)
+
+class NDOCRA(DMLWarning):
+    """
+    No documentation string was specified for a _required_ attribute.
+    """
+    fmt = "no documentation for required attribute '%s'"
+    def __init__(self, node, member):
+        DMLWarning.__init__(self, node, member)
+
+class NEGOFFS(DMLWarning):
+    """
+    A negative integer expression is given as a register offset.
+    Register offsets are unsigned 64-bit numbers, which means that
+    a negative offset expression translates to a very large offset.
+    """
+    fmt = "negative register offset: %d"
+
+class UNUSED(DMLWarning):
+    """
+    The object is not referenced anywhere.
+    (This warning is disabled by default.; it typically causes many false
+    warnings.)
+    """
+    fmt = "unused: %s"
+    def __init__(self, obj):
+        DMLWarning.__init__(self, obj, obj.identity())
+
+class UNUSEDDEFAULT(DMLWarning):
+    """
+    The object is not referenced anywhere but it matches a name of an
+    object automatically referenced in another scope. This is the same
+    as WUNUSED but only for known common errors and it will never be
+    emitted if WUNUSED is enabled.
+    """
+    fmt = "unused: %s methods are not called automatically for %s objects in %s"
+    def __init__(self, obj):
+        DMLWarning.__init__(self, obj, obj.name, obj.parent.objtype,
+                            obj.identity())
+
+class UNUSED_DML12(DMLWarning):
+    """A DML 1.4 file contains a method implementation that would override
+    a library method in DML 1.2, but which is not part of the DML 1.4
+    library, because some methods have been renamed. For instance,
+    implementing `read_access` in a register makes no sense
+    in DML 1.4, because the method has been renamed to
+    `read_register`.
+
+    If a DML 1.4 file contains common code that also is imported from
+    DML 1.2 devices, then it may need to implement methods like
+    `read_access` to get the right callbacks when compiled
+    for DML 1.2. Such implementations can be placed inside `#if
+    (dml_1_2) { }` blocks to avoid this warning.
+    """
+    fmt = ("unused implementation of DML 1.2 method %s;"
+           + " enclose in #if (dml_1_2) ?")
+    def __init__(self, obj):
+        DMLWarning.__init__(self, obj, obj.name)
+
+class DUPEVENT(DMLWarning):
+    """
+    Two or more events will be checkpointed using the same name, which
+    means that the checkpoint cannot be safely read back.
+    """
+    fmt = "duplicate event checkpoint names: %s"
+    def __init__(self, site, objlist):
+        DMLWarning.__init__(self, site,
+                            ", ".join(dollar(self.site) + o.logname()
+                                      for o in objlist))
+
+class SIZEOFTYPE(DMLWarning):
+    """
+    The 'sizeof' operator is used on a type name, but expects an
+    expression. Use the 'sizeoftype' operator for types.
+    """
+    fmt = "sizeof on a type is not legal, use sizeoftype instead"
+
+class DEPRECATED(DMLWarning):
+    """
+    This part of the language is deprecated, usually because the
+    underlying support in Simics is deprecated.
+    """
+    fmt = "deprecation: %s"
+
+class EXPERIMENTAL(DMLWarning):
+    """
+    This part of the language is experimental, and not yet officially
+    supported. Code relying on the feature may break without notice in
+    future releases.
+    """
+    fmt = "Use of unsupported feature: %s"
+    def preprocess(self):
+        return super(EXPERIMENTAL, self).preprocess()
+
+class EXPERIMENTAL_UNMAPPED(EXPERIMENTAL):
+    __doc__ = EXPERIMENTAL.__doc__
+
+class CONFIDENTIAL(DMLWarning):
+    """
+    The object's name/qname is used as part of an expression in a
+    context other than the log statement, which could potentially lead
+    to the leak of confidential information.
+    """
+    fmt = "potential leak of confidential information"
+    def __init__(self, site):
+        DMLWarning.__init__(self, site)
+
+# Not used (see ctree.py class CopyData), not documented.
+# class WASSIGN(DMLWarning):
+#     def __init__(self, site):
+#         DMLWarning.__init__(self, site, "cannot perform assignment")
+
+class OLDAST(DMLWarning):
+    """
+    A precompiled DML file has an old time-stamp. This may happen if a
+    user accidentally edits a DML file from the standard library. A
+    safe way to suppress the warning is to remove the outdated
+    `.dmlast` file.
+    """
+    fmt = "Outdated AST file: %s"
+    def __init__(self, dmlfile):
+        DMLWarning.__init__(self, SimpleSite(dmlfile + ":0"),
+                            dmlfile + "ast")
+
+class WRNSTMT(DMLWarning):
+    """
+    The source code contained a statement "`warning;`", which
+    causes a warning to be printed.
+    """
+    fmt = "%s"
+
+    # This message should be removed, SIMICS-9886
+
+class REF(DMLWarning):
+    """An unused parameter refers to an object that has not been declared.
+
+    This warning message will be replaced with a hard error in future
+    major versions of Simics.
+    """
+    instances = []
+    fmt = "unused parameter %s contains %s"
+
+    def __init__(self, site, param, eref):
+        # message formatting hack is based on this assumption
+        assert eref.msg.startswith('reference to unknown object ')
+        DMLWarning.__init__(self, site, param, eref.msg)
+
+class TEMPLATEIS(DMLWarning):
+    """In a template with methods marked `shared`, it is recommended that
+    other templates are instantiated on the same line"""
+    fmt = ("prefer 'is' statement outside template braces,"
+           + " 'template ... is (x, y) {'")
+
+class NOIS(DMLWarning):
+    """Many standard method overrides will only be recognized if a
+    template named like the method is also instantiated. For instance,
+    the method `set` in a field has no effect unless the
+    `set` template is instantiated.
+    """
+    def __init__(self, site, name):
+        DMLWarning.__init__(self, site, name, name)
+    fmt = ("implementation of %s() without 'is %s' is ignored"
+           + " by the standard library")
+
+class THROWS_DML12(DMLWarning):
+    """In DML 1.2, a method is by default permitted to throw an exception,
+    while in DML 1.4, an annotation `throws` is required for that.
+    So, if a method without annotations is ported to DML 1.4, it will
+    no longer permit exceptions. If such method is overridden by
+    a DML 1.2 file, then a non-throwing method is overridden by a potentially
+    throwing method, which is normally a type error. However, this particular
+    case is reduced to this warning. If an exception is uncaught in the
+    override, then this will automatically be caught in runtime and
+    an error message will be printed.
+    """
+    fmt = ("overriding non-throwing DML 1.4 method"
+           + " with throwing DML 1.2 method")
+    def __init__(self, site, other_site=None):
+        DMLWarning.__init__(self, site)
+        self.other_site = other_site
+    def log(self):
+        DMLWarning.log(self)
+        self.print_site_message(
+            self.other_site,
+            "original non-throwing declaration")
+
+class NEGCONSTCOMP(DMLWarning):
+    """DML uses a special method when comparing an unsigned and signed integer,
+    meaning that comparing a negative constant to an unsigned integer always
+    has the same result, which is usually not the intended behaviour."""
+    def __init__(self, site, expr, ty):
+        DMLWarning.__init__(self, site)
+        self.expr = expr
+        self.ty = ty
+    fmt = ("Comparing negative constant to unsigned integer has a constant "
+           + "result")
+    def log(self):
+        DMLWarning.log(self)
+        self.print_site_message(
+            self.expr.site, "Consider 'cast(%s, %s)'" % (self.expr, self.ty))
+
+class ASTRUNC(DMLWarning):
+    """The source of an assignment is a constant value that can't fit in the
+    type of the target, and is thus truncated. This warning can be silenced by
+    explicitly casting the expression to the target type.
+    """
+    fmt = ("The assignment source is a constant value which does not fit "
+           + "the assign target of type '%s', and will thus be truncated")
+
+class REDUNDANTLEVEL(DMLWarning):
+    """`X then Y` log level syntax has no effect when the
+    first and subsequent levels are the same.
+    """
+    def __init__(self, site):
+        DMLWarning.__init__(self, site)
+    fmt = ("'X then Y' log level has no effect when the levels are the same")
+
+class TTYPEC(DMLWarning):
+    """
+    The delay value provided to an `after` call is subject to
+    implicit type conversion which may be unexpected for certain types.
+    To silence this warning, explicitly cast the delay value to the expected
+    type.
+    """
+    fmt = ("the time value of type '%s' is implicitly converted "
+           + "to the type '%s' expected by the specified time unit '%s'.")
+
+class PCAST(DMLWarning):
+    """
+    A pointer is cast to a base type which has incompatible representation
+    compared to the original. Accessing the pointed-to object via the new
+    pointer type will almost certainly constitute undefined behavior.
+
+    This warning is extremely limited in scope: don't rely on it to catch every
+    bad pointer cast.
+
+    To silence this warning, first cast the pointer to `void *`, then cast it
+    to the desired type.
+    """
+    fmt = ("very suspect pointer-to-pointer cast: the new base type has "
+           + "incompatible representation. This could lead to your code "
+           + "getting mangled by the C compiler, with unpredictable results.\n"
+           + "old base type: %s\n"
+           + "new base type: %s%s")
+    def __init__(self, site, old, new, maybe_intended):
+        suggestion = ('\nperhaps you meant the new base type to be '
+                      + maybe_intended.describe()
+                      if maybe_intended else '')
+        DMLWarning.__init__(self, site, old, new, suggestion)
+
+class LOGMIXUP(DMLWarning):
+    """
+
+    A specified log level of a `log` looks as though you meant to specify the
+    log groups instead, and/or vice versa. For example:
+    ```
+    // Log group used as log level, when the intention is instead to
+    // specify log groups and implicitly use log level 1
+    log spec_viol, some_log_group: ...;
+
+    // Log groups and log level mistakenly specified in reverse order
+    log info, (some_log_group | another_log_group), 2: ...;
+
+    // Log level used as log groups, when the intention is instead to
+    // specify the subsequent log level
+    log info, 2, 3: ...;
+    ```
+    If you want to specify log groups, make sure to (explicitly) specify the
+    log level beforehand. If you want to specify the subsequent log level, use
+    `then` syntax.
+    ```
+    log spec_viol, 1, some_log_group: ...;
+    log info, 2, (some_log_group | another_log_group): ...;
+    log info, 2 then 3: ...;
+    ```
+
+    This warning is only enabled by default with Simics API version 7 or above
+    (due to the breaking change `enable_WLOGMIXUP`.)
+    """
+    fmt = ("log statement with likely misspecified log level(s) and log "
+           + "groups: %s")
+    def __init__(self, site, kind, level, later_level, groups):
+        suggestions = []
+        from .codegen import probable_loggroups_specification, \
+            probable_loglevel_specification
+        # There are three main scenarios for which we want to offer suggestions
+        # -- those covered in the docstring. All other scenarios either involve
+        # subsequent log levels -- at which point it's too difficult to guess
+        # what the user actually wanted to do -- or have no obvious fix that is
+        # not blatantly incorrect.
+        if probable_loggroups_specification(level):
+            if (not later_level
+                and not (groups.constant and not (1 <= groups.value <= 4))):
+                # Scenario 2: 'log info, 2, some_log_groups: ...;'
+                details = ("the specified log level and log groups look as "
+                           + "though they are meant to be reversed.")
+                suggestions.append(f"log {kind}, {groups}, {level}: ...;")
+            else:
+                details = ("log group(s) and/or constant 0 are used as log "
+                           + "level.")
+                if not later_level and groups.constant and groups.value == 0:
+                    # Scenario 1: 'log info, some_log_groups: ...;'
+                    suggestions.append(f"log {kind}, 1, {level}: ...;")
+        elif later_level and probable_loggroups_specification(later_level):
+            details = ("log group(s) and/or constant 0 are used as subsequent "
+                       + "log level.")
+        else:
+            assert probable_loglevel_specification(groups)
+            details = "non-zero integer constant used as log groups."
+            if not later_level:
+                if site is None or site.dml_version != (1, 2):
+                    # Scenario 3: 'log info, 2, 3: ...;'
+                    suggestions.append(
+                        f"log {kind}, {level} then {groups}: ...;")
+                if (not probable_loglevel_specification(level)
+                    and not (groups.constant and groups.value == 5)):
+                    # Scenario 2: 'log info, nonconstant, 3: ...;'
+                    suggestions.append(f"log {kind}, {groups}, {level}: ...;")
+
+        if suggestions:
+            details += (" Perhaps you meant%s:\n%s"
+                        % (" one of the below"*(len(suggestions) > 1),
+                           '\n'.join(suggestions)))
+
+        DMLWarning.__init__(self, site, details)
+
+class IMMAFTER(DMLWarning):
+    """
+    An immediate `after` statement was specified where some argument to the
+    callback is a pointer to some stack-allocated data — i.e. a pointer
+    to data stored within a local variable. That data is guaranteed to be
+    invalid by the point the callback is called, which presents an enormous
+    security risk!
+    """
+    version = "1.4"
+    fmt = ("***INCREDIBLY UNSAFE*** use of immediate 'after' statement: the "
+           + "callback argument '%s' is a pointer to stack-allocated data!")
+
+class HOOKSEND(DMLWarning):
+    """
+    The `send` operation of a hook was called, and some provided message
+    component is a pointer to some stack-allocated data — i.e. a pointer
+    to data stored within a local variable. That data is guaranteed to be
+    invalid by the point the message is sent, which presents an enormous
+    security risk!
+
+    If you must use pointers to stack-allocated data, then `send_now` should
+    be used instead of `send`. If you want the message to be delayed to avoid
+    ordering bugs, create a method which wraps the `send_now` call together
+    with the declarations of the local variable(s) which you need pointers to,
+    and then use immediate after (`after: m(...)`) to delay the call to that
+    method.
+    """
+    version = "1.4"
+    fmt = ("***INCREDIBLY UNSAFE*** use of the 'send' operation of a hook: "
+           + "the message component '%s' is a pointer to stack-allocated "
+           + "data!\n"
+           + "Did you mean to use 'send_now' instead? See the Hook "
+           + "Declarations section in the DML 1.4 reference manual for "
+           + "information about the differences between 'send' and 'send_now'")
+
+class STRAYIS(DMLWarning):
+    """
+    A standalone `is` statement was found that looks like it was instead
+    intended to affect a preceding object declaration rather than the enclosing
+    object/template in which the `is` statement and (sub)object declaration are
+    made.
+
+    This typically happens due to a stray semicolon before the `is`, e.g.:
+    ```
+    field f @ [31:0]; is read_only;
+    ```
+    or
+    ```
+    field f @ [31:0];
+        is read_only;
+    ```
+
+    If done unintentionally, address this warning by making the `is` part of
+    the declared object. If there is indeed a stray semicolon this can
+    typically be accomplished simply by removing it.
+
+    If the standalone `is` statement is intentional, silence this warning
+    by making sure the `is` statement is on a new line separate from the object
+    declaration, and is not indented any deeper than the object declaration is.
+    """
+    fmt = ("suspect standalone 'is': formatting suggests it was meant to "
+           + "affect the %s declared just before it rather than the "
+           + "enclosing object/template. "
+           + "Perhaps you have a stray ';' before the 'is'?")
+
+
+all_warnings = dict(sorted(
+    (o.tag(), o) for o in globals().values()
+    if isinstance(o, type)
+    and issubclass(o, DMLWarning)
+    and o is not DMLWarning))
diff --git a/py/port_dml.py b/py/port_dml.py
index 2312efa15..6c4c4e847 100644
--- a/py/port_dml.py
+++ b/py/port_dml.py
@@ -27,7 +27,8 @@ def find_lexer(self_path):
         path = self_path.parent
     if (path / 'dml').is_dir():
         sys.path.append(str(path))
-        import dml.dmllex14 as _
+        # https://github.com/astral-sh/ruff/issues/25399
+        import dml.dmllex14 as _  # noqa: F401
         return
     raise Exception(
         f'cannot find dmlc in {path}.'
@@ -283,7 +284,7 @@ def test_decode_loc(self):
 
     def test_read_tokens(self):
         find_lexer(Path(__file__))
-        from dml.messages import ESYNTAX
+        import dml.errors as E
 
         with TempFile(b"75 /**/ xyz;") as tf:
             f = SourceFile(tf.name)
@@ -296,7 +297,7 @@ def test_read_tokens(self):
             try:
                 for _ in f.read_tokens(2):
                     pass
-            except ESYNTAX as e:
+            except E.SYNTAX as e:
                 self.assertIn('%s:5:4:' % (tf.name,), str(e))
             else:
                 self.fail('expected ESYNTAX')
diff --git a/run_unit_tests.py b/run_unit_tests.py
index a70355818..6935de52b 100644
--- a/run_unit_tests.py
+++ b/run_unit_tests.py
@@ -8,12 +8,12 @@
     (hostdir, testscript) = sys.argv[1:]
     path = os.path.join(hostdir, "bin", "dml", "python")
     if not os.path.isdir(path):
-        optpar.error('not a directory: %r' % path)
+        sys.exit('error: not a directory: %r' % path)
     sys.path.append(path)
     if not os.path.isfile(testscript):
-        optpar.error('not a file: %r' % testscript)
+        sys.exit('error: not a file: %r' % testscript)
     sys.path.append(os.path.dirname(testscript))
     base, ext = os.path.splitext(os.path.basename(testscript))
     if ext != '.py':
-        optpar.error('file name does end with .py: %r' % testscript)
+        sys.exit('error: file name does end with .py: %r' % testscript)
     unittest.main(module = base, argv = [""])
diff --git a/test/1.2/events/T_after.py b/test/1.2/events/T_after.py
index 424a48846..72cc51d67 100644
--- a/test/1.2/events/T_after.py
+++ b/test/1.2/events/T_after.py
@@ -1,6 +1,9 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import simics
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 obj.alttest = 1
diff --git a/test/1.2/events/T_after_array.py b/test/1.2/events/T_after_array.py
index 184bb281b..522cfa9d6 100644
--- a/test/1.2/events/T_after_array.py
+++ b/test/1.2/events/T_after_array.py
@@ -1,9 +1,12 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 obj.alttest = 1
-SIM_continue(100000)
+simics.SIM_continue(100000)
 stest.expect_true(obj.runtest)
diff --git a/test/1.2/events/T_after_chk_dup.cont.py b/test/1.2/events/T_after_chk_dup.cont.py
index 2492198e8..a91af0afa 100644
--- a/test/1.2/events/T_after_chk_dup.cont.py
+++ b/test/1.2/events/T_after_chk_dup.cont.py
@@ -1,11 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import conf
 
-run_command("peq")
+simics.SIM_run_command("peq")
 print("Running 2 s")
-SIM_continue(2000000)
+simics.SIM_continue(2000000)
 
 stest.expect_true(conf.obj.a_flag)
 stest.expect_true(conf.obj.b_flag)
diff --git a/test/1.2/events/T_after_chk_dup.py b/test/1.2/events/T_after_chk_dup.py
index f3fce40d3..1ec8354d6 100644
--- a/test/1.2/events/T_after_chk_dup.py
+++ b/test/1.2/events/T_after_chk_dup.py
@@ -1,20 +1,26 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from os.path import join
+import simics
+from os.path import join, dirname
+from pathlib import Path
 import subprocess
 from simicsutils.host import batch_suffix
+import testenv
+import conf
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 obj.alttest = 1
 
-SIM_write_configuration_to_file(testname + ".chkp", Sim_Save_Nobundle)
+stem = Path(__file__).stem
+simics.SIM_write_configuration_to_file(stem + ".chkp", simics.Sim_Save_Nobundle)
 
 subprocess.check_call(
     [f'{conf.sim.project}/bin/simics{batch_suffix()}'] +
     ["--batch-mode", "--quiet", "--no-copyright", "--dump-core", "--werror",
      '--project', conf.sim.project,
-     "--module-path", scratchdir,
-     "-e", f'read-configuration {testname + ".chkp"}',
-     join(basedir, "T_"+testname+".cont.py")])
+     "--module-path", testenv.scratchdir(),
+     "-e", f'read-configuration {stem}.chkp',
+     join(dirname(__file__), stem + ".cont.py")])
diff --git a/test/1.2/events/T_after_param.py b/test/1.2/events/T_after_param.py
index cd0f9c160..da38fb53f 100644
--- a/test/1.2/events/T_after_param.py
+++ b/test/1.2/events/T_after_param.py
@@ -1,10 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 obj.alttest = 30
-SIM_continue(100000)
+simics.SIM_continue(100000)
 stest.expect_equal(obj.num, 30)
 stest.expect_equal(obj.p_num, [0, 30])
diff --git a/test/1.2/events/T_describe_event.py b/test/1.2/events/T_describe_event.py
index 487efa31c..287ec2af4 100644
--- a/test/1.2/events/T_describe_event.py
+++ b/test/1.2/events/T_describe_event.py
@@ -1,9 +1,12 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
 obj.post_all = None
diff --git a/test/1.2/events/T_dup.cont.py b/test/1.2/events/T_dup.cont.py
index ee8492ae1..78cda0199 100644
--- a/test/1.2/events/T_dup.cont.py
+++ b/test/1.2/events/T_dup.cont.py
@@ -1,9 +1,11 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import conf
 
-SIM_continue(1000000)
+simics.SIM_continue(1000000)
 
 stest.expect_equal(conf.obj.a_flag, True)
 stest.expect_equal(conf.obj.b_flag, True)
diff --git a/test/1.2/events/T_dup.py b/test/1.2/events/T_dup.py
index 2db51e9aa..03cfbdea0 100644
--- a/test/1.2/events/T_dup.py
+++ b/test/1.2/events/T_dup.py
@@ -1,20 +1,24 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from os.path import join
+import simics
+from os.path import join, dirname
 import subprocess
 from simicsutils.host import batch_suffix
+import testenv
+import conf
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 obj.postall = 1
 
-SIM_write_configuration_to_file("dup.chkp", Sim_Save_Nobundle)
+simics.SIM_write_configuration_to_file("dup.chkp", simics.Sim_Save_Nobundle)
 
 subprocess.check_call(
     [f'{conf.sim.project}/bin/simics{batch_suffix()}'] +
     ["--batch-mode", "--quiet", "--no-copyright", "--dump-core", "--werror",
      '--project', conf.sim.project,
-     "--module-path", scratchdir,
+     "--module-path", testenv.scratchdir(),
      "-e", "read-configuration dup.chkp",
-     join(basedir, "T_dup.cont.py")])
+     join(dirname(__file__), "T_dup.cont.py")])
diff --git a/test/1.2/events/T_event_info.py b/test/1.2/events/T_event_info.py
index 0530f153c..5ce0d7acb 100644
--- a/test/1.2/events/T_event_info.py
+++ b/test/1.2/events/T_event_info.py
@@ -1,14 +1,17 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
 # Just posting user data with an event works.
 obj.post_all = 100
-SIM_continue(1)
+simics.SIM_continue(1)
 stest.expect_equal(obj.a, 100)
 stest.expect_equal(obj.b, [[0, 0], [0, 100]])
 
@@ -16,7 +19,7 @@
 # converted back and forth to an attribute.
 obj.post_all = 100
 cpu.time_queue = list(cpu.time_queue)
-SIM_continue(1)
+simics.SIM_continue(1)
 # 20 + 3 was added to the parameter because of translation via
 # get_event_info() + set_event_info()
 stest.expect_equal(obj.a, 123)
diff --git a/test/1.2/events/T_next.py b/test/1.2/events/T_next.py
index 3f88c98ab..1f597aada 100644
--- a/test/1.2/events/T_next.py
+++ b/test/1.2/events/T_next.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 stest.expect_true(obj.runtest)
diff --git a/test/1.2/events/T_next_time.py b/test/1.2/events/T_next_time.py
index 3f88c98ab..1f597aada 100644
--- a/test/1.2/events/T_next_time.py
+++ b/test/1.2/events/T_next_time.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 stest.expect_true(obj.runtest)
diff --git a/test/1.2/events/T_no_queue.py b/test/1.2/events/T_no_queue.py
index a5a708cf2..a317ecabd 100644
--- a/test/1.2/events/T_no_queue.py
+++ b/test/1.2/events/T_no_queue.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest
+import testenv
+obj = testenv.instantiate()
 
 with stest.expect_log_mgr(obj, "error"):
     obj.after_test = 1
diff --git a/test/1.2/events/T_posted.py b/test/1.2/events/T_posted.py
index 3f88c98ab..1f597aada 100644
--- a/test/1.2/events/T_posted.py
+++ b/test/1.2/events/T_posted.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 stest.expect_true(obj.runtest)
diff --git a/test/1.2/events/T_remove.py b/test/1.2/events/T_remove.py
index 35b3a48d8..ab11477d0 100644
--- a/test/1.2/events/T_remove.py
+++ b/test/1.2/events/T_remove.py
@@ -1,16 +1,19 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
 # event happens if you don't remove it. Should be caught by other test.
 obj.last_ev = -1
 obj.last_destroy = 0
 obj.post = [5, 42]
-SIM_continue(5)
+simics.SIM_continue(5)
 assert obj.last_ev == 42
 assert obj.last_destroy == 0
 
@@ -18,19 +21,19 @@
 obj.last_ev = 0
 obj.last_destroy = 0
 obj.post = [5, 42]
-SIM_continue(4)
+simics.SIM_continue(4)
 obj.remove = 42
 stest.expect_equal(obj.last_destroy, 42)
-SIM_continue(1)
+simics.SIM_continue(1)
 stest.expect_equal(obj.last_ev, 0)
 
 # event happens if you remove it with mismatching event data.
 obj.last_ev = 0
 obj.last_destroy = 0
 obj.post = [5, 42]
-SIM_continue(4)
+simics.SIM_continue(4)
 obj.remove = 43
-SIM_continue(1)
+simics.SIM_continue(1)
 stest.expect_equal(obj.last_destroy, 0)
 stest.expect_equal(obj.last_ev, 42)
 
@@ -48,7 +51,7 @@ def set_pattr_array(attrname, valarray):
 set_pattr_array('last_ev', [[-1, -1], [-1, -1]])
 set_pattr_array('last_destroy', [[0, 0], [0, 0]])
 set_pattr_array('post', [[[5, 42], [5, 42]], [[5, 42], [5, 42]]])
-SIM_continue(5)
+simics.SIM_continue(5)
 stest.expect_equal(get_pattr_array('last_ev'), [[42, 42], [42, 42]])
 stest.expect_equal(get_pattr_array('last_destroy'), [[0, 0], [0, 0]])
 
@@ -56,19 +59,19 @@ def set_pattr_array(attrname, valarray):
 set_pattr_array('last_ev', [[0, 0], [0, 0]])
 set_pattr_array('last_destroy', [[0, 0], [0, 0]])
 set_pattr_array('post', [[[5, 42], [5, 42]], [[5, 42], [5, 42]]])
-SIM_continue(4)
+simics.SIM_continue(4)
 set_pattr_array('remove', [[42, 42], [42, 42]])
 stest.expect_equal(get_pattr_array('last_destroy'), [[42, 42], [42, 42]])
-SIM_continue(1)
+simics.SIM_continue(1)
 set_pattr_array('last_ev', [[0, 0], [0, 0]])
 
 # event happens if you remove it with mismatching event data.
 set_pattr_array('last_ev', [[0, 0], [0, 0]])
 set_pattr_array('last_destroy', [[0, 0], [0, 0]])
 set_pattr_array('post', [[[5, 42], [5, 42]], [[5, 42], [5, 42]]])
-SIM_continue(4)
+simics.SIM_continue(4)
 set_pattr_array('remove', [[43, 43], [43, 43]])
-SIM_continue(1)
+simics.SIM_continue(1)
 stest.expect_equal(get_pattr_array('last_ev'), [[42, 42], [42, 42]])
 stest.expect_equal(get_pattr_array('last_destroy'), [[0, 0], [0, 0]])
 
diff --git a/test/1.2/events/T_stacked.py b/test/1.2/events/T_stacked.py
index c8ba718e2..b794d31bc 100644
--- a/test/1.2/events/T_stacked.py
+++ b/test/1.2/events/T_stacked.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import simics
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 obj.post = None
-SIM_continue(1)
+simics.SIM_continue(1)
diff --git a/test/1.2/internal/T_int_register.py b/test/1.2/internal/T_int_register.py
index 658c2848c..fee4a33ab 100644
--- a/test/1.2/internal/T_int_register.py
+++ b/test/1.2/internal/T_int_register.py
@@ -1,6 +1,8 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import testenv
+obj = testenv.instantiate()
 RN = 17
 RS = '_r0x0'                    # anonymized name
 
diff --git a/test/1.2/misc/T_destroy.py b/test/1.2/misc/T_destroy.py
index 596c9c847..99fd76e8e 100644
--- a/test/1.2/misc/T_destroy.py
+++ b/test/1.2/misc/T_destroy.py
@@ -4,11 +4,14 @@
 # We need to create a second object, since run-test.py expects obj to
 # remain after executing this script.
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import simics
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 
-o = SIM_create_object("test", "o", [["queue", cpu]])
+o = simics.SIM_create_object("test", "o", [["queue", cpu]])
 print("Deleting")
-SIM_delete_object(o)
+simics.SIM_delete_object(o)
 print("Done")
-SIM_continue(10000000)
+simics.SIM_continue(10000000)
 print("Events not triggered")
diff --git a/test/1.2/misc/T_notify_state.py b/test/1.2/misc/T_notify_state.py
index 03c37a485..dcc10277f 100644
--- a/test/1.2/misc/T_notify_state.py
+++ b/test/1.2/misc/T_notify_state.py
@@ -1,13 +1,16 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
 # Every time we access the counter, it will increase by 1
 
 stest.expect_equal(obj.count, 0)
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
 stest.expect_equal(obj.count, 1)
@@ -24,7 +27,7 @@
 
 stest.expect_equal(obj.count, 7)
 
-SIM_continue(100000)
+simics.SIM_continue(100000)
 
 stest.expect_equal(obj.count, 9)
 
diff --git a/test/1.2/misc/T_register_view_no_xml.py b/test/1.2/misc/T_register_view_no_xml.py
index e73d3e9e7..28efd5064 100644
--- a/test/1.2/misc/T_register_view_no_xml.py
+++ b/test/1.2/misc/T_register_view_no_xml.py
@@ -4,6 +4,8 @@
 import stest
 
 from simics import SIM_get_port_interface
+import testenv
+obj = testenv.instantiate()
 
 b = SIM_get_port_interface(obj, 'register_view', 'b')
 stest.expect_equal(b.description(), "")
diff --git a/test/1.2/misc/T_unimpl_templates.py b/test/1.2/misc/T_unimpl_templates.py
index 721d1c3da..1a1123066 100644
--- a/test/1.2/misc/T_unimpl_templates.py
+++ b/test/1.2/misc/T_unimpl_templates.py
@@ -1,8 +1,11 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import dev_util as du
 import stest
+import testenv
+obj = testenv.instantiate()
 
 expect = '''
 Write to unimplemented register regs.r1 (0x10) (value written = 0x00001267).
@@ -124,7 +127,7 @@ def collect(arg, obj, logtype, msg):
     global log_messages
     log_messages.append(msg)
 
-SIM_hap_add_callback("Core_Log_Message", collect, 0)
+simics.SIM_hap_add_callback("Core_Log_Message", collect, 0)
 
 def write(reg, val):
     reg.write(val)
@@ -143,7 +146,7 @@ def test(obj, access):
         reg = du.Register_LE(obj.bank.with_fields, offset)
         access(reg)
 
-o = SIM_create_object("test", "o", [])
+o = simics.SIM_create_object("test", "o", [])
 n = 4711
 for l in range(1, 5):
     o.bank.regs.log_level = l
diff --git a/test/1.2/misc/T_utility_14_api.py b/test/1.2/misc/T_utility_14_api.py
index a393a84ac..e01ee3e10 100644
--- a/test/1.2/misc/T_utility_14_api.py
+++ b/test/1.2/misc/T_utility_14_api.py
@@ -4,7 +4,8 @@
 import stest
 import dev_util
 import sim_commands
-import contextlib
+import testenv
+obj = testenv.instantiate()
 
 [read_write,
  ignore_write,
diff --git a/test/1.2/misc/register_view.py b/test/1.2/misc/register_view.py
index 02266f640..c794f56dc 100644
--- a/test/1.2/misc/register_view.py
+++ b/test/1.2/misc/register_view.py
@@ -2,7 +2,9 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import test_register_view
-from stest import expect_equal, expect_true, expect_log_mgr
+from stest import expect_equal, expect_log_mgr
+import testenv
+obj = testenv.instantiate()
 
 test_register_view.test(obj)
 
diff --git a/test/1.2/misc/register_view_bitorder_be.py b/test/1.2/misc/register_view_bitorder_be.py
index d88d227f4..1b67e188c 100644
--- a/test/1.2/misc/register_view_bitorder_be.py
+++ b/test/1.2/misc/register_view_bitorder_be.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 from stest import expect_true
+import testenv
+obj = testenv.instantiate()
 
-b = SIM_get_port_interface(obj, 'register_view', 'b')
+b = simics.SIM_get_port_interface(obj, 'register_view', 'b')
 expect_true(b.big_endian_bitorder())
diff --git a/test/1.2/misc/register_view_bitorder_le.py b/test/1.2/misc/register_view_bitorder_le.py
index 99e4ff604..c3f3400f8 100644
--- a/test/1.2/misc/register_view_bitorder_le.py
+++ b/test/1.2/misc/register_view_bitorder_le.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 from stest import expect_false
+import testenv
+obj = testenv.instantiate()
 
-b = SIM_get_port_interface(obj, 'register_view', 'b')
+b = simics.SIM_get_port_interface(obj, 'register_view', 'b')
 expect_false(b.big_endian_bitorder())
diff --git a/test/1.2/misc/register_view_descriptions.py b/test/1.2/misc/register_view_descriptions.py
index 1691a7761..f04cf3dc3 100644
--- a/test/1.2/misc/register_view_descriptions.py
+++ b/test/1.2/misc/register_view_descriptions.py
@@ -2,5 +2,7 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import test_register_view_descriptions
+import testenv
+obj = testenv.instantiate()
 
 test_register_view_descriptions.test(obj)
diff --git a/test/1.2/misc/register_view_fields.py b/test/1.2/misc/register_view_fields.py
index 8ab40afff..c7d4e7eef 100644
--- a/test/1.2/misc/register_view_fields.py
+++ b/test/1.2/misc/register_view_fields.py
@@ -1,11 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from simics import *
+import simics
 from stest import expect_equal
+import testenv
+obj = testenv.instantiate()
 
 def test(obj):
-    b = SIM_get_port_interface(obj, 'register_view', 'b')
+    b = simics.SIM_get_port_interface(obj, 'register_view', 'b')
 
     expect_equal(b.register_info(0)[4], [['all', '', 0, 31]])
     expect_equal(b.register_info(1)[4], [['g', '7', 7, 7],
diff --git a/test/1.2/misc/register_view_inquiry.py b/test/1.2/misc/register_view_inquiry.py
index e9edd7bcf..f684037d1 100644
--- a/test/1.2/misc/register_view_inquiry.py
+++ b/test/1.2/misc/register_view_inquiry.py
@@ -2,5 +2,7 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import test_register_view_inquiry
+import testenv
+obj = testenv.instantiate()
 
 test_register_view_inquiry.test(obj)
diff --git a/test/1.2/operators/T_interface_avail.py b/test/1.2/operators/T_interface_avail.py
index c92a42b0e..535061f4f 100644
--- a/test/1.2/operators/T_interface_avail.py
+++ b/test/1.2/operators/T_interface_avail.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-cpu = SIM_create_object("clock", "cpu", [["freq_mhz", 1]])
+import simics
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "cpu", [["freq_mhz", 1]])
 
 failures = 0
 
@@ -33,5 +36,5 @@
     failures += 1
 
 if failures:
-    SIM_quit(1)
+    simics.SIM_quit(1)
 
diff --git a/test/1.2/registers/T_bankarray.py b/test/1.2/registers/T_bankarray.py
index cb18231b4..7ec4a3294 100644
--- a/test/1.2/registers/T_bankarray.py
+++ b/test/1.2/registers/T_bankarray.py
@@ -1,11 +1,15 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import dev_util
 from stest import expect_equal
+import conf
+import testenv
+obj = testenv.instantiate()
 
-mem = SIM_create_object("memory-space", "mem",
-                        [["map", 
+mem = simics.SIM_create_object("memory-space", "mem",
+                        [["map",
                           [[0x0,   [obj, "regs[0]"], 0, 0, 0x100],
                            [0x100, [obj, "regs[1]"], 0, 0, 0x100],
                            [0x200, obj, 3, 0, 0x100],
@@ -25,7 +29,6 @@ def wr(offset, value):
 expect_equal(rd(0x200), 0xbadc0ffe)
 expect_equal(rd(0x300), 0xdeadbeef)
 
-obj = conf.obj
 obj.regs_ra = [[[0x10, 0x14], [0x18, 0x1c]], [[0x110, 0x114], [0x118, 0x11c]]]
 obj.regs_g_gr = [[0x40, 0x54], [0x140, 0x154]]
 obj.regs_g_gra = [[[[0x44, 0x48], [0x4c, 0x50]],
diff --git a/test/1.2/registers/T_be_slice.py b/test/1.2/registers/T_be_slice.py
index 794850c5d..167067449 100644
--- a/test/1.2/registers/T_be_slice.py
+++ b/test/1.2/registers/T_be_slice.py
@@ -1,10 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 from functools import reduce
 import operator
 import stest, dev_util
-run_command("log-level 4")
+import testenv
+obj = testenv.instantiate()
+simics.SIM_run_command("log-level 4")
 
 def check(bank, offset, size):
     data = reduce(operator.ior, (
diff --git a/test/1.2/registers/T_get_exc.py b/test/1.2/registers/T_get_exc.py
index c1f779d84..9cd51093c 100644
--- a/test/1.2/registers/T_get_exc.py
+++ b/test/1.2/registers/T_get_exc.py
@@ -1,9 +1,12 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
+import testenv
+obj = testenv.instantiate()
 try:
     print(obj.b_r)
     print("attribute get didn't fail as it should have")
-    SIM_quit(1)
+    simics.SIM_quit(1)
 except Exception as e:
     print(e)
diff --git a/test/1.2/registers/T_inquiry.py b/test/1.2/registers/T_inquiry.py
index 84a283874..f83bbe88a 100644
--- a/test/1.2/registers/T_inquiry.py
+++ b/test/1.2/registers/T_inquiry.py
@@ -1,13 +1,14 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-import random
-
-from stest import *
+import simics
+import stest
 import dev_util as du
 from functools import reduce
+import testenv
+obj = testenv.instantiate()
 
-SIM_run_command("log-level 4")
+simics.SIM_run_command("log-level 4")
 
 def reset_dev(d, r_val):
     d.b_r = r_val
@@ -37,46 +38,46 @@ def expected_int(bytes, offs):
 
         reset_dev(obj, 0)
         r.write(val)
-        expect_equal(obj.write_val, val << offs * 8)
-        expect_equal(obj.before_write_called, True)
-        expect_equal(obj.after_write_called, True)
-        expect_equal(obj.before_read_called, False)
-        expect_equal(obj.after_read_called, False)
-        expect_equal(obj.before_set_called, False)
-        expect_equal(obj.after_set_called, False)
+        stest.expect_equal(obj.write_val, val << offs * 8)
+        stest.expect_equal(obj.before_write_called, True)
+        stest.expect_equal(obj.after_write_called, True)
+        stest.expect_equal(obj.before_read_called, False)
+        stest.expect_equal(obj.after_read_called, False)
+        stest.expect_equal(obj.before_set_called, False)
+        stest.expect_equal(obj.after_set_called, False)
 
         reset_dev(obj, 0)
         r_inq.write(val)
-        expect_equal(obj.b_r, val << offs * 8)
-        expect_equal(obj.write_val, 0)
-        expect_equal(obj.before_write_called, False)
-        expect_equal(obj.after_write_called, False)
-        expect_equal(obj.before_read_called, False)
-        expect_equal(obj.after_read_called, False)
-        expect_equal(obj.before_set_called, True)
-        expect_equal(obj.after_set_called, True)
+        stest.expect_equal(obj.b_r, val << offs * 8)
+        stest.expect_equal(obj.write_val, 0)
+        stest.expect_equal(obj.before_write_called, False)
+        stest.expect_equal(obj.after_write_called, False)
+        stest.expect_equal(obj.before_read_called, False)
+        stest.expect_equal(obj.after_read_called, False)
+        stest.expect_equal(obj.before_set_called, True)
+        stest.expect_equal(obj.after_set_called, True)
 
         READ_VALUE = (0xdeadbeefbaadc0de >> offs * 8) & ((1 << size * 8) - 1)
         reset_dev(obj, val)
         ret = r.read()
-        expect_equal(ret, READ_VALUE)
-        expect_equal(obj.b_r, val)
-        expect_equal(obj.write_val, 0)
-        expect_equal(obj.before_write_called, False)
-        expect_equal(obj.after_write_called, False)
-        expect_equal(obj.before_read_called, True)
-        expect_equal(obj.after_read_called, True)
-        expect_equal(obj.before_set_called, False)
-        expect_equal(obj.after_set_called, False)
+        stest.expect_equal(ret, READ_VALUE)
+        stest.expect_equal(obj.b_r, val)
+        stest.expect_equal(obj.write_val, 0)
+        stest.expect_equal(obj.before_write_called, False)
+        stest.expect_equal(obj.after_write_called, False)
+        stest.expect_equal(obj.before_read_called, True)
+        stest.expect_equal(obj.after_read_called, True)
+        stest.expect_equal(obj.before_set_called, False)
+        stest.expect_equal(obj.after_set_called, False)
 
         reset_dev(obj, val << offs * 8)
         ret = r_inq.read()
-        expect_equal(ret, val)
-        expect_equal(obj.b_r, val << offs * 8)
-        expect_equal(obj.write_val, 0)
-        expect_equal(obj.before_write_called, False)
-        expect_equal(obj.after_write_called, False)
-        expect_equal(obj.before_read_called, False)
-        expect_equal(obj.after_read_called, False)
-        expect_equal(obj.before_set_called, False)
-        expect_equal(obj.after_set_called, False)
+        stest.expect_equal(ret, val)
+        stest.expect_equal(obj.b_r, val << offs * 8)
+        stest.expect_equal(obj.write_val, 0)
+        stest.expect_equal(obj.before_write_called, False)
+        stest.expect_equal(obj.after_write_called, False)
+        stest.expect_equal(obj.before_read_called, False)
+        stest.expect_equal(obj.after_read_called, False)
+        stest.expect_equal(obj.before_set_called, False)
+        stest.expect_equal(obj.after_set_called, False)
diff --git a/test/1.2/registers/T_instrumentation.py b/test/1.2/registers/T_instrumentation.py
index 66a8f2b65..f24d8c73a 100644
--- a/test/1.2/registers/T_instrumentation.py
+++ b/test/1.2/registers/T_instrumentation.py
@@ -1,6 +1,7 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import instrumentation_access_inquire
 import instrumentation_access_set_missed
 import instrumentation_access_set_offset
@@ -22,16 +23,18 @@
 import instrumentation_remove_callback
 import instrumentation_remove_connection_callbacks
 import instrumentation_subscribe_multiple
+import testenv
+obj = testenv.instantiate()
 
-subscribe_b1 = SIM_get_port_interface(
+subscribe_b1 = simics.SIM_get_port_interface(
     obj, 'bank_instrumentation_subscribe', 'b1')
-subscribe_b2 = SIM_get_port_interface(
+subscribe_b2 = simics.SIM_get_port_interface(
     obj, 'bank_instrumentation_subscribe', 'b2')
-order_b1 = SIM_get_port_interface(obj, 'instrumentation_order', 'b1')
+order_b1 = simics.SIM_get_port_interface(obj, 'instrumentation_order', 'b1')
 
 subscribe_ba = [
-    SIM_get_port_interface(obj, 'bank_instrumentation_subscribe', 'ba[0]'),
-    SIM_get_port_interface(obj, 'bank_instrumentation_subscribe', 'ba[1]')]
+    simics.SIM_get_port_interface(obj, 'bank_instrumentation_subscribe', 'ba[0]'),
+    simics.SIM_get_port_interface(obj, 'bank_instrumentation_subscribe', 'ba[1]')]
 
 # The tests don't clean up created connections, so run the connection
 # order test first
diff --git a/test/1.2/registers/T_large_stride.py b/test/1.2/registers/T_large_stride.py
index d548d3c7d..b522c4fcc 100644
--- a/test/1.2/registers/T_large_stride.py
+++ b/test/1.2/registers/T_large_stride.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest, dev_util
+import testenv
+obj = testenv.instantiate()
 
 regs = [dev_util.Register_LE(obj.bank.b, i*0x10000000, size=1) for i in range(16)]
 
diff --git a/test/1.2/registers/T_largearray.py b/test/1.2/registers/T_largearray.py
index 7b06db1ce..ca0cb2dcd 100644
--- a/test/1.2/registers/T_largearray.py
+++ b/test/1.2/registers/T_largearray.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import dev_util
+import testenv
+obj = testenv.instantiate()
 
 a = dev_util.Register_LE(obj.bank.b,  50000)
 b = dev_util.Register_LE(obj.bank.b, 90000)
diff --git a/test/1.2/registers/T_lowarray.py b/test/1.2/registers/T_lowarray.py
index aab83305a..e2cd6c4f1 100644
--- a/test/1.2/registers/T_lowarray.py
+++ b/test/1.2/registers/T_lowarray.py
@@ -1,20 +1,23 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from stest import *
-untrap_log("spec-viol")
+import simics
+import stest
+import testenv
+obj = testenv.instantiate()
+stest.untrap_log("spec-viol")
 
-mem = SIM_create_object("memory-space", "mem",
+mem = simics.SIM_create_object("memory-space", "mem",
                         [["map", [[0, obj, 0, 0, 0x10000000, None, 0, 8192]]]])
 
 try:
     mem.iface.memory_space.read(None, 0, 4, 0)
-    raise TestFailure("no exception")
-except SimExc_Memory:
+    raise stest.TestFailure("no exception")
+except simics.SimExc_Memory:
     pass
 
 data = mem.iface.memory_space.read(None, 16, 4, 0)
-expect_equal(data, (0x22,0x22,0x22,0x22))
+stest.expect_equal(data, (0x22,0x22,0x22,0x22))
 
 data = mem.iface.memory_space.read(None, 40, 4, 0)
-expect_equal(data, (0x22,0x22,0x22,0x22))
+stest.expect_equal(data, (0x22,0x22,0x22,0x22))
diff --git a/test/1.2/registers/T_miss.py b/test/1.2/registers/T_miss.py
index 29e6d0d4b..f5db14d0a 100644
--- a/test/1.2/registers/T_miss.py
+++ b/test/1.2/registers/T_miss.py
@@ -18,6 +18,8 @@
 
 import stest
 import dev_util
+import testenv
+obj = testenv.instantiate()
 
 def read(bank, offs, len):
     return dev_util.Register_LE(bank, offs, size=len).read()
diff --git a/test/1.2/registers/T_miss_pattern.py b/test/1.2/registers/T_miss_pattern.py
index 4e7dea2b4..3e8ed9dea 100644
--- a/test/1.2/registers/T_miss_pattern.py
+++ b/test/1.2/registers/T_miss_pattern.py
@@ -4,6 +4,8 @@
 import contextlib
 import stest, dev_util
 from stest import expect_equal
+import testenv
+obj = testenv.instantiate()
 
 mkR = dev_util.Register_LE
 
@@ -133,8 +135,6 @@ def test_partial():
     r5.write(0xabcd)
     expect_equal(ru.read(), 0xcdab)
 
-#conf.obj.log_level = 4
-
 test_overlap()
 test_partial()
 
diff --git a/test/1.2/registers/T_numbered.py b/test/1.2/registers/T_numbered.py
index 905b0b3a1..46dc3205c 100644
--- a/test/1.2/registers/T_numbered.py
+++ b/test/1.2/registers/T_numbered.py
@@ -1,10 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
 def check_reg(bankname, name, regnum, val):
-    iface = SIM_get_port_interface(obj, "int_register", bankname)
+    iface = simics.SIM_get_port_interface(obj, "int_register", bankname)
 
     if name:
         qname = bankname + "." + name
diff --git a/test/1.2/registers/T_par_over_endian.py b/test/1.2/registers/T_par_over_endian.py
index 2bd27a408..31819d75f 100644
--- a/test/1.2/registers/T_par_over_endian.py
+++ b/test/1.2/registers/T_par_over_endian.py
@@ -2,8 +2,10 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import contextlib
-from simics import *
+import simics
 import stest, dev_util
+import testenv
+obj = testenv.instantiate()
 
 def byte_at(offs, big_endian_regsize):
     if big_endian_regsize:
@@ -36,8 +38,8 @@ def write(bank, offset, length, partial = False, overlapping = False,
     data = expected_data(offset, length, not little_endian)
     print("DATA %x" % (data,))
     illegal = (illegal
-               or (partial and 'nonpar' in SIM_object_name(bank))
-               or (overlapping and 'nonover' in SIM_object_name(bank)))
+               or (partial and 'nonpar' in simics.SIM_object_name(bank))
+               or (overlapping and 'nonover' in simics.SIM_object_name(bank)))
     if illegal:
         with expect_miss(bank):
             reg.write(data)
@@ -50,8 +52,8 @@ def read(bank, offset, length,
     print("Reading %d bytes from offset %#x" % (length, offset))
     reg = dev_util.Register_LE(bank, offset, size=length)
     illegal = (illegal
-               or (partial and 'nonpar' in SIM_object_name(bank))
-               or (overlapping and 'nonover' in SIM_object_name(bank)))
+               or (partial and 'nonpar' in simics.SIM_object_name(bank))
+               or (overlapping and 'nonover' in simics.SIM_object_name(bank)))
     if illegal:
         with expect_miss(bank):
             reg.read()
@@ -154,5 +156,5 @@ def w(offs, size, force_little_endian=False, **args):
 for p in ['nonpar', 'par']:
     for o in ['nonover', 'over']:
         for e in ['le', 'be']:
-            test_some(SIM_object_descendant(obj.bank, '_'.join([p, o, e])),
+            test_some(simics.SIM_object_descendant(obj.bank, '_'.join([p, o, e])),
                       e == 'le')
diff --git a/test/1.2/registers/T_read_constant.py b/test/1.2/registers/T_read_constant.py
index 82aa16930..a68b79277 100644
--- a/test/1.2/registers/T_read_constant.py
+++ b/test/1.2/registers/T_read_constant.py
@@ -1,18 +1,21 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 stest.expect_equal(obj.b_r0, 0x12345678)
 stest.expect_equal(obj.b_r1, 0x12345678)
 
 try:
     obj.b_r0 = 17
     stest.fail("register is writable")
-except SimExc_AttrNotWritable:
+except simics.SimExc_AttrNotWritable:
     pass
 
 try:
     obj.b_r1 = 17
     stest.fail("register is writable")
-except SimExc_AttrNotWritable:
+except simics.SimExc_AttrNotWritable:
     pass
diff --git a/test/1.2/registers/T_read_only.py b/test/1.2/registers/T_read_only.py
index b7df0f9c7..cd4302076 100644
--- a/test/1.2/registers/T_read_only.py
+++ b/test/1.2/registers/T_read_only.py
@@ -4,8 +4,10 @@
 # Test that the read_only template works on registers with and without
 # fields (bug 16355)
 
-from stest import *
+import stest
 import dev_util as du
+import testenv
+obj = testenv.instantiate()
 
 # Create register objects for accessing the DUT. R0 is a simple
 # read-only register and R1 has a field. Both registers implement the
@@ -15,47 +17,47 @@
 
 # Registers should have 0 as reset value and ignore writes (since they
 # are read_only). They should also emit 'spec-viol' on write access.
-expect_equal(r0.read(), 0)
-expect_log(r0.write, [17], obj.bank.b, 'spec-viol')
-expect_equal(r0.read(), 0)
+stest.expect_equal(r0.read(), 0)
+stest.expect_log(r0.write, [17], obj.bank.b, 'spec-viol')
+stest.expect_equal(r0.read(), 0)
 
-expect_equal(r1.read(), 0)
-expect_log(r1.write, [17], obj.bank.b, 'spec-viol')
-expect_equal(r1.read(), 0)
+stest.expect_equal(r1.read(), 0)
+stest.expect_log(r1.write, [17], obj.bank.b, 'spec-viol')
+stest.expect_equal(r1.read(), 0)
 
 # read-only fields should be writable with the same value
 r2 = du.Register_LE(obj.bank.b, 8)
 
-expect_equal(r2.read(), 0)
+stest.expect_equal(r2.read(), 0)
 r2.write(0)
-expect_log(r2.write, [17], obj.bank.b, 'spec-viol')
-expect_equal(r2.read(), 0)
+stest.expect_log(r2.write, [17], obj.bank.b, 'spec-viol')
+stest.expect_equal(r2.read(), 0)
 
 # Testing no-alloc variants of read_only template
 r3 = du.Register_LE(obj.bank.b, 12)
-expect_equal(r3.read(), 0)
-expect_log(r3.write, [17], obj.bank.b, 'spec-viol')
-expect_equal(r3.read(), 0)
+stest.expect_equal(r3.read(), 0)
+stest.expect_log(r3.write, [17], obj.bank.b, 'spec-viol')
+stest.expect_equal(r3.read(), 0)
 
 r4 = du.Register_LE(obj.bank.b, 16)
-expect_equal(r4.read(), 0)
-expect_log(r4.write, [17], obj.bank.b, 'spec-viol')
-expect_equal(r4.read(), 0)
+stest.expect_equal(r4.read(), 0)
+stest.expect_log(r4.write, [17], obj.bank.b, 'spec-viol')
+stest.expect_equal(r4.read(), 0)
 
 r5 = du.Register_LE(obj.bank.b, 20)
-expect_equal(r5.read(), 0)
+stest.expect_equal(r5.read(), 0)
 r5.write(0)
-expect_log(r5.write, [17], obj.bank.b, 'spec-viol')
-expect_equal(r5.read(), 0)
+stest.expect_log(r5.write, [17], obj.bank.b, 'spec-viol')
+stest.expect_equal(r5.read(), 0)
 
 r6 = du.Register_LE(obj.bank.b, 24)
-expect_equal(r6.read(), 7)
+stest.expect_equal(r6.read(), 7)
 r6.write(7)
-expect_log(r6.write, [11], obj.bank.b, 'spec-viol')
-expect_equal(r6.read(), 7)
+stest.expect_log(r6.write, [11], obj.bank.b, 'spec-viol')
+stest.expect_equal(r6.read(), 7)
 
 r7 = du.Register_LE(obj.bank.b, 28)
-expect_equal(r7.read(), 7)
+stest.expect_equal(r7.read(), 7)
 r7.write(7)
-expect_log(r7.write, [11], obj.bank.b, 'spec-viol')
-expect_equal(r7.read(), 7)
+stest.expect_log(r7.write, [11], obj.bank.b, 'spec-viol')
+stest.expect_equal(r7.read(), 7)
diff --git a/test/1.2/registers/T_reserved.py b/test/1.2/registers/T_reserved.py
index 32b9dda39..d13be6c6c 100644
--- a/test/1.2/registers/T_reserved.py
+++ b/test/1.2/registers/T_reserved.py
@@ -1,30 +1,33 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-SIM_run_command("log-level 4")
-mem = SIM_create_object("memory-space", "mem",
+import simics
+import testenv
+obj = testenv.instantiate()
+simics.SIM_run_command("log-level 4")
+mem = simics.SIM_create_object("memory-space", "mem",
                         [["map", [[0, [obj, "regs"], 0, 0, 0x10000000]]]])
 
 def loghap(arg, obj, logtype, msg):
     global specviol
-    if logtype == Sim_Log_Spec_Violation:
+    if logtype == simics.Sim_Log_Spec_Violation:
         specviol = True
 
-SIM_hap_add_callback("Core_Log_Message", loghap, None)
+simics.SIM_hap_add_callback("Core_Log_Message", loghap, None)
 
 def dowrite(offset, data, expect_failure):
     global specviol
     specviol = False
     exc = mem.iface.memory_space.write(None, 0, data, 0)
-    if exc != Sim_PE_No_Exception:
+    if exc != simics.Sim_PE_No_Exception:
         print("exception when writing")
-        SIM_quit(1)
+        simics.SIM_quit(1)
     if expect_failure and not specviol:
         print("no violation detected")
-        SIM_quit(1)
+        simics.SIM_quit(1)
     if not expect_failure and specviol:
         print("stray violation detected")
-        SIM_quit(1)
+        simics.SIM_quit(1)
 
 # Should always be OK to write zero
 dowrite(0, (0,0,0,0), False)
diff --git a/test/1.2/registers/T_unmapped_hole.py b/test/1.2/registers/T_unmapped_hole.py
index abe74e427..09c2000a1 100644
--- a/test/1.2/registers/T_unmapped_hole.py
+++ b/test/1.2/registers/T_unmapped_hole.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest, dev_util
+import testenv
+obj = testenv.instantiate()
 
 regs = [dev_util.Register_LE(obj.bank.b, i, size=1) for i in range(3)]
 
diff --git a/test/1.2/statements/T_log.py b/test/1.2/statements/T_log.py
index 4386183b8..74ea82a9a 100644
--- a/test/1.2/statements/T_log.py
+++ b/test/1.2/statements/T_log.py
@@ -1,5 +1,8 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import testenv
+import conf
+obj = testenv.instantiate()
 conf.sim.stop_on_error = False
 obj.log_stuff = None
diff --git a/test/1.2/statements/T_log_new.py b/test/1.2/statements/T_log_new.py
index 6b57df918..35378d5e0 100644
--- a/test/1.2/statements/T_log_new.py
+++ b/test/1.2/statements/T_log_new.py
@@ -1,9 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
+import testenv
+import conf
+obj = testenv.instantiate()
 conf.sim.stop_on_error = False
 if not obj.runtest:
     print('test attribute returned false')
-    SIM_quit(1)
+    simics.SIM_quit(1)
 
 
diff --git a/test/1.2/structure/T_attribute_array_1.py b/test/1.2/structure/T_attribute_array_1.py
index b532af7ce..71307e870 100644
--- a/test/1.2/structure/T_attribute_array_1.py
+++ b/test/1.2/structure/T_attribute_array_1.py
@@ -3,8 +3,10 @@
 
 import stest
 import simics
+import testenv
+obj = testenv.instantiate()
 
-[footype] = [attr[4] for attr in VT_get_all_attributes("test")
+[footype] = [attr[4] for attr in simics.VT_get_all_attributes("test")
              if attr[0] == 'foo']
 
 stest.expect_equal(footype, "[[i{4}]{4}]")
@@ -12,7 +14,7 @@
                              [8, 9, 10, 11], [12, 13, 14, 15]])
 
 with stest.expect_exception_mgr(simics.SimExc_General):
-    SIM_get_attribute(obj, 'bad')
+    simics.SIM_get_attribute(obj, 'bad')
 
 with stest.expect_exception_mgr(simics.SimExc_General):
     obj.bad = [None] * 5
diff --git a/test/1.2/structure/T_attribute_conf.dml b/test/1.2/structure/T_attribute_conf.dml
index 6279e12d0..f33513d8e 100644
--- a/test/1.2/structure/T_attribute_conf.dml
+++ b/test/1.2/structure/T_attribute_conf.dml
@@ -6,7 +6,6 @@ dml 1.2;
 device test;
 
 // must set required attributes
-/// INSTANTIATE-MANUALLY
 
 attribute persist {
     parameter persistent = true;
diff --git a/test/1.2/structure/T_attribute_conf.py b/test/1.2/structure/T_attribute_conf.py
index 6d010cf5c..9b9a6a5c2 100644
--- a/test/1.2/structure/T_attribute_conf.py
+++ b/test/1.2/structure/T_attribute_conf.py
@@ -2,9 +2,10 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest
+import simics
 import simicsutils
 
-obj = SIM_create_object('test', 'obj', [['b1_a', 5], ['b2_a', [0,1,2,3]]])
+obj = simics.SIM_create_object('test', 'obj', [['b1_a', 5], ['b2_a', [0,1,2,3]]])
 
 stest.expect_equal(obj.bank.b1.a, 5)
 stest.expect_equal([obj.bank.b2[i].a for i in range(4)], list(range(4)))
@@ -14,11 +15,11 @@
 obj.persist = 17
 
 if simicsutils.internal.get_simics_major() == "6":
-    CORE_write_configuration_persistent("persistent.conf", None, Sim_Save_Nobundle)
+    simics.CORE_write_configuration_persistent("persistent.conf", None, simics.Sim_Save_Nobundle)
 else:
-    SIM_write_persistent_state("persistent.conf", None, Sim_Save_Nobundle)
+    simics.SIM_write_persistent_state("persistent.conf", None, simics.Sim_Save_Nobundle)
 
-config = VT_get_configuration("persistent.conf")
+config = simics.VT_get_configuration("persistent.conf")
 print(config)
 
 pobj = config.get('obj')
diff --git a/test/1.2/structure/T_attribute_string.py b/test/1.2/structure/T_attribute_string.py
index 804ee8b66..e4a06c47f 100644
--- a/test/1.2/structure/T_attribute_string.py
+++ b/test/1.2/structure/T_attribute_string.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
+import testenv
+obj = testenv.instantiate()
 obj.s = "teststring"
 if obj.s != "teststring":
     print("Failed to set and get string attribute")
-    SIM_quit(1)
+    simics.SIM_quit(1)
diff --git a/test/1.2/structure/T_attribute_throw.py b/test/1.2/structure/T_attribute_throw.py
index 391001ded..e08337f18 100644
--- a/test/1.2/structure/T_attribute_throw.py
+++ b/test/1.2/structure/T_attribute_throw.py
@@ -1,16 +1,19 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-with stest.expect_exception_mgr(SimExc_IllegalValue):
+with stest.expect_exception_mgr(simics.SimExc_IllegalValue):
     obj.a = None
 
-with stest.expect_exception_mgr(SimExc_General):
-    SIM_get_attribute(obj, "a")
+with stest.expect_exception_mgr(simics.SimExc_General):
+    simics.SIM_get_attribute(obj, "a")
 
-with stest.expect_exception_mgr(SimExc_IllegalValue):
+with stest.expect_exception_mgr(simics.SimExc_IllegalValue):
     obj.b = None
 
-with stest.expect_exception_mgr(SimExc_General):
-    SIM_get_attribute(obj, "b")
+with stest.expect_exception_mgr(simics.SimExc_General):
+    simics.SIM_get_attribute(obj, "b")
diff --git a/test/1.2/structure/T_connect_array.py b/test/1.2/structure/T_connect_array.py
index c83d3ec74..d55372d48 100644
--- a/test/1.2/structure/T_connect_array.py
+++ b/test/1.2/structure/T_connect_array.py
@@ -3,6 +3,8 @@
 
 import stest
 import dev_util
+import testenv
+obj = testenv.instantiate()
 
 stest.expect_equal(obj.c, [[None, None, None], [None, None, None]])
 
diff --git a/test/1.2/structure/T_connect_validate.py b/test/1.2/structure/T_connect_validate.py
index bdfd23c84..1f5d966bb 100644
--- a/test/1.2/structure/T_connect_validate.py
+++ b/test/1.2/structure/T_connect_validate.py
@@ -1,11 +1,15 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
+import testenv
+import conf
+obj = testenv.instantiate()
 conf.sim.stop_on_error = False
 obj.foo = conf.sim
 try:
     obj.foo = obj
     print("*** Failed to detect wrong object")
-    SIM_quit(1)
-except SimExc_IllegalValue:
+    simics.SIM_quit(1)
+except simics.SimExc_IllegalValue:
     pass
diff --git a/test/1.2/structure/T_connects_in_port_array.py b/test/1.2/structure/T_connects_in_port_array.py
index 43d083a5e..7be9a0e6f 100644
--- a/test/1.2/structure/T_connects_in_port_array.py
+++ b/test/1.2/structure/T_connects_in_port_array.py
@@ -3,6 +3,8 @@
 
 import stest
 import dev_util
+import testenv
+obj = testenv.instantiate()
 
 for pa1 in obj.port.p:
     for pa2 in pa1:
diff --git a/test/1.2/structure/T_desc.py b/test/1.2/structure/T_desc.py
index 51fc95562..57dd4d155 100644
--- a/test/1.2/structure/T_desc.py
+++ b/test/1.2/structure/T_desc.py
@@ -1,20 +1,23 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
 stest.expect_equal(obj.class_desc, 'short desc 1')
-stest.expect_equal(VT_get_class_description(SIM_object_class(obj)),
+stest.expect_equal(simics.VT_get_class_description(simics.SIM_object_class(obj)),
                    'short desc 1')
-port = SIM_object_descendant(obj, 'bank.descb')
+port = simics.SIM_object_descendant(obj, 'bank.descb')
 stest.expect_equal(port.class_desc, 'short desc 2')
-stest.expect_equal(VT_get_class_description(SIM_object_class(port)),
+stest.expect_equal(simics.VT_get_class_description(simics.SIM_object_class(port)),
                    'short desc 2')
-port = SIM_object_descendant(obj, 'port.descp')
+port = simics.SIM_object_descendant(obj, 'port.descp')
 stest.expect_equal(port.class_desc, 'short desc 3')
-stest.expect_equal(VT_get_class_description(SIM_object_class(port)),
+stest.expect_equal(simics.VT_get_class_description(simics.SIM_object_class(port)),
                    'short desc 3')
 for portname in ['port.nodescp', 'bank.nodescb']:
-    port = SIM_object_descendant(obj, portname)
+    port = simics.SIM_object_descendant(obj, portname)
     stest.expect_equal(port.class_desc, None)
-    stest.expect_equal(VT_get_class_description(SIM_object_class(port)), None)
+    stest.expect_equal(simics.VT_get_class_description(simics.SIM_object_class(port)), None)
diff --git a/test/1.2/structure/T_doc.py b/test/1.2/structure/T_doc.py
index c220916db..f15f14919 100644
--- a/test/1.2/structure/T_doc.py
+++ b/test/1.2/structure/T_doc.py
@@ -1,16 +1,19 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
 stest.expect_equal(obj.class_desc, None)
-stest.expect_equal(VT_get_class_description(SIM_object_class(obj)),
+stest.expect_equal(simics.VT_get_class_description(simics.SIM_object_class(obj)),
                                             'long description')
-port = SIM_object_descendant(obj, 'port.doc_only')
+port = simics.SIM_object_descendant(obj, 'port.doc_only')
 stest.expect_equal(port.class_desc, None)
-stest.expect_equal(VT_get_class_description(SIM_object_class(port)),
+stest.expect_equal(simics.VT_get_class_description(simics.SIM_object_class(port)),
                                             'long description 2')
-port = SIM_object_descendant(obj, 'bank.doc_desc')
+port = simics.SIM_object_descendant(obj, 'bank.doc_desc')
 stest.expect_equal(port.class_desc, 'short desc')
-stest.expect_equal(VT_get_class_description(SIM_object_class(port)),
+stest.expect_equal(simics.VT_get_class_description(simics.SIM_object_class(port)),
                                             'long description 3')
diff --git a/test/1.2/structure/T_group_attr.py b/test/1.2/structure/T_group_attr.py
index ebedc2b37..b99bb98d2 100644
--- a/test/1.2/structure/T_group_attr.py
+++ b/test/1.2/structure/T_group_attr.py
@@ -1,6 +1,9 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
+import testenv
+obj = testenv.instantiate()
 print(obj.b_ga_a)
 
 if obj.b_ga_a == [[[i*100 + j*10 + k for k in range(3)]
@@ -9,4 +12,4 @@
     print("OK")
 else:
     print("Incorrect value")
-    SIM_quit(1)
+    simics.SIM_quit(1)
diff --git a/test/1.2/structure/T_mappable.py b/test/1.2/structure/T_mappable.py
index e6d231939..4482df999 100644
--- a/test/1.2/structure/T_mappable.py
+++ b/test/1.2/structure/T_mappable.py
@@ -1,15 +1,18 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
-print(SIM_get_port_interface(obj, "io_memory", "b1"))
+import testenv
+obj = testenv.instantiate()
+print(simics.SIM_get_port_interface(obj, "io_memory", "b1"))
 
 try:
-    print(SIM_get_port_interface(obj, "io_memory", "b2"))
+    print(simics.SIM_get_port_interface(obj, "io_memory", "b2"))
     print("b2 is mappable")
-    SIM_quit(1)
-except SimExc_Lookup:
+    simics.SIM_quit(1)
+except simics.SimExc_Lookup:
     pass
 
-print(SIM_get_port_interface(obj, "io_memory", "b3"))
+print(simics.SIM_get_port_interface(obj, "io_memory", "b3"))
 stest.expect_true(obj.runtest)
diff --git a/test/1.2/structure/T_port.py b/test/1.2/structure/T_port.py
index 1a0d57514..703995943 100644
--- a/test/1.2/structure/T_port.py
+++ b/test/1.2/structure/T_port.py
@@ -1,17 +1,20 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-iface = SIM_get_port_interface(obj, "simple_interrupt", "p")
+iface = simics.SIM_get_port_interface(obj, "simple_interrupt", "p")
 iface.interrupt(17)
 stest.expect_equal(obj.p_last_irq, 17)
-port = SIM_object_descendant(obj, 'port.p')
-portclass = SIM_object_class(port)
+port = simics.SIM_object_descendant(obj, 'port.p')
+portclass = simics.SIM_object_class(port)
 stest.expect_equal(portclass.name, 'test.p')
 with stest.expect_log_mgr(log_type='error'):
-    with stest.expect_exception_mgr(SimExc_General):
-        SIM_create_object(portclass, obj.name + '.port.q', [])
-iface = SIM_get_interface(port, 'simple_interrupt')
+    with stest.expect_exception_mgr(simics.SimExc_General):
+        simics.SIM_create_object(portclass, obj.name + '.port.q', [])
+iface = simics.SIM_get_interface(port, 'simple_interrupt')
 iface.interrupt(43)
 stest.expect_equal(port.last_irq, 43)
diff --git a/test/1.2/structure/T_port_array.py b/test/1.2/structure/T_port_array.py
index b43d26bee..012ccb917 100644
--- a/test/1.2/structure/T_port_array.py
+++ b/test/1.2/structure/T_port_array.py
@@ -1,11 +1,14 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-arr_iface = SIM_get_port_interface(obj, "signal", "prt[0]")
+arr_iface = simics.SIM_get_port_interface(obj, "signal", "prt[0]")
 arr_iface.signal_raise()
-arr_iface = SIM_get_port_interface(obj, "signal", "prt[1]")
+arr_iface = simics.SIM_get_port_interface(obj, "signal", "prt[1]")
 arr_iface.signal_raise()
 stest.expect_equal(obj.prt_raised, [True, True, False, False])
 
@@ -24,8 +27,8 @@
     for j, val in enumerate(sublist):
         stest.expect_equal(obj.port.prtarr[i][j].raised, val)
 
-port = SIM_object_descendant(obj, 'port.prtarr[3][0]')
-portclass = SIM_object_class(port)
+port = simics.SIM_object_descendant(obj, 'port.prtarr[3][0]')
+portclass = simics.SIM_object_class(port)
 stest.expect_equal(portclass.name, 'test.prtarr')
 
 stest.expect_equal(port.raised, False)
diff --git a/test/1.2/structure/T_string_attribute.dml b/test/1.2/structure/T_string_attribute.dml
index 180a5db80..879695667 100644
--- a/test/1.2/structure/T_string_attribute.dml
+++ b/test/1.2/structure/T_string_attribute.dml
@@ -6,7 +6,6 @@ dml 1.2;
 device test;
 
 // must set required attributes
-/// INSTANTIATE-MANUALLY
 
 attribute req "required" {
     parameter allocate_type = "string";
diff --git a/test/1.2/structure/T_string_attribute.py b/test/1.2/structure/T_string_attribute.py
index 0bd22e3c3..d63cc3ba6 100644
--- a/test/1.2/structure/T_string_attribute.py
+++ b/test/1.2/structure/T_string_attribute.py
@@ -2,7 +2,7 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import simics
-from stest import *
+import stest
 
 obj = simics.SIM_create_object('test', 'obj', [['req', 'banan']])
 
@@ -10,23 +10,23 @@
 _ = obj.opt
 _ = obj.pse
 
-expect_equal(obj.req, "banan")
-expect_equal(obj.opt, None)
-expect_equal(obj.pse, None)
+stest.expect_equal(obj.req, "banan")
+stest.expect_equal(obj.opt, None)
+stest.expect_equal(obj.pse, None)
 
 obj.req = "bazooka"
 obj.opt = "apelsin"
 obj.pse = "krutong"
 
-expect_equal(obj.req, "bazooka")
-expect_equal(obj.opt, "apelsin")
-expect_equal(obj.pse, "krutong")
+stest.expect_equal(obj.req, "bazooka")
+stest.expect_equal(obj.opt, "apelsin")
+stest.expect_equal(obj.pse, "krutong")
 
-expect_exception(setattr, [obj, 'req', None], SimExc_Type)
+stest.expect_exception(setattr, [obj, 'req', None], simics.SimExc_Type)
 obj.opt = None
 #obj.pse = None
 #
-#expect_equal(obj.req, "bazooka")
-#expect_equal(obj.opt, "apelsin")
-#expect_equal(obj.pse, "krutong")
+#stest.expect_equal(obj.req, "bazooka")
+#stest.expect_equal(obj.opt, "apelsin")
+#stest.expect_equal(obj.pse, "krutong")
 
diff --git a/test/1.4/events/T_after.py b/test/1.4/events/T_after.py
index 9b62f6dc4..c1f375d32 100644
--- a/test/1.4/events/T_after.py
+++ b/test/1.4/events/T_after.py
@@ -1,9 +1,12 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
 
@@ -13,25 +16,25 @@
 obj.trigger = [[1, 1], [1, 1]]
 obj.trigger_hook = [1, 1]
 obj.operate = None
-SIM_continue(99999)
+simics.SIM_continue(99999)
 stest.expect_equal(obj.trigger, [[0, 0], [0, 0]])
 stest.expect_equal(obj.trigger_hook, [0, 0])
 stest.expect_equal(obj.single_operator, 0)
 stest.expect_equal(obj.multi_operator, [[0, 0], [0, 0]])
 stest.expect_equal(obj.hook_operator, [[0, 0], [0, 0]])
-SIM_continue(2)
+simics.SIM_continue(2)
 stest.expect_equal(obj.trigger, [[0, 0], [0, 4]])
 stest.expect_equal(obj.trigger_hook, [0, 2])
 stest.expect_equal(obj.single_operator, 5)
 stest.expect_equal(obj.multi_operator, [[0, 5], [3, 0]])
 stest.expect_equal(obj.hook_operator, [[0, 5], [3, 0]])
-SIM_continue(99998)
+simics.SIM_continue(99998)
 stest.expect_equal(obj.single_operator, 5)
-SIM_continue(2)
+simics.SIM_continue(2)
 stest.expect_equal(obj.single_operator, 3)
 
 obj.trigger_constig = None
-SIM_continue(99999)
+simics.SIM_continue(99999)
 stest.expect_equal(obj.constig_res, [0, 0])
-SIM_continue(2)
+simics.SIM_continue(2)
 stest.expect_equal(obj.constig_res, [4, 7 << 32 | 11])
diff --git a/test/1.4/events/T_after_cancel.py b/test/1.4/events/T_after_cancel.py
index 1b618f5ac..363fb65fc 100644
--- a/test/1.4/events/T_after_cancel.py
+++ b/test/1.4/events/T_after_cancel.py
@@ -1,9 +1,12 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
 def init():
@@ -12,10 +15,10 @@ def init():
 
 init()
 obj.test_1 = None
-SIM_continue(99999)
+simics.SIM_continue(99999)
 stest.expect_equal(obj.single_operator, 1)
 stest.expect_equal(obj.multi_operator, [[1, 1], [1, 1]])
-SIM_continue(2)
+simics.SIM_continue(2)
 stest.expect_equal(obj.single_operator, 216)
 stest.expect_equal(obj.multi_operator, [[1, 216], [1, 1]])
 
@@ -23,10 +26,10 @@ def init():
     try:
         init()
         obj.test_2 = i
-        SIM_continue(99999)
+        simics.SIM_continue(99999)
         stest.expect_equal(obj.single_operator, 1)
         stest.expect_equal(obj.multi_operator, [[1, 1], [1, 1]])
-        SIM_continue(2)
+        simics.SIM_continue(2)
         stest.expect_equal(obj.single_operator, 2)
         stest.expect_equal(obj.multi_operator, [[1, 5], [1, 1]])
     except Exception as e:
diff --git a/test/1.4/events/T_after_chk.cont.py b/test/1.4/events/T_after_chk.cont.py
index f0967217d..45e109235 100644
--- a/test/1.4/events/T_after_chk.cont.py
+++ b/test/1.4/events/T_after_chk.cont.py
@@ -1,13 +1,14 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import conf
 
-run_command("peq")
+simics.run_command("peq")
 conf.obj.cancel_afters = None
 print("Running 2 s")
-SIM_continue(2000000)
-
+simics.SIM_continue(2000000)
 stest.expect_equal(conf.obj.flag, [True]*2)
 stest.expect_equal(conf.obj.g_flag, [False]*2)
 stest.expect_equal(conf.obj.port.p[0][0].flag, [False]*2)
diff --git a/test/1.4/events/T_after_chk.py b/test/1.4/events/T_after_chk.py
index 06170e598..1c408e1a9 100644
--- a/test/1.4/events/T_after_chk.py
+++ b/test/1.4/events/T_after_chk.py
@@ -1,20 +1,24 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from os.path import join
+import simics
+from os.path import join, dirname
 import subprocess
 from simicsutils.host import batch_suffix
+import testenv
+import conf
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 obj.exec_afters = None
 
-SIM_write_configuration_to_file("after_chk.chkp", Sim_Save_Nobundle)
+simics.SIM_write_configuration_to_file("after_chk.chkp", simics.Sim_Save_Nobundle)
 
 subprocess.check_call(
     [f'{conf.sim.project}/bin/simics{batch_suffix()}'] +
     ["--batch-mode", "--quiet", "--no-copyright", "--dump-core", "--werror",
      '--project', conf.sim.project,
-     "--module-path", scratchdir,
+     "--module-path", testenv.scratchdir(),
      "-e", "read-configuration after_chk.chkp",
-     join(basedir, "T_after_chk.cont.py")])
+     join(dirname(__file__), "T_after_chk.cont.py")])
diff --git a/test/1.4/expressions/T_illegal_arithmetic.py b/test/1.4/expressions/T_illegal_arithmetic.py
index 0d642df4e..4a287f31b 100644
--- a/test/1.4/expressions/T_illegal_arithmetic.py
+++ b/test/1.4/expressions/T_illegal_arithmetic.py
@@ -2,6 +2,9 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import simics
+import testenv
+import conf
+obj = testenv.instantiate()
 conf.sim.stop_on_error = False
 try:
     obj.not_zero = 0
diff --git a/test/1.4/expressions/T_trait_identity.py b/test/1.4/expressions/T_trait_identity.py
index e08d6076f..95eb49fca 100644
--- a/test/1.4/expressions/T_trait_identity.py
+++ b/test/1.4/expressions/T_trait_identity.py
@@ -3,6 +3,9 @@
 
 import simics
 import stest
+import testenv
+import conf
+obj = testenv.instantiate()
 conf.sim.stop_on_error = False
 
 try:
diff --git a/test/1.4/hooks/T_asynchronous_send.py b/test/1.4/hooks/T_asynchronous_send.py
index 812557f07..72250a73d 100644
--- a/test/1.4/hooks/T_asynchronous_send.py
+++ b/test/1.4/hooks/T_asynchronous_send.py
@@ -1,25 +1,28 @@
 # © 2024 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import simics
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
-setup_ev = SIM_register_event("setup_ev", None, Sim_EC_Notsaved,
+setup_ev = simics.SIM_register_event("setup_ev", None, simics.Sim_EC_Notsaved,
                        lambda _o, _d: obj.setup, None, None, None, None)
-test_ev = SIM_register_event("test_ev", None, Sim_EC_Notsaved,
+test_ev = simics.SIM_register_event("test_ev", None, simics.Sim_EC_Notsaved,
                        lambda _o, _d: obj.test, None, None, None, None)
 
 # global context
 _ = obj.setup
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 _ = obj.test
 
 # execution context
-SIM_event_post_cycle(cpu, setup_ev, obj, 0, None)
-SIM_continue(1)
+simics.SIM_event_post_cycle(cpu, setup_ev, obj, 0, None)
+simics.SIM_continue(1)
 _ = obj.test
 
 # global context into execution context
-SIM_event_post_cycle(cpu, test_ev, obj, 0, None)
+simics.SIM_event_post_cycle(cpu, test_ev, obj, 0, None)
 _ = obj.setup
-SIM_continue(1)
+simics.SIM_continue(1)
diff --git a/test/1.4/hooks/T_bad_hookattr_set.py b/test/1.4/hooks/T_bad_hookattr_set.py
index d8dbf5f71..a017d282a 100644
--- a/test/1.4/hooks/T_bad_hookattr_set.py
+++ b/test/1.4/hooks/T_bad_hookattr_set.py
@@ -3,6 +3,8 @@
 
 import simics;
 import stest;
+import testenv
+obj = testenv.instantiate()
 
 after_to_m_elem = ['after', ["('g[%u].m', (None, None))", [2], [2, True],
                              [['dev', []]]]]
diff --git a/test/1.4/hooks/T_checkpointing.cont.py b/test/1.4/hooks/T_checkpointing.cont.py
index 3e4b44aec..324ea06fc 100644
--- a/test/1.4/hooks/T_checkpointing.cont.py
+++ b/test/1.4/hooks/T_checkpointing.cont.py
@@ -1,6 +1,8 @@
 # © 2024 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-SIM_read_configuration("checkpointing.chkp")
+import simics
+import conf
+simics.SIM_read_configuration("checkpointing.chkp")
 
 conf.obj.test_state = None
diff --git a/test/1.4/hooks/T_checkpointing.py b/test/1.4/hooks/T_checkpointing.py
index ce0754173..3416b3644 100644
--- a/test/1.4/hooks/T_checkpointing.py
+++ b/test/1.4/hooks/T_checkpointing.py
@@ -1,17 +1,21 @@
 # © 2024 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from os.path import join
+import simics
+from os.path import join, dirname
 import subprocess
 from simicsutils.host import batch_suffix
+import testenv
+import conf
+obj = testenv.instantiate()
 
 obj.setup_state = None
 
-SIM_write_configuration_to_file("checkpointing.chkp", Sim_Save_Nobundle)
+simics.SIM_write_configuration_to_file("checkpointing.chkp", simics.Sim_Save_Nobundle)
 
 subprocess.check_call(
     [f'{conf.sim.project}/bin/simics{batch_suffix()}'] +
     ["--batch-mode", "--quiet", "--no-copyright", "--dump-core", "--werror",
      '--project', conf.sim.project,
-     "-L", scratchdir,
-     join(basedir, "T_checkpointing.cont.py")])
+     "-L", testenv.scratchdir(),
+     join(dirname(__file__), "T_checkpointing.cont.py")])
diff --git a/test/1.4/legacy/T_restrict_log_levels_disabled.py b/test/1.4/legacy/T_restrict_log_levels_disabled.py
index 679d3b7d0..6f5123f7c 100644
--- a/test/1.4/legacy/T_restrict_log_levels_disabled.py
+++ b/test/1.4/legacy/T_restrict_log_levels_disabled.py
@@ -1,7 +1,10 @@
 # © 2024 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import sim_commands
 import stest
+import testenv
+obj = testenv.instantiate()
 
 class LogCapture(object):
     def __init__(self):
diff --git a/test/1.4/lib/T_bad_subobj_connect.dml b/test/1.4/lib/T_bad_subobj_connect.dml
index 52b2986e6..882932616 100644
--- a/test/1.4/lib/T_bad_subobj_connect.dml
+++ b/test/1.4/lib/T_bad_subobj_connect.dml
@@ -6,8 +6,6 @@ dml 1.4;
 
 device test;
 
-/// INSTANTIATE-MANUALLY
-
 connect x is init_as_subobj {
     param classname = "garbage";
 }
diff --git a/test/1.4/lib/T_bad_subobj_connect.py b/test/1.4/lib/T_bad_subobj_connect.py
index b379c5f4a..7b0787c35 100644
--- a/test/1.4/lib/T_bad_subobj_connect.py
+++ b/test/1.4/lib/T_bad_subobj_connect.py
@@ -3,9 +3,10 @@
 
 import simics
 import stest
+import conf
 conf.sim.stop_on_error = False
 try:
-    simics.SIM_load_module(f'dml-test-bad_subobj_connect')
+    simics.SIM_load_module('dml-test-bad_subobj_connect')
 except simics.CriticalErrors as e:
     stest.expect_true('garbage' in str(e))
 else:
diff --git a/test/1.4/lib/T_bank.py b/test/1.4/lib/T_bank.py
index 99facdada..eb1e55fb5 100644
--- a/test/1.4/lib/T_bank.py
+++ b/test/1.4/lib/T_bank.py
@@ -1,7 +1,11 @@
 # © 2026 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import sim_commands
 import stest
+import testenv
+import conf
+obj = testenv.instantiate()
 
 class LogCapture(object):
     def __init__(self, kind='error'):
diff --git a/test/1.4/lib/T_connect.dml b/test/1.4/lib/T_connect.dml
index 35ee57337..f381f0fc5 100644
--- a/test/1.4/lib/T_connect.dml
+++ b/test/1.4/lib/T_connect.dml
@@ -10,7 +10,6 @@ import "simics/devs/signal.dml";
 import "simics/devs/ethernet.dml";
 
 // must define class 'signal_stub' before instantiating
-/// INSTANTIATE-MANUALLY
 
 connect validate {
     method validate(conf_object_t *obj) -> (bool) {
diff --git a/test/1.4/lib/T_connect.py b/test/1.4/lib/T_connect.py
index 606f4fc30..dfe29ac13 100644
--- a/test/1.4/lib/T_connect.py
+++ b/test/1.4/lib/T_connect.py
@@ -3,8 +3,8 @@
 
 import pyobj
 import stest
-import dev_util
 import simics
+import conf
 
 calls = []
 class signal_stub(pyobj.ConfObject): pass
@@ -18,7 +18,7 @@ class signal_stub(pyobj.ConfObject): pass
 stest.expect_equal(bad.sub_renamed, [None, None])
 conf.sim.stop_on_error = True
 
-SIM_register_interface('signal_stub', 'signal', signal_interface_t(
+simics.SIM_register_interface('signal_stub', 'signal', simics.signal_interface_t(
     signal_raise=lambda obj: calls.append((obj, 'signal_raise'))))
 
 obj = simics.SIM_create_object('test', 'obj', [])
@@ -29,18 +29,18 @@ class signal_stub(pyobj.ConfObject): pass
 stest.expect_equal(obj.attr.sub_renamed, [obj.sub[0].renamed,
                                           obj.sub[1].renamed])
 
-stest.expect_true(SIM_object_descendant(obj, "a2[1].bank.b2[2].c2[4].d[6]"))
-stest.expect_true(SIM_object_descendant(obj, "a2[1].e.f"))
-stest.expect_true(SIM_object_descendant(obj, "a2[1].port.p.q"))
+stest.expect_true(simics.SIM_object_descendant(obj, "a2[1].bank.b2[2].c2[4].d[6]"))
+stest.expect_true(simics.SIM_object_descendant(obj, "a2[1].e.f"))
+stest.expect_true(simics.SIM_object_descendant(obj, "a2[1].port.p.q"))
 
 # by default, init_as_subobj connects have configuration=none
-stest.expect_false(SIM_class_has_attribute('test', 'noconf'))
+stest.expect_false(simics.SIM_class_has_attribute('test', 'noconf'))
 
-with stest.expect_exception_mgr(SimExc_General):
+with stest.expect_exception_mgr(simics.SimExc_General):
     obj.validate = [conf.sim, "foo"]
-with stest.expect_exception_mgr(SimExc_General):
+with stest.expect_exception_mgr(simics.SimExc_General):
     obj.validate = conf.sim
-with stest.expect_exception_mgr(SimExc_General):
+with stest.expect_exception_mgr(simics.SimExc_General):
     obj.validate = [obj, "bar"]
 obj.validate = [obj, "foo"]
 obj.validate = obj
@@ -65,12 +65,12 @@ def signal_lower(self): pass
 both.register()
 three.register()
 [only_common, only_cable, both, three] = [
-    SIM_create_object(name, name, []) for name in [
+    simics.SIM_create_object(name, name, []) for name in [
         'only_common', 'only_cable', 'both', 'three']]
 
-with stest.expect_exception_mgr(SimExc_General):
+with stest.expect_exception_mgr(simics.SimExc_General):
     obj.ifaces = only_common
-with stest.expect_exception_mgr(SimExc_General):
+with stest.expect_exception_mgr(simics.SimExc_General):
     obj.ifaces = only_cable
 
 obj.ifaces = both
diff --git a/test/1.4/lib/T_destroy.py b/test/1.4/lib/T_destroy.py
index 76ebb89d6..79dfd8b88 100644
--- a/test/1.4/lib/T_destroy.py
+++ b/test/1.4/lib/T_destroy.py
@@ -1,6 +1,9 @@
 # © 2024 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
 destroy_list = None
 def on_destroyed(*invocations):
@@ -8,10 +11,10 @@ def on_destroyed(*invocations):
     stest.expect_equal(destroy_list, None)
     destroy_list = list(invocations)
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 obj.post_ev = None
 
-SIM_delete_object(obj)
+simics.SIM_delete_object(obj)
 
 stest.expect_equal(destroy_list, ["ev", "g2", "g1", "dev"])
diff --git a/test/1.4/lib/T_event.py b/test/1.4/lib/T_event.py
index f07b9f2cf..84c2aadd3 100644
--- a/test/1.4/lib/T_event.py
+++ b/test/1.4/lib/T_event.py
@@ -1,9 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
+import sim_commands
 import stest
+import testenv
+obj = testenv.instantiate()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
 def get_posted_attrs(obj):
@@ -93,10 +97,10 @@ def read_happened_attrs(obj):
 for cycle in sorted(cycles):
     left = cycle - now
     assert left > 1
-    SIM_continue(left - 1)
+    simics.SIM_continue(left - 1)
     stest.expect_equal(set(read_happened_attrs(obj).values()), {0},
                        'cycle %d' % (cycle - 1,))
-    SIM_continue(1)
+    simics.SIM_continue(1)
     now = cycle
     happened_attrs = read_happened_attrs(obj)
     # side-effect of a single event() call
@@ -148,6 +152,6 @@ def read_happened_attrs(obj):
 def callback(o, kind, msg):
     msgs.append(msg)
 with sim_commands.logger.filter(callback):
-    SIM_delete_object(obj)
+    simics.SIM_delete_object(obj)
 stest.expect_equal(len(msgs), 2)
 stest.expect_equal(set(msgs), {'DESTROY CYCLE -1', 'DESTROY TIME 1750'})
diff --git a/test/1.4/lib/T_event_large_uint64.py b/test/1.4/lib/T_event_large_uint64.py
index 68e3e13d9..607b2ee6b 100644
--- a/test/1.4/lib/T_event_large_uint64.py
+++ b/test/1.4/lib/T_event_large_uint64.py
@@ -1,12 +1,15 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
-clock = SIM_create_object('clock', 'clock', [['freq_mhz', 1]])
+clock = simics.SIM_create_object('clock', 'clock', [['freq_mhz', 1]])
 obj.queue = clock
 
 obj.post = None
-SIM_continue(1)
+simics.SIM_continue(1)
 
 stest.expect_equal(obj.happened, 0xAFFFFFFFFFFFFFFF)
diff --git a/test/1.4/lib/T_field.py b/test/1.4/lib/T_field.py
index 53022de20..a75e67def 100644
--- a/test/1.4/lib/T_field.py
+++ b/test/1.4/lib/T_field.py
@@ -3,6 +3,8 @@
 
 import dev_util
 import stest
+import testenv
+obj = testenv.instantiate()
 for name in ['r1', 'r2', 'r3', 'r4']:
     setattr(obj, 'b_' + name, 4)
     # set adds 1, get adds 2
diff --git a/test/1.4/lib/T_io_memory.py b/test/1.4/lib/T_io_memory.py
index 8a19336a9..155717a8a 100644
--- a/test/1.4/lib/T_io_memory.py
+++ b/test/1.4/lib/T_io_memory.py
@@ -1,8 +1,11 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
 import dev_util
+import testenv
+obj = testenv.instantiate()
 
 # bank_io_memory works
 stest.expect_equal(dev_util.Register_LE(obj.port.bare, 0, size=1).read(), 0xaa)
@@ -33,7 +36,7 @@
 stest.expect_equal(dev_util.Register_LE((obj.ab.cc, 0xb, 0), size=1).read(),
                                          0xcc)
 # accessing 0x10 hits address 0x100 in the bank
-ms = SIM_create_object('memory-space', 'ms', map=[[0x10, obj, 0xf, 0x100, 1]])
+ms = simics.SIM_create_object('memory-space', 'ms', map=[[0x10, obj, 0xf, 0x100, 1]])
 ms.iface.memory_space.read(None, 0x10, 1, False)
 # .. and incorrect function numbers are handled somewhat gracefully
 with stest.expect_log_mgr(obj, 'error'), stest.expect_exception_mgr(
diff --git a/test/1.4/lib/T_largearray.py b/test/1.4/lib/T_largearray.py
index 65258a331..e34e2a9c8 100644
--- a/test/1.4/lib/T_largearray.py
+++ b/test/1.4/lib/T_largearray.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import dev_util
+import testenv
+obj = testenv.instantiate()
 
 a = dev_util.Register_LE(obj.bank.b, 50000)
 b = dev_util.Register_LE(obj.bank.b, 90000)
diff --git a/test/1.4/lib/T_map_target_connect.py b/test/1.4/lib/T_map_target_connect.py
index dbaac00f2..eb9d391b1 100644
--- a/test/1.4/lib/T_map_target_connect.py
+++ b/test/1.4/lib/T_map_target_connect.py
@@ -5,6 +5,8 @@
 import simics
 from dev_util import Register_LE
 import re
+import testenv
+obj = testenv.instantiate()
 
 stest.expect_equal(obj.y_value, 42)
 
diff --git a/test/1.4/lib/T_miss_pattern.py b/test/1.4/lib/T_miss_pattern.py
index ea202192f..143646ab3 100644
--- a/test/1.4/lib/T_miss_pattern.py
+++ b/test/1.4/lib/T_miss_pattern.py
@@ -4,6 +4,9 @@
 import contextlib
 import stest, dev_util
 from stest import expect_equal
+import testenv
+import conf
+obj = testenv.instantiate()
 
 mkR = dev_util.Register_LE
 
diff --git a/test/1.4/lib/T_objects_finalized.dml b/test/1.4/lib/T_objects_finalized.dml
index a044a937e..e2e74269f 100644
--- a/test/1.4/lib/T_objects_finalized.dml
+++ b/test/1.4/lib/T_objects_finalized.dml
@@ -6,8 +6,6 @@ dml 1.4;
 
 device test;
 
-/// INSTANTIATE-MANUALLY
-
 saved bool objects_finalized_done;
 
 connect partner;
diff --git a/test/1.4/lib/T_objects_finalized.py b/test/1.4/lib/T_objects_finalized.py
index 33ef76af0..eb6e62c1d 100644
--- a/test/1.4/lib/T_objects_finalized.py
+++ b/test/1.4/lib/T_objects_finalized.py
@@ -1,14 +1,15 @@
 # © 2026 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
+import simics
 import stest
+import conf
 
-
-obj1 = pre_conf_object('obj1', 'test')
-obj2 = pre_conf_object('obj2', 'test')
+obj1 = simics.pre_conf_object('obj1', 'test')
+obj2 = simics.pre_conf_object('obj2', 'test')
 obj1.partner = obj2
 obj2.partner = obj1
 
-SIM_add_configuration([obj1, obj2], None)
+simics.SIM_add_configuration([obj1, obj2], None)
 
 stest.expect_true(conf.obj1.objects_finalized_done)
 stest.expect_true(conf.obj1.g_objects_finalized_done)
diff --git a/test/1.4/lib/T_partial_access_log.py b/test/1.4/lib/T_partial_access_log.py
index 5aaac7507..66796dc04 100644
--- a/test/1.4/lib/T_partial_access_log.py
+++ b/test/1.4/lib/T_partial_access_log.py
@@ -1,8 +1,11 @@
 # © 2025 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import dev_util
 import stest
+import testenv
+obj = testenv.instantiate()
 
 for (order, bank) in [('little', obj.bank.le), ('big', obj.bank.be)]:
     bank.log_level = 4
diff --git a/test/1.4/lib/T_regdisp.py b/test/1.4/lib/T_regdisp.py
index b2b3bcf13..375bc622e 100644
--- a/test/1.4/lib/T_regdisp.py
+++ b/test/1.4/lib/T_regdisp.py
@@ -2,9 +2,10 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import contextlib
-from simics import *
+import simics
 import stest
-import dev_util
+import testenv
+obj = testenv.instantiate()
 
 def test_some(mem, obj, port, allow_partial, allow_overlapping,
               bigendian=False):
@@ -32,11 +33,11 @@ def write(offset, length, partial, overlapping, illegal):
                    or (overlapping and not allow_overlapping))
         with contextlib.ExitStack() as ctx:
             if illegal:
-                ctx.enter_context(stest.expect_exception_mgr(SimExc_Memory))
+                ctx.enter_context(stest.expect_exception_mgr(simics.SimExc_Memory))
                 ctx.enter_context(stest.expect_log_mgr(None, 'spec-viol'))
             exc = mem.iface.memory_space.write(None, offset, data, 0)
-            if exc != Sim_PE_No_Exception:
-                raise SimExc_Memory
+            if exc != simics.Sim_PE_No_Exception:
+                raise simics.SimExc_Memory
             print("Wrote %r to %#x" % (data, offset))
 
     def read(offset, length, partial, overlapping, illegal):
@@ -47,7 +48,7 @@ def read(offset, length, partial, overlapping, illegal):
                    or (overlapping and not allow_overlapping))
         with contextlib.ExitStack() as ctx:
             if illegal:
-                ctx.enter_context(stest.expect_exception_mgr(SimExc_Memory))
+                ctx.enter_context(stest.expect_exception_mgr(simics.SimExc_Memory))
                 ctx.enter_context(stest.expect_log_mgr(None, 'spec-viol'))
             data = mem.iface.memory_space.read(None, offset, length, 0)
             print("Read %r from %#x" % (data, offset))
@@ -122,7 +123,7 @@ def access(offset, length, partial = False, overlapping = False,
     access(0x500, 8, overlapping = True)
     access(0x501, 8, overlapping = True)
 
-mem = SIM_create_object("memory-space", "mem", [])
+mem = simics.SIM_create_object("memory-space", "mem", [])
 
 test_some(mem, obj, 'par_over',
           allow_partial = True,
diff --git a/test/1.4/lib/T_reset.py b/test/1.4/lib/T_reset.py
index e27459c34..0482d0a8c 100644
--- a/test/1.4/lib/T_reset.py
+++ b/test/1.4/lib/T_reset.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest
+import testenv
+obj = testenv.instantiate()
 stest.expect_equal(obj.b_r, [0, 1])
 stest.expect_equal(obj.b_p, 0)
 stest.expect_equal(obj.b_q, 0x123b)
diff --git a/test/1.4/lib/T_signal_templates.dml b/test/1.4/lib/T_signal_templates.dml
index 65be3f9c1..1b985b08a 100644
--- a/test/1.4/lib/T_signal_templates.dml
+++ b/test/1.4/lib/T_signal_templates.dml
@@ -2,7 +2,6 @@
   © 2022 Intel Corporation
   SPDX-License-Identifier: MPL-2.0
 */
-/// INSTANTIATE-MANUALLY
 dml 1.4;
 
 device test;
diff --git a/test/1.4/lib/T_signal_templates.py b/test/1.4/lib/T_signal_templates.py
index 11f52ba4c..f687d7299 100644
--- a/test/1.4/lib/T_signal_templates.py
+++ b/test/1.4/lib/T_signal_templates.py
@@ -4,6 +4,7 @@
 import os
 import simics
 import stest
+import testenv
 
 
 class signal_stub:
@@ -36,7 +37,7 @@ def signal_lower(self):
 stest.expect_equal(stub.level, 1)
 
 # loading a checkpoint doesn't call raise
-cpfile = os.path.join(scratchdir, "checkpoint")
+cpfile = os.path.join(testenv.scratchdir(), "checkpoint")
 simics.SIM_write_configuration_to_file(cpfile, 0)
 simics.SIM_delete_objects([clock, clock.cell, stub, obj])
 simics.SIM_read_configuration(cpfile)
diff --git a/test/1.4/lib/T_transaction.py b/test/1.4/lib/T_transaction.py
index ef5a0c2ec..3794ca5e8 100644
--- a/test/1.4/lib/T_transaction.py
+++ b/test/1.4/lib/T_transaction.py
@@ -1,43 +1,45 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from simics import Sim_PE_No_Exception
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
 
 for b, endian in ((obj.bank.b, 'little'), (obj.bank.be, 'big')):
-    trans = transaction_t(read=True, size=4)
+    trans = simics.transaction_t(read=True, size=4)
     stest.expect_equal((b.iface.transaction.issue(trans, 3), b.read_offset,
                         trans.value_be if endian == 'big' else trans.value_le,
                         b.read_mask, b.read_aux),
-                       (Sim_PE_No_Exception, 3, 4711, 0xffffffff, 1234),
+                       (simics.Sim_PE_No_Exception, 3, 4711, 0xffffffff, 1234),
                        trans.data)
     stest.expect_equal(b.iface.transaction.issue(trans, 13),
-                       Sim_PE_IO_Not_Taken)
+                       simics.Sim_PE_IO_Not_Taken)
 
-    trans = transaction_t(read=True, inquiry=True, size=4)
+    trans = simics.transaction_t(read=True, inquiry=True, size=4)
     stest.expect_equal((b.iface.transaction.issue(trans, 3), b.get_offset,
                         trans.value_be if endian == 'big' else trans.value_le,
                         b.get_size),
-                       (Sim_PE_No_Exception, 3, 4711, 4,))
+                       (simics.Sim_PE_No_Exception, 3, 4711, 4,))
     stest.expect_equal(b.iface.transaction.issue(trans, 13),
-                       Sim_PE_IO_Not_Taken)
+                       simics.Sim_PE_IO_Not_Taken)
 
-    trans = transaction_t(write=True, data=int.to_bytes(4712, 3, endian))
+    trans = simics.transaction_t(write=True, data=int.to_bytes(4712, 3, endian))
     stest.expect_equal((b.iface.transaction.issue(trans, 5),
                         b.write_offset, b.write_value, b.write_mask,
                         b.write_aux),
-                       (Sim_PE_No_Exception, 5, 4712, 0xffffff, 1234))
+                       (simics.Sim_PE_No_Exception, 5, 4712, 0xffffff, 1234))
     stest.expect_equal(b.iface.transaction.issue(trans, 13),
-                       Sim_PE_IO_Not_Taken)
+                       simics.Sim_PE_IO_Not_Taken)
 
-    trans = transaction_t(
+    trans = simics.transaction_t(
         write=True, inquiry=True, data=int.to_bytes(4712, 3, endian))
     stest.expect_equal((b.iface.transaction.issue(trans, 5),
                         b.set_offset, b.set_value, b.set_size),
-                       (Sim_PE_No_Exception, 5, 4712, 3))
+                       (simics.Sim_PE_No_Exception, 5, 4712, 3))
     stest.expect_equal(b.iface.transaction.issue(trans, 13),
-                       Sim_PE_No_Exception)
+                       simics.Sim_PE_No_Exception)
 
     exp_offsets = [17, 24, 32, 0]
     exp_chunks = [(0, 7), (7, 15), (15, 20)]
@@ -46,31 +48,31 @@
                     for (v, sz) in zip(exp_multi_value, (7, 8, 5)))
     exp_value = exp_multi_value[2]
 
-    trans = transaction_t(write=True, inquiry=True, data=data)
+    trans = simics.transaction_t(write=True, inquiry=True, data=data)
     stest.expect_equal((b.iface.transaction.issue(trans, 17),
                         b.set_offset, b.set_value, b.set_size),
-                       (Sim_PE_No_Exception, 32, exp_value, 5))
+                       (simics.Sim_PE_No_Exception, 32, exp_value, 5))
     stest.expect_equal(b.set_multi_value, exp_multi_value)
     stest.expect_equal(b.set_multi_offset, exp_offsets)
 
-    trans = transaction_t(write=True, data=data)
+    trans = simics.transaction_t(write=True, data=data)
     stest.expect_equal((b.iface.transaction.issue(trans, 17),
                         b.write_offset, b.write_value),
-                       (Sim_PE_No_Exception, 32, exp_value))
+                       (simics.Sim_PE_No_Exception, 32, exp_value))
     stest.expect_equal(b.write_multi_value, exp_multi_value)
     stest.expect_equal(b.write_multi_offset, exp_offsets)
 
-    trans = transaction_t(read=True, inquiry=True, size=20)
+    trans = simics.transaction_t(read=True, inquiry=True, size=20)
     stest.expect_equal((b.iface.transaction.issue(trans, 17),
                         b.get_offset, b.get_size),
-                       (Sim_PE_No_Exception, 32, 5))
+                       (simics.Sim_PE_No_Exception, 32, 5))
     stest.expect_equal(b.get_multi_offset, exp_offsets)
     for x, y in exp_chunks:
         stest.expect_equal(int.from_bytes(trans.data[x:y], endian), 4711)
 
-    trans = transaction_t(read=True, size=20)
+    trans = simics.transaction_t(read=True, size=20)
     stest.expect_equal((b.iface.transaction.issue(trans, 17), b.read_offset),
-                       (Sim_PE_No_Exception, 32))
+                       (simics.Sim_PE_No_Exception, 32))
     stest.expect_equal(b.read_multi_offset, exp_offsets)
     for x, y in exp_chunks:
         stest.expect_equal(int.from_bytes(trans.data[x:y], endian), 4711)
diff --git a/test/1.4/lib/T_utility.py b/test/1.4/lib/T_utility.py
index ef6cb6cc6..8783f3d13 100644
--- a/test/1.4/lib/T_utility.py
+++ b/test/1.4/lib/T_utility.py
@@ -4,7 +4,9 @@
 import stest
 import dev_util
 import sim_commands
-import contextlib
+import testenv
+import conf
+obj = testenv.instantiate()
 
 [read_write,
  ignore_write,
diff --git a/test/1.4/methods/T_startup.dml b/test/1.4/methods/T_startup.dml
index f106d24ac..10f050665 100644
--- a/test/1.4/methods/T_startup.dml
+++ b/test/1.4/methods/T_startup.dml
@@ -6,8 +6,6 @@ dml 1.4;
 
 device test;
 
-/// INSTANTIATE-MANUALLY
-
 independent method call_on_startup(const char *name) {
     local attr_value_t args = SIM_make_attr_list(
         1, SIM_make_attr_string(name));
diff --git a/test/1.4/methods/T_startup.py b/test/1.4/methods/T_startup.py
index 46c287c75..484325b23 100644
--- a/test/1.4/methods/T_startup.py
+++ b/test/1.4/methods/T_startup.py
@@ -1,6 +1,7 @@
 # © 2022 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
 
 startup_calls = {'a': 0, 'b': 0}
@@ -10,7 +11,7 @@ def on_startup(name):
     startup_calls[name] += 1
 
 stest.expect_equal(startup_calls, {'a': 0, 'b': 0})
-SIM_load_module('dml-test-startup')
+simics.SIM_load_module('dml-test-startup')
 stest.expect_equal(startup_calls, {'a': 1, 'b': 4})
-obj = SIM_create_object('test', 'obj', [])
+obj = simics.SIM_create_object('test', 'obj', [])
 stest.expect_equal(startup_calls, {'a': 1, 'b': 4})
diff --git a/test/1.4/methods/T_startup_memoized.dml b/test/1.4/methods/T_startup_memoized.dml
index 47cbedd3b..541bf4414 100644
--- a/test/1.4/methods/T_startup_memoized.dml
+++ b/test/1.4/methods/T_startup_memoized.dml
@@ -5,8 +5,6 @@
 dml 1.4;
 device test;
 
-/// INSTANTIATE-MANUALLY
-
 independent method call_on_startup(const char *node, const char *meth) {
     local attr_value_t args = SIM_make_attr_list(
         2, SIM_make_attr_string(node), SIM_make_attr_string(meth));
diff --git a/test/1.4/methods/T_startup_memoized.py b/test/1.4/methods/T_startup_memoized.py
index 02e139d0c..1256ed75d 100644
--- a/test/1.4/methods/T_startup_memoized.py
+++ b/test/1.4/methods/T_startup_memoized.py
@@ -1,6 +1,7 @@
 # © 2022 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import itertools
 import stest
 
@@ -17,7 +18,7 @@ def on_startup(node, meth):
     global startup_calls
     startup_calls[(node, meth)] += 1
 
-SIM_load_module('dml-test-startup_memoized')
+simics.SIM_load_module('dml-test-startup_memoized')
 stest.expect_equal(startup_calls, expected_after_startup)
-obj = SIM_create_object('test', 'obj', [])
+obj = simics.SIM_create_object('test', 'obj', [])
 stest.expect_equal(startup_calls, expected_after_startup)
diff --git a/test/1.4/misc/T_notify_state.py b/test/1.4/misc/T_notify_state.py
index c9a2e219b..9dbe23bd4 100644
--- a/test/1.4/misc/T_notify_state.py
+++ b/test/1.4/misc/T_notify_state.py
@@ -1,11 +1,14 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
 stest.expect_equal(obj.count, 0)
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 # TODO: is this the desired behaviour? attributes not controlled by DML do not
 #       count for the context
 obj.queue = cpu
@@ -24,7 +27,7 @@
 
 stest.expect_equal(obj.count, 3)
 
-SIM_continue(100000)
+simics.SIM_continue(100000)
 
 stest.expect_equal(obj.count, 4)
 
@@ -32,11 +35,11 @@
 
 stest.expect_equal(obj.count, 5)
 
-SIM_notify(obj, SIM_notifier_type("exported-entry"))
+simics.SIM_notify(obj, simics.SIM_notifier_type("exported-entry"))
 
 stest.expect_equal(obj.count, 6)
 
-SIM_notify(obj, SIM_notifier_type("statically-exported-entry"))
+simics.SIM_notify(obj, simics.SIM_notifier_type("statically-exported-entry"))
 
 stest.expect_equal(obj.count, 7)
 
@@ -44,6 +47,6 @@
 
 stest.expect_equal(obj.count, 8)
 
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 
 stest.expect_equal(obj.count, 9)
diff --git a/test/1.4/misc/T_register_view.py b/test/1.4/misc/T_register_view.py
index b501dd008..05f89ae0d 100644
--- a/test/1.4/misc/T_register_view.py
+++ b/test/1.4/misc/T_register_view.py
@@ -2,5 +2,7 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import test_register_view
+import testenv
+obj = testenv.instantiate()
 
 test_register_view.test(obj)
diff --git a/test/1.4/misc/T_register_view_bitorder_be.py b/test/1.4/misc/T_register_view_bitorder_be.py
index d88d227f4..1b67e188c 100644
--- a/test/1.4/misc/T_register_view_bitorder_be.py
+++ b/test/1.4/misc/T_register_view_bitorder_be.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 from stest import expect_true
+import testenv
+obj = testenv.instantiate()
 
-b = SIM_get_port_interface(obj, 'register_view', 'b')
+b = simics.SIM_get_port_interface(obj, 'register_view', 'b')
 expect_true(b.big_endian_bitorder())
diff --git a/test/1.4/misc/T_register_view_bitorder_le.py b/test/1.4/misc/T_register_view_bitorder_le.py
index 99e4ff604..c3f3400f8 100644
--- a/test/1.4/misc/T_register_view_bitorder_le.py
+++ b/test/1.4/misc/T_register_view_bitorder_le.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 from stest import expect_false
+import testenv
+obj = testenv.instantiate()
 
-b = SIM_get_port_interface(obj, 'register_view', 'b')
+b = simics.SIM_get_port_interface(obj, 'register_view', 'b')
 expect_false(b.big_endian_bitorder())
diff --git a/test/1.4/misc/T_register_view_descriptions.py b/test/1.4/misc/T_register_view_descriptions.py
index 1691a7761..f04cf3dc3 100644
--- a/test/1.4/misc/T_register_view_descriptions.py
+++ b/test/1.4/misc/T_register_view_descriptions.py
@@ -2,5 +2,7 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import test_register_view_descriptions
+import testenv
+obj = testenv.instantiate()
 
 test_register_view_descriptions.test(obj)
diff --git a/test/1.4/misc/T_register_view_fields.py b/test/1.4/misc/T_register_view_fields.py
index 1e8e4f7ca..36557bcc8 100644
--- a/test/1.4/misc/T_register_view_fields.py
+++ b/test/1.4/misc/T_register_view_fields.py
@@ -1,11 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-from simics import *
+import simics
 from stest import expect_equal
+import testenv
+obj = testenv.instantiate()
 
 def test(obj):
-    b = SIM_get_port_interface(obj, 'register_view', 'b')
+    b = simics.SIM_get_port_interface(obj, 'register_view', 'b')
 
     expect_equal(b.register_info(0)[4], [['all', '', 0, 31]])
     expect_equal(b.register_info(1)[4], [['ab', '12', 0, 2],
diff --git a/test/1.4/misc/T_register_view_inquiry.py b/test/1.4/misc/T_register_view_inquiry.py
index e9edd7bcf..f684037d1 100644
--- a/test/1.4/misc/T_register_view_inquiry.py
+++ b/test/1.4/misc/T_register_view_inquiry.py
@@ -2,5 +2,7 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import test_register_view_inquiry
+import testenv
+obj = testenv.instantiate()
 
 test_register_view_inquiry.test(obj)
diff --git a/test/1.4/misc/T_register_view_read_only.py b/test/1.4/misc/T_register_view_read_only.py
index 5fe76cdfe..1953a61ef 100644
--- a/test/1.4/misc/T_register_view_read_only.py
+++ b/test/1.4/misc/T_register_view_read_only.py
@@ -3,6 +3,8 @@
 
 from simics import SIM_get_port_interface
 from stest import expect_equal
+import testenv
+obj = testenv.instantiate()
 
 b = SIM_get_port_interface(obj, 'register_view_read_only', 'b')
 expect_equal(b.is_read_only(0), False)
diff --git a/test/1.4/registers/T_inquiry.py b/test/1.4/registers/T_inquiry.py
index de58a6bd5..addb764b0 100644
--- a/test/1.4/registers/T_inquiry.py
+++ b/test/1.4/registers/T_inquiry.py
@@ -1,10 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 from dev_util import Register_LE
 from stest import expect_equal, expect_true, expect_false
+import testenv
+obj = testenv.instantiate()
 
-SIM_run_command("log-level 4")
+simics.SIM_run_command("log-level 4")
 
 aaaa = 0xaaaaaaaaaaaaaaaa
 bbbb = 0xbbbbbbbbbbbbbbbb
diff --git a/test/1.4/registers/T_instrumentation_io_memory.py b/test/1.4/registers/T_instrumentation_io_memory.py
index a08b50b09..8a2a3d14b 100644
--- a/test/1.4/registers/T_instrumentation_io_memory.py
+++ b/test/1.4/registers/T_instrumentation_io_memory.py
@@ -1,7 +1,8 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-import instrumentation_test
 from instrumentation_test import test
+import testenv
+obj = testenv.instantiate()
 
 test(obj)
diff --git a/test/1.4/registers/T_instrumentation_transaction.py b/test/1.4/registers/T_instrumentation_transaction.py
index 7cdef8ed8..8a2a3d14b 100644
--- a/test/1.4/registers/T_instrumentation_transaction.py
+++ b/test/1.4/registers/T_instrumentation_transaction.py
@@ -2,5 +2,7 @@
 # SPDX-License-Identifier: MPL-2.0
 
 from instrumentation_test import test
+import testenv
+obj = testenv.instantiate()
 
 test(obj)
diff --git a/test/1.4/registers/instrumentation_test.py b/test/1.4/registers/instrumentation_test.py
index 31371ad56..67e61eed9 100644
--- a/test/1.4/registers/instrumentation_test.py
+++ b/test/1.4/registers/instrumentation_test.py
@@ -24,6 +24,8 @@
 import instrumentation_remove_connection_callbacks
 
 import stest
+import testenv
+obj = testenv.instantiate()
 
 def test(obj):
     subscribe_b1 = obj.bank.b1.iface.bank_instrumentation_subscribe
diff --git a/test/1.4/saved/T_simple.py b/test/1.4/saved/T_simple.py
index 23012e9c0..2998b6866 100644
--- a/test/1.4/saved/T_simple.py
+++ b/test/1.4/saved/T_simple.py
@@ -1,7 +1,11 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+import conf
+obj = testenv.instantiate()
 
 # check the initial values where applicable
 stest.expect_equal(obj.DML_saved_saved_initialized_int, 5)
@@ -12,16 +16,16 @@
 obj.verify_all_saved = 1
 
 # take checkpoint
-SIM_write_configuration_to_file("init.ckpt", 0)
+simics.SIM_write_configuration_to_file("init.ckpt", 0)
 
 # change values
 obj.modify_all_saved = 3
 # sanity
 obj.verify_all_saved = 3
 
-SIM_delete_objects(SIM_get_all_objects())
+simics.SIM_delete_objects(simics.SIM_get_all_objects())
 
 # load checkpoint, verify values reset
-SIM_read_configuration("init.ckpt")
+simics.SIM_read_configuration("init.ckpt")
 # plain 'obj' reference is dead here
 conf.obj.verify_all_saved = 1
diff --git a/test/1.4/serialize/T_identity_compat.py b/test/1.4/serialize/T_identity_compat.py
index 1e91d00b3..32bcb5aed 100644
--- a/test/1.4/serialize/T_identity_compat.py
+++ b/test/1.4/serialize/T_identity_compat.py
@@ -3,6 +3,8 @@
 
 import stest
 import simics
+import testenv
+obj = testenv.instantiate()
 
 with stest.expect_exception_mgr(simics.SimExc_IllegalValue):
     obj.s = ["test", []]
diff --git a/test/1.4/serialize/T_saved_declaration.py b/test/1.4/serialize/T_saved_declaration.py
index 96c8b3321..ce7fffe80 100644
--- a/test/1.4/serialize/T_saved_declaration.py
+++ b/test/1.4/serialize/T_saved_declaration.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest
+import testenv
+obj = testenv.instantiate()
 
 # Test initial values
 obj.test_initial = None
diff --git a/test/1.4/serialize/T_saved_failure.py b/test/1.4/serialize/T_saved_failure.py
index 836ab8b8e..c3cade854 100644
--- a/test/1.4/serialize/T_saved_failure.py
+++ b/test/1.4/serialize/T_saved_failure.py
@@ -3,6 +3,8 @@
 
 import stest
 import simics
+import testenv
+obj = testenv.instantiate()
 
 with stest.expect_exception_mgr(simics.SimExc_IllegalValue):
     obj.g_saved_objects = [[['g[%u]', [1]], ['dev', []]],
diff --git a/test/1.4/serialize/T_saved_statement.py b/test/1.4/serialize/T_saved_statement.py
index e68a4aea8..add17c24f 100644
--- a/test/1.4/serialize/T_saved_statement.py
+++ b/test/1.4/serialize/T_saved_statement.py
@@ -1,10 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 
 # Needed so that we can check 'after'
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
 # check initial value through attribute
diff --git a/test/1.4/statements/T_immediate_after_basic.py b/test/1.4/statements/T_immediate_after_basic.py
index 812557f07..72250a73d 100644
--- a/test/1.4/statements/T_immediate_after_basic.py
+++ b/test/1.4/statements/T_immediate_after_basic.py
@@ -1,25 +1,28 @@
 # © 2024 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import simics
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
-setup_ev = SIM_register_event("setup_ev", None, Sim_EC_Notsaved,
+setup_ev = simics.SIM_register_event("setup_ev", None, simics.Sim_EC_Notsaved,
                        lambda _o, _d: obj.setup, None, None, None, None)
-test_ev = SIM_register_event("test_ev", None, Sim_EC_Notsaved,
+test_ev = simics.SIM_register_event("test_ev", None, simics.Sim_EC_Notsaved,
                        lambda _o, _d: obj.test, None, None, None, None)
 
 # global context
 _ = obj.setup
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 _ = obj.test
 
 # execution context
-SIM_event_post_cycle(cpu, setup_ev, obj, 0, None)
-SIM_continue(1)
+simics.SIM_event_post_cycle(cpu, setup_ev, obj, 0, None)
+simics.SIM_continue(1)
 _ = obj.test
 
 # global context into execution context
-SIM_event_post_cycle(cpu, test_ev, obj, 0, None)
+simics.SIM_event_post_cycle(cpu, test_ev, obj, 0, None)
 _ = obj.setup
-SIM_continue(1)
+simics.SIM_continue(1)
diff --git a/test/1.4/statements/T_immediate_after_cancel.py b/test/1.4/statements/T_immediate_after_cancel.py
index 812557f07..72250a73d 100644
--- a/test/1.4/statements/T_immediate_after_cancel.py
+++ b/test/1.4/statements/T_immediate_after_cancel.py
@@ -1,25 +1,28 @@
 # © 2024 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+import simics
+import testenv
+obj = testenv.instantiate()
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 obj.queue = cpu
 
-setup_ev = SIM_register_event("setup_ev", None, Sim_EC_Notsaved,
+setup_ev = simics.SIM_register_event("setup_ev", None, simics.Sim_EC_Notsaved,
                        lambda _o, _d: obj.setup, None, None, None, None)
-test_ev = SIM_register_event("test_ev", None, Sim_EC_Notsaved,
+test_ev = simics.SIM_register_event("test_ev", None, simics.Sim_EC_Notsaved,
                        lambda _o, _d: obj.test, None, None, None, None)
 
 # global context
 _ = obj.setup
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 _ = obj.test
 
 # execution context
-SIM_event_post_cycle(cpu, setup_ev, obj, 0, None)
-SIM_continue(1)
+simics.SIM_event_post_cycle(cpu, setup_ev, obj, 0, None)
+simics.SIM_continue(1)
 _ = obj.test
 
 # global context into execution context
-SIM_event_post_cycle(cpu, test_ev, obj, 0, None)
+simics.SIM_event_post_cycle(cpu, test_ev, obj, 0, None)
 _ = obj.setup
-SIM_continue(1)
+simics.SIM_continue(1)
diff --git a/test/1.4/statements/T_immediate_after_entrances.dml b/test/1.4/statements/T_immediate_after_entrances.dml
index e5bc3cf86..113c11efd 100644
--- a/test/1.4/statements/T_immediate_after_entrances.dml
+++ b/test/1.4/statements/T_immediate_after_entrances.dml
@@ -9,8 +9,6 @@ device test;
 import "simics/devs/signal.dml";
 import "simics/simulator/callbacks.dml";
 
-/// INSTANTIATE-MANUALLY
-
 // attributes set/get -- hardcoded
 
 attribute count is uint64_attr {
diff --git a/test/1.4/statements/T_immediate_after_entrances.py b/test/1.4/statements/T_immediate_after_entrances.py
index de244c6d9..651428f0f 100644
--- a/test/1.4/statements/T_immediate_after_entrances.py
+++ b/test/1.4/statements/T_immediate_after_entrances.py
@@ -2,96 +2,94 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest
-import dev_util
 import simics
-from simics import *
 
 class signal_stub:
-    cls = confclass('signal-stub')
+    cls = simics.confclass('signal-stub')
 
     @cls.iface.signal.signal_raise
     def signal_raise(self):
         return obj.iface.signal.signal_raise()
 
-cpu = SIM_create_object("clock", "clock", [["freq_mhz", 1]])
+cpu = simics.SIM_create_object("clock", "clock", [["freq_mhz", 1]])
 
 destroyed_map = {}
 def destroyed(name):
     destroyed_map[name] = destroyed_map.get(name, 0) + 1
 
-obj = SIM_create_object('test', 'obj', queue=cpu, post_inc_attr=None)
+obj = simics.SIM_create_object('test', 'obj', queue=cpu, post_inc_attr=None)
 # objects_finalized will execute immediate afters posted in init(), post_init(),
 # objects_finalized(), and attribute configuration
 stest.expect_equal(obj.count, 4)
 
 obj.count = 0
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 stest.expect_equal(obj.count, 0)
 
 obj.count = 0
 obj.simple_attr = None
 stest.expect_equal(obj.count, 0)
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 stest.expect_equal(obj.count, 1)
 
 obj.count = 0
 obj.iface.signal.signal_raise()
 stest.expect_equal(obj.count, 0)
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 stest.expect_equal(obj.count, 1)
 
 obj.count = 0
 obj.recursive_entry_attr = None
 stest.expect_equal(obj.count, 0)
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 stest.expect_equal(obj.count, 1)
 
 obj.count = 0
-SIM_notify(obj, SIM_notifier_type("static-export"))
+simics.SIM_notify(obj, simics.SIM_notifier_type("static-export"))
 stest.expect_equal(obj.count, 0)
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 stest.expect_equal(obj.count, 1)
 
 obj.count = 0
-SIM_notify(obj, SIM_notifier_type("extern-export"))
+simics.SIM_notify(obj, simics.SIM_notifier_type("extern-export"))
 stest.expect_equal(obj.count, 0)
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 stest.expect_equal(obj.count, 1)
 
 obj.count = 0
-SIM_continue(99999)
+simics.SIM_continue(99999)
 stest.expect_equal(obj.count, 0)
-SIM_continue(1)
+simics.SIM_continue(1)
 stest.expect_equal(obj.count, 1)
-SIM_continue(99999)
+simics.SIM_continue(99999)
 stest.expect_equal(obj.count, 1)
-SIM_continue(1)
+simics.SIM_continue(1)
 stest.expect_equal(obj.count, 2)
 
 obj.post_never_called = None
 # The immediate after posted by the post_never_called write will be warned
 # about and cancelled
 with stest.expect_log_mgr(obj, 'warning', regex='immediate after'):
-    SIM_delete_object(obj)
+    simics.SIM_delete_object(obj)
 
 stest.expect_equal(destroyed_map.get('dev', 0), 1)
 stest.expect_equal(destroyed_map.get('event', 0), 1)
 
 # Make sure that the delayed deallocation of immediate after state doesn't
 # error or segfault
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
 
 # Check that the immediate afters posted during init, post_init, and attribute
-# configuration are cancelled without warning when SIM_add_configuration fails
+# configuration are cancelled without warning when simics.SIM_add_configuration fails
 # late and has to rollback object creation
-conf.sim.warnings_as_errors = True
-with stest.expect_exception_mgr(SimExc_General):
-    SIM_add_configuration(
-        [pre_conf_object('obj1', 'test', queue=cpu, post_never_called=None),
-         pre_conf_object('obj2', 'test', queue=cpu, error_on_post_init=True)],
+simics.conf.sim.warnings_as_errors = True
+with stest.expect_exception_mgr(simics.SimExc_General):
+    simics.SIM_add_configuration(
+        [simics.pre_conf_object('obj1', 'test', queue=cpu, post_never_called=None),
+         simics.pre_conf_object('obj2', 'test', queue=cpu, error_on_post_init=True)],
     None)
 
 stest.expect_equal(destroyed_map.get('dev', 0), 3)
 stest.expect_equal(destroyed_map.get('event', 0), 5)
 
-SIM_process_pending_work()
+simics.SIM_process_pending_work()
diff --git a/test/1.4/statements/T_log.py b/test/1.4/statements/T_log.py
index c1983b13f..e090800fa 100644
--- a/test/1.4/statements/T_log.py
+++ b/test/1.4/statements/T_log.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest
+import testenv
+obj = testenv.instantiate()
 
 try:
     with stest.expect_log_mgr(obj, 'info'):
diff --git a/test/1.4/statements/T_subsequent_log.py b/test/1.4/statements/T_subsequent_log.py
index 55188d12e..c028608f8 100644
--- a/test/1.4/statements/T_subsequent_log.py
+++ b/test/1.4/statements/T_subsequent_log.py
@@ -1,8 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-import simics
+import sim_commands
 import stest
+import testenv
+obj = testenv.instantiate()
 
 obj.log_level = 1
 
diff --git a/test/1.4/structure/T_connect_array.py b/test/1.4/structure/T_connect_array.py
index c83d3ec74..d55372d48 100644
--- a/test/1.4/structure/T_connect_array.py
+++ b/test/1.4/structure/T_connect_array.py
@@ -3,6 +3,8 @@
 
 import stest
 import dev_util
+import testenv
+obj = testenv.instantiate()
 
 stest.expect_equal(obj.c, [[None, None, None], [None, None, None]])
 
diff --git a/test/1.4/structure/T_connect_doc.py b/test/1.4/structure/T_connect_doc.py
index b0473d46d..2c903f1a0 100644
--- a/test/1.4/structure/T_connect_doc.py
+++ b/test/1.4/structure/T_connect_doc.py
@@ -1,6 +1,8 @@
 # © 2026 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 import stest
+import testenv
+obj = testenv.instantiate()
 
 attr_doc = {name: doc for (name, _, doc, _) in obj.attributes}
 
diff --git a/test/1.4/structure/T_loggroup.py b/test/1.4/structure/T_loggroup.py
index bc55cd54b..e5ed9941d 100644
--- a/test/1.4/structure/T_loggroup.py
+++ b/test/1.4/structure/T_loggroup.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest
+import testenv
+obj = testenv.instantiate()
 
 stest.expect_equal(set(obj.log_groups), {
     'Default_Log_Group', 'Register_Read', 'Register_Write', 'abc_4711'})
diff --git a/test/1.4/structure/T_subobjs.py b/test/1.4/structure/T_subobjs.py
index 6e24c9e37..44cbf9f4e 100644
--- a/test/1.4/structure/T_subobjs.py
+++ b/test/1.4/structure/T_subobjs.py
@@ -2,6 +2,8 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import stest
+import testenv
+obj = testenv.instantiate()
 
 with stest.expect_log_mgr(obj.port.p[1], 'info'):
     obj.port.p[1].pa = 3
diff --git a/test/1.4/structure/T_trait_largearray.dml b/test/1.4/structure/T_trait_largearray.dml
index aa9f0c94a..1d179d671 100644
--- a/test/1.4/structure/T_trait_largearray.dml
+++ b/test/1.4/structure/T_trait_largearray.dml
@@ -4,7 +4,6 @@
 */
 dml 1.4;
 
-/// INSTANTIATE-MANUALLY
 device test;
 
 // vtable size: 8 bytes
diff --git a/test/1.4/structure/T_trait_largearray.py b/test/1.4/structure/T_trait_largearray.py
index 0873ca230..8ed8ed8f9 100644
--- a/test/1.4/structure/T_trait_largearray.py
+++ b/test/1.4/structure/T_trait_largearray.py
@@ -1,17 +1,18 @@
 # © 2022 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 from simicsutils.host import is_windows
 if is_windows():
     # resource module only available on linux
-    SIM_create_object('test', 'obj', [])
+    simics.SIM_create_object('test', 'obj', [])
     exit(0)
 
 import resource
 import stest
 
 before = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
-SIM_create_object('test', 'obj', [])
+simics.SIM_create_object('test', 'obj', [])
 after = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
 print(after - before)
 stest.expect_true(after - before < 1024)
diff --git a/test/bugs/T_15852.py b/test/bugs/T_15852.py
index 41133c2fc..685cd0304 100644
--- a/test/bugs/T_15852.py
+++ b/test/bugs/T_15852.py
@@ -1,9 +1,12 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
 import stest
+import testenv
+obj = testenv.instantiate()
 # Test that all banks get the int_register interface, no matter if
 # they are mappable or not
 for bank in ('b1', 'b2', 'b3'):
-    print(SIM_get_port_interface(obj, 'int_register', bank))
+    print(simics.SIM_get_port_interface(obj, 'int_register', bank))
 stest.expect_true(obj.runtest)
diff --git a/test/bugs/T_17423.py b/test/bugs/T_17423.py
index 755a78c50..6d4c13a45 100644
--- a/test/bugs/T_17423.py
+++ b/test/bugs/T_17423.py
@@ -1,10 +1,13 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
+import testenv
+obj = testenv.instantiate()
 obj.log_level = 4
 print(obj)
-cpu = SIM_create_object("clock", "cpu", [["freq_mhz", 1]])
-mem = SIM_create_object("memory-space", "mem",
+cpu = simics.SIM_create_object("clock", "cpu", [["freq_mhz", 1]])
+mem = simics.SIM_create_object("memory-space", "mem",
                         [["map", [[0, [obj, 'bank0'], 0, 0, 0x10]]]])
 
 reg_vals = (0xfa1afe1, 0xbabe, 0xabba)
@@ -15,7 +18,7 @@
 try:
     mem.iface.memory_space.write(cpu, 0, (0 , 1), 0)
     raise Exception("expected nothing-is-mapped error")
-except SimExc_Memory:
+except simics.SimExc_Memory:
     if (obj.bank0_REG1 != reg_vals[0] or obj.bank0_REG2 != reg_vals[1] 
         or obj.bank0_REG3 != reg_vals[2]):
         raise Exception("expect registers 1-3 to be unchanged")
diff --git a/test/bugs/T_17729.py b/test/bugs/T_17729.py
index d5cc42383..6b12e64fa 100644
--- a/test/bugs/T_17729.py
+++ b/test/bugs/T_17729.py
@@ -3,6 +3,8 @@
 
 import stest
 import dev_util
+import testenv
+obj = testenv.instantiate()
 
 regs = [[dev_util.Register((obj, 'b', i*2 + j*5), size = 1)
          for j in range(2)]
diff --git a/test/bugs/T_4873.py b/test/bugs/T_4873.py
index 87db72992..5e709bd77 100644
--- a/test/bugs/T_4873.py
+++ b/test/bugs/T_4873.py
@@ -1,7 +1,10 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-mem = SIM_create_object("memory-space", "mem",
+import simics
+import testenv
+obj = testenv.instantiate()
+mem = simics.SIM_create_object("memory-space", "mem",
                         [["map", [[0, obj, 0, 0, 0x10000, None, 0, 8192]]]])
 
 obj.log_level = 4
@@ -23,21 +26,21 @@
 # Not all parts of the FIR register are implemented
 if r1 + r2 + r3 != (1,2,3,4,5,6,7,8,9,10,11,12):
     print("Wrong registers values")
-    SIM_quit(1)
+    simics.SIM_quit(1)
 
 # Now read an overlapping range
 try:
     r1r2 = mem.iface.memory_space.read(None, 2, 4, 0)
     print("Didn't get expected exception when reading r1r2")
     print("r1r2 = %s" % (r1r2,))
-    SIM_quit(1)
-except SimExc_Memory:
+    simics.SIM_quit(1)
+except simics.SimExc_Memory:
     print("Got expected exception when reading r1r2")
 
 try:
     r2r3 = mem.iface.memory_space.read(None, 6, 4, 0)
     print("Didn't get expected exception when reading r2r3")
     print("r1r2 = %s" % (r2r3,))
-    SIM_quit(1)
-except SimExc_Memory:
+    simics.SIM_quit(1)
+except simics.SimExc_Memory:
     print("Got expected exception when reading r2r3")
diff --git a/test/bugs/T_5878.py b/test/bugs/T_5878.py
index d8349bdc8..28b7167bb 100644
--- a/test/bugs/T_5878.py
+++ b/test/bugs/T_5878.py
@@ -1,12 +1,15 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
+import simics
+import testenv
+obj = testenv.instantiate()
 obj.log_level = 4
-cpu = SIM_create_object("clock", "cpu", [["freq_mhz", 1]])
-mem = SIM_create_object("memory-space", "mem",
+cpu = simics.SIM_create_object("clock", "cpu", [["freq_mhz", 1]])
+mem = simics.SIM_create_object("memory-space", "mem",
                         [["map", [[0, obj, 0, 0, 0x10]]]])
 try:
     mem.iface.memory_space.write(cpu, 0, (1,2,3,4), 0)
     raise Exception("expected nothing-is-mapped error")
-except SimExc_Memory:
+except simics.SimExc_Memory:
     pass
diff --git a/test/common/instrumentation_access_value_at_miss.py b/test/common/instrumentation_access_value_at_miss.py
index a41177368..2532affa2 100644
--- a/test/common/instrumentation_access_value_at_miss.py
+++ b/test/common/instrumentation_access_value_at_miss.py
@@ -2,7 +2,6 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import dev_util
-import simics
 import stest
 
 def expect_error(connection, access, handle, obj):
diff --git a/test/common/instrumentation_callback_args.py b/test/common/instrumentation_callback_args.py
index 5b14505ed..d25961d2d 100644
--- a/test/common/instrumentation_callback_args.py
+++ b/test/common/instrumentation_callback_args.py
@@ -2,7 +2,6 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import dev_util
-import simics
 import stest
 
 import instrumentation_common as common
diff --git a/test/common/instrumentation_callback_inquiry.py b/test/common/instrumentation_callback_inquiry.py
index b6bd46e44..ce7b5ef35 100644
--- a/test/common/instrumentation_callback_inquiry.py
+++ b/test/common/instrumentation_callback_inquiry.py
@@ -2,7 +2,6 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import dev_util
-import simics
 import stest
 
 def test_inquiry(register_callback, remove_callback,
diff --git a/test/common/instrumentation_connection_order.py b/test/common/instrumentation_connection_order.py
index ce8975520..a590670f9 100644
--- a/test/common/instrumentation_connection_order.py
+++ b/test/common/instrumentation_connection_order.py
@@ -1,7 +1,6 @@
 # © 2021 Intel Corporation
 # SPDX-License-Identifier: MPL-2.0
 
-import dev_util
 import stest
 
 import instrumentation_common as common
diff --git a/test/common/instrumentation_endianness.py b/test/common/instrumentation_endianness.py
index 1e93e67b9..cd9b9d64f 100644
--- a/test/common/instrumentation_endianness.py
+++ b/test/common/instrumentation_endianness.py
@@ -2,7 +2,6 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import dev_util
-import simics
 import stest
 
 def expect_value(value):
diff --git a/test/common/instrumentation_endianness_overlapping.py b/test/common/instrumentation_endianness_overlapping.py
index 2125e9259..a8adcd98b 100644
--- a/test/common/instrumentation_endianness_overlapping.py
+++ b/test/common/instrumentation_endianness_overlapping.py
@@ -2,7 +2,6 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import dev_util
-import simics
 import stest
 
 def expect_value(value):
diff --git a/test/common/instrumentation_remove_connection_callbacks.py b/test/common/instrumentation_remove_connection_callbacks.py
index fd37fe160..b5957d77a 100644
--- a/test/common/instrumentation_remove_connection_callbacks.py
+++ b/test/common/instrumentation_remove_connection_callbacks.py
@@ -2,7 +2,6 @@
 # SPDX-License-Identifier: MPL-2.0
 
 import dev_util
-import simics
 import stest
 
 import instrumentation_common as common
diff --git a/test/common/testenv.py b/test/common/testenv.py
new file mode 100644
index 000000000..9acbb7b18
--- /dev/null
+++ b/test/common/testenv.py
@@ -0,0 +1,15 @@
+# © 2021 Intel Corporation
+# SPDX-License-Identifier: MPL-2.0
+
+# Test environment parameters injected by the test runner.
+# Test scripts should import this module and call the functions below.
+_scratchdir: str = ''
+
+
+def scratchdir() -> str:
+    return _scratchdir
+
+
+def instantiate():
+    import simics
+    return simics.SIM_create_object('test', 'obj', [])
diff --git a/test/tests.py b/test/tests.py
index 922ac4ab1..4dc0372af 100644
--- a/test/tests.py
+++ b/test/tests.py
@@ -484,7 +484,6 @@ class TestFlags:
         cc_flags: list[str] = dataclasses.field(default_factory=list)
         dmlc_flags: list[str] = dataclasses.field(default_factory=list)
         api_version: str = default_api_version
-        instantiate_manually: bool = False
         compile_only: bool = False
         no_cc: bool = False
 
@@ -540,8 +539,6 @@ def test_flags(self, filename=None, append_to=None):
                 flags.cc_flags.append(data)
             elif key == 'GREP':
                 flags.exp_stdout.append(data)
-            elif key == 'INSTANTIATE-MANUALLY':
-                flags.instantiate_manually = True
             elif key == 'COMPILE-ONLY':
                 flags.compile_only = True
             elif key == 'NO-CC':
@@ -666,7 +663,7 @@ def run_linker(self):
             self.pr("LD: %r" % args)
         return status
 
-    def run_simics(self, pyfile=None, auto_instantiate=True):
+    def run_simics(self, pyfile=None):
         name = self.shortname
         self.simics_stdout = join(self.scratchdir, name+'.simics_stdout')
         self.simics_stderr = join(self.scratchdir, name+'.simics_stderr')
@@ -675,16 +672,13 @@ def run_simics(self, pyfile=None, auto_instantiate=True):
         sc = open(self.scriptname, "w")
         #sc.write("print conf.sim.module_searchpath\n")
         #sc.write("run_command('list-modules')\n")
-        sc.write("testname = %r\n" % self.shortname)
         sc.write("scratchdir = %r\n" % self.scratchdir)
-        sc.write("basedir = %r\n" % join(os.path.dirname(self.filename)))
+        sc.write("import sys\n")
+        sc.write("sys.path.insert(0, %r)\n" % join(os.getcwd(), 'common'))
+        sc.write("import testenv\n")
+        sc.write("testenv._scratchdir = scratchdir\n")
         sc.write("SIM_add_module_dir(scratchdir)\n")
         sc.write("SIM_module_list_refresh()\n")
-        if auto_instantiate:
-            sc.write(f"SIM_load_module('dml-test-{self.shortname}')\n")
-            sc.write("obj = SIM_create_object('test', 'obj', [])\n")
-        else:
-            assert pyfile
 
         if pyfile:
             sc.write("print('running', %r)\n" % pyfile)
@@ -694,6 +688,7 @@ def run_simics(self, pyfile=None, auto_instantiate=True):
             sc.write("sys.path.append(%r)\n" % os.path.dirname(pyfile))
             sc.write("SIM_source_python(%r)\n" % pyfile)
         elif self.fullname.startswith(('1.2/', 'bugs/')):
+            sc.write('obj = testenv.instantiate()\n')
             sc.write("if not obj.runtest:\n")
             sc.write("    print('test attribute returned false')\n")
             sc.write("    SIM_quit(1)\n")
@@ -780,8 +775,7 @@ def test(self):
             return
 
         # Run simics
-        status = self.runlog("Simics", lambda: self.run_simics(
-            pyfile, not self.flags.instantiate_manually))
+        status = self.runlog("Simics", lambda: self.run_simics(pyfile))
         if status != 0:
             self.print_logs('simics', self.simics_stdout, self.simics_stderr)
             raise TestFail("simics status=%d" % status)
@@ -804,9 +798,9 @@ def test(self):
 
 class XmlTestCase(CTestCase):
     __slots__ = ()
-    def run_simics(self, pyfile=None, auto_instantiate=True):
+    def run_simics(self, pyfile=None):
         os.rename('%s.xml' % self.cfilename, join(self.scratchdir, 'test.xml'))
-        return CTestCase.run_simics(self, pyfile, auto_instantiate)
+        return CTestCase.run_simics(self, pyfile)
 
 class DMLCProfileTestCase(CTestCase):
     __slots__ = ()
diff --git a/validate_md_links.py b/validate_md_links.py
index b37488c83..41fadbf68 100644
--- a/validate_md_links.py
+++ b/validate_md_links.py
@@ -6,7 +6,6 @@
 import re
 import json
 import functools
-import traceback
 
 def lookup(f, dirs):
     for d in dirs: