Mini Shell
from guppy.etc.Descriptor import property_nondata
from guppy.gsl.Exceptions import *
class SpecEnv:
def __init__(self, mod):
self.mod = mod
self.imported_packages = {}
self.importing_packages = {}
self.error_reports = []
self.num_errors = 0
self.num_warnings = 0
def errmsg_context(self, context):
linetext = ''
filename = '<unknown file>'
if context is not None:
node = context # Assume it's a node - that's all we use for now
lineno = node.index + 1
src = node.src
if src is not None:
filename = src.filename
linetext = src.get_line(index=context.index)
print('%s:%s:' % (filename, lineno))
if linetext:
print(' %r' % linetext)
def error(self, message, context=None, exception=ReportedError, more=(), harmless=0):
self.error_reports.append(
(message, context, exception, more, harmless))
if harmless:
self.num_warnings += 1
else:
self.num_errors += 1
self.errmsg_context(context)
if harmless:
print('* %s' % message)
else:
print('*** %s' % message)
print()
for msg, ctx in more:
self.errmsg_context(ctx)
print(' %s' % msg)
print()
if self.debug:
import pdb
pdb.set_trace()
else:
if self.num_errors >= self.max_errors:
raise TooManyErrors('Too many errors, giving up')
if exception is not None:
raise exception
def get_filers(self, documents):
filers = []
for d in documents:
filers.extend(d.get_filers(self.output_dir))
return filers
def import_package(self, name, context):
pac = self.imported_packages.get(name)
if pac is None:
if name in self.importing_packages:
self.error('Invalid mutual import involving packages %r' % (
list(self.importing_packages.keys()),), context)
self.importing_packages[name] = 1
filename = name.replace('.', self.mod.IO.path.sep)+'.gsl'
ip = self.package_of_filename(filename, name)
pac = self.mkPackage(ip)
self.imported_packages[name] = pac
del self.importing_packages[name]
return pac
def link_documents(self, documents):
defines = {}
links = {}
def walk(node):
t = node.tag
if t == 'link_to':
name = node.arg.strip()
links.setdefault(name, []).append((d, node))
elif t == 'define':
name = node.arg.strip()
defines.setdefault(name, []).append((d, node))
elif t == 'to_tester_only':
return
for ch in node.children:
walk(ch)
for d in documents:
node = d.get_result()
walk(node)
for name, ds in list(defines.items()):
if len(ds) > 1:
print('Duplicate definition of name %r, defined in:' % name)
for (d, node) in ds:
print(' %s line %s' % (d.get_doc_name(), node.index+1))
print('Will use the first one.')
nodefs = []
for name, ds in list(links.items()):
if name not in defines:
used = {}
for (d, node) in ds:
used[d.get_doc_name()] = 1
node.tag = 'link_to_unresolved'
used = list(used.keys())
used.sort()
used = ', '.join(used)
nodefs.append('%s used in %s' % (name, used))
else:
defd, defnode = defines[name][0]
for (d, node) in ds:
if d is defd:
node.tag = 'link_to_local'
else:
node.tag = 'link_to_extern'
node.children = (defd.doc_name_node,)+node.children
if nodefs:
nodefs.sort()
print('Unresolved links:')
for nd in nodefs:
print(' ', nd)
def mkPackage(self, sub):
pac = PackageDescription(self, sub, sub)
pac.output_dir = self.output_dir
pac.resolve_all()
return pac
def package_of_filename(self, filename, packname=None, nostrip=1, input_string=None):
mod = self.mod
if packname is None:
if filename.endswith('.gsl'):
packname = filename[:-4]
else:
packname = filename
packname = packname.replace(mod.IO.path.sep, '.')
if self.input_dir:
filename = mod.IO.path.join(self.input_dir, filename)
else:
filename = mod.IO.path.abspath(filename)
if input_string is not None:
data = input_string
else:
data = mod.IO.read_file(filename)
md5 = mod.md5()
md5.update(b'.filename: %s\n' % filename.encode('utf-8'))
md5.update(b'.packname: : %s\n' % packname.encode('utf-8'))
md5.update(data.encode('utf-8'))
digest = md5.digest()
if digest in mod.package_cache:
return mod.package_cache[digest]
node = mod.SpecNodes.node_of_string(data, filename, nostrip=nostrip)
numerr = self.num_errors
print('Making package subject %r' % packname)
package = PackageSubject(mod, self, node, packname, filename)
if numerr == self.num_errors:
mod.package_cache[digest] = package
return package
def process_main(self, filename, input_dir=None, output_dir=None, debug=False, max_errors=None,
process_despite_errors=False, raise_at_errors=False,
input_string=None
):
if input_dir is None:
input_dir = self.mod.input_dir
self.input_dir = input_dir
if output_dir is None:
output_dir = '/tmp'
self.output_dir = output_dir
self.debug = debug
if max_errors is None:
max_errors = self.mod.max_errors
self.max_errors = max_errors
try:
pac = self.mkPackage(self.package_of_filename(
filename, input_string=input_string))
documents = pac.get_documents()
if not documents:
self.error('No documents specified.',
exception=None, harmless=1)
if not self.num_errors or process_despite_errors:
print('Linking')
self.link_documents(documents)
if not self.num_errors or process_despite_errors:
filers = self.get_filers(documents)
except TooManyErrors:
giving_up = ' giving up --'
else:
giving_up = ''
if not self.num_errors:
for filer in filers:
f = self.mod.Filer.filer(filer)
print('Writing: ', ', '.join(list(f.writefile_names)))
f.write()
if self.num_warnings:
print('* %d warning%s reported.' % (
self.num_warnings, 's'[:self.num_warnings > 1]))
if self.num_errors:
print('*** %d error%s reported --%s no files written.' % (
self.num_errors, 's'[:self.num_errors > 1], giving_up))
if raise_at_errors:
raise HadReportedError('Some error has been reported.')
class UntypedDescription:
def __init__(self, env, tgt, src):
self.env = env
self.pac = env.pac
self.mod = env.mod
self.tgt = tgt
self.src = src
def combine_with_subject(self, subject):
self.combined_subjects.append(subject)
def resolve_all(self):
self.resolve_primary()
self.resolve_lookuped()
def resolve_primary(self):
self.resolve_type()
self.resolve_tgt()
def resolve_type(self):
dc = self.tgt.description_class
if not hasattr(dc, 'd_tag'):
self.d_tag = self.tgt.tag
self.tgtfullname = self.mod.tgt_prefix+self.tgt.fullname
self.tgtnode = self.tgt.node
self.tgtlastname = self.tgt.lastname
self.srcnode = self.tgt.node
self.srcfullname = self.src.fullname
self.srclastname = self.tgt.lastname
self.__class__ = dc
class Description:
d_max_occur = None # Max occurence as an aspect if a number
d_sub = () # Tags of allowed sub-aspects
d_type = 'other'
d_is_def = 0
is_lookuped = False
is_synthetic = False # Set if it was made not to correspond with a user node
the_less_specific_descr = None
args = ()
def aspects_extend(self, as_):
for asp in as_:
try:
k = asp.src.definame
# k = asp.tgt.definame # Humm
if k:
w = self.localview.get(k)
if w:
if w is asp:
# May happen eg as in test16, for a product
# But it is somewhat mystical.
continue
self.error('Duplicate aspect %r (may be correct in future).' % (k,),
w.src.node,
DuplicateError)
self.localview[k] = asp
bn = self.aspects_by_tag.setdefault(asp.d_tag, [])
oc = asp.d_max_occur
if oc is not None:
if len(bn) + 1 > oc:
self.error('More than %d %r aspects.' % (
oc, asp.d_tag), asp.src.node)
bn.append(asp)
self.aspects.append(asp)
except ReportedError:
pass
def aspects_extend_by_subjects(self, subjects):
for v in subjects:
try:
asp = UntypedDescription(self, v, v)
asp.resolve_primary()
self.aspects_extend((asp,))
except ReportedError:
pass
def deftgt(self, forme=None):
if forme is None:
forme = self
try:
tgtview = self.tgtview
except AttributeError:
self.env.deftgt(forme)
else:
if forme.tgtfullname in tgtview:
self.error('Duplicate definition of %r' %
forme.tgtfullname, forme.src.node)
tgtview[forme.tgtfullname] = forme
def error(self, msg, node=None, exception=ReportedError, **kwds):
return self.pac.env.error(msg, node, exception, **kwds)
def resolve_lookuped(self):
if not self.is_lookuped:
self.is_lookuped = 1
self.resolve_aspects()
def resolve_tgt(self):
self.deftgt()
def find_aspects(self, tag='*', *tags):
al = []
tag = tag.replace(' ', '_')
if tag in ('*', 'arg'):
for a in self.args:
a.resolve_lookuped()
al.append(a)
if tag == '*':
for a in self.aspects:
a.resolve_lookuped()
al.append(a)
return al
tags = (tag,) + tags
for a in self.aspects:
if a.d_tag in tags:
a.resolve_lookuped()
al.append(a)
return al
def find_arg_aspects(self):
al = []
for a in self.args:
a.resolve_lookuped()
al.append(a)
for a in self.aspects:
if a.d_tag in ('arg', 'seq', 'repeat', 'alt', 'args', 'optionals', 'key_arg',
'draw', 'no_arg'):
a.resolve_lookuped()
al.append(a)
return al
def find_kind_aspects(self):
kas = []
for asp in self.find_aspects('*'):
if asp.d_tag in ('attribute', 'mapping', 'kind', 'either', 'kind_of', 'superkind',
'superkind_of'):
kas.append(asp)
else:
pass
return kas
def merge_policy(self, descrs):
return descrs
def get_descr_for_aspect(self, aspect):
if not self.aspects and self.the_less_specific_descr is not None:
return self.the_less_specific_descr.get_descr_for_aspect(aspect)
return self
def get_atom_beams(self):
aspects = self.find_aspects('*')
aks = []
for asp in aspects:
if asp.d_tag in ('attribute', 'mapping', 'either', 'operator',
'inplace_operator', 'reverse_operator', 'function_operator',
'delitem', 'getitem', 'setitem',
):
aks.append(beam(self, asp))
elif asp.d_tag in ('kind', 'kind_of', 'subkind_of') and asp is not self:
a = beam(self, asp)
for b in asp.get_atom_beams():
aks.append(a + b)
return aks
def get_aspects_kind(self, aspects=None):
if aspects is None:
aspects = self.find_aspects('*')
aks = []
for asp in aspects:
if asp.d_tag in ('attribute', 'mapping', 'either',
'operator', 'inplace_operator', 'reverse_operator', 'function_operator',
'delitem', 'getitem', 'setitem',
):
aks.append(asp)
elif asp.d_tag in ('kind', 'kind_of', 'subkind_of') and asp is not self:
aks.extend(asp.get_atom_kinds())
return aks
def get_atom_kinds(self):
return self.get_aspects_kind([self] + self.find_aspects('*'))
def get_examples(self, get_all=False):
examples = []
exs = self.find_aspects('example')
for ex in exs:
examples.extend(ex.get_examples())
return examples
def get_re(self, opt):
if opt.get('get_examples'):
exres = [self.mod.RE.Single(x) for x in self.get_examples()]
if not exres:
self.error('Test coverage error: no examples specified.',
self.tgt.node,
CoverageError)
return self.mod.RE.Union(*exres)
else:
return self.mod.RE.Single(self)
def get_most_specific_descrs(self, descrs):
nds = []
for d in descrs:
nds = [x for x in nds if not d.is_more_specific_than(x)]
for x in nds:
if x is d:
break
if x.is_more_specific_than(d):
break
else:
nds.append(d)
return nds
def get_package(self):
return self.pac
def is_more_specific_than(self, d):
r = self.the_less_specific_descr
return r is d or (r is not None and r.is_more_specific_than(d))
def get_self_name(self):
def find(e):
sa = e.find_aspects('self')
if sa:
# length = 1, has been checked
assert len(sa) == 1
return sa[0].src.node.arg.strip()
if e.d_tag != 'package':
return find(e.env)
return None
return find(self)
def gen_description_doc(self, out):
ds = self.find_aspects('description')
if not ds:
out.gen_text('<NO DESCRIPTION OF %r>' % self.tgtfullname)
else:
for d in ds:
d.gen_doc(out)
def get_id_name(self):
return self.tgtfullname
def get_link_name(self):
return self.tgtfullname
def get_local_name(self):
return self.srclastname
def get_test_name(self):
return self.tgtfullname
def get_name(self):
return self.tgtfullname
def get_Name(self):
# To be used in Name of doc.
n = self.find_aspects('name')
if not n:
name = self.tgtlastname
else:
name = n.tgt.node.arg.strip()
return name
def get_descr_by_subject(self, subject):
return self.pac.get_descr_by_subject(subject)
def init_localview(self, only_vars=0):
self.localview = {}
self.aspects = []
self.aspects_by_tag = {}
if not only_vars:
self.aspects_extend_by_subjects(self.tgt.aspects)
def resolve_aspects(self):
self.init_localview()
if self.src.args:
self.args = [self.env.get_descr_by_subject(
arg) for arg in self.src.args]
self.resolve_special()
def resolve_special(self):
# To be overridden with special checks etc.
pass
def get_the_one_argument(self):
arg = self.src.node.arg.strip()
if self.aspects:
'No children expected for %r' % self.node.tag
return arg
def make_and_test_kind(self, kinds):
ks = []
def flatten(k):
if k.d_tag == 'kind':
for k1 in k.find_kind_aspects():
flatten(k1)
else:
ks.append(k)
if (len(kinds) == 1 and kinds[0].d_tag == 'kind'):
return kinds[0]
for k in kinds:
flatten(k)
kinds = ks
k = Kind()
k.d_tag = 'kind'
k.aspects = kinds
k.tgtfullname = '(%s)' % ('&'.join([x.tgtfullname for x in kinds]))
k.is_lookuped = 1
return k
def make_and_kind(self, kinds):
if (len(kinds) == 1 and kinds[0].d_tag in('kind', 'kind_of')):
return kinds[0]
k = Kind()
k.d_tag = 'kind'
k.aspects = kinds
k.tgtfullname = '(%s)' % ('&'.join([x.tgtfullname for x in kinds]))
k.is_lookuped = True
k.is_synthetic = True
return k
def make_or_kind(self, kinds):
if len(kinds) == 1:
return kinds[0]
else:
k = Superkind()
k.d_tag = 'kind'
k.aspects = kinds
k.tgtfullname = '(%s)' % ('|'.join([x.tgtfullname for x in kinds]))
k.is_lookuped = True
k.is_synthetic = True
return k
class Definition(Description):
d_is_def = 1
d_type = 'definition'
def export_aspects(self, src):
src.__class__ = self.__class__
if src.d_tag == 'import':
src.d_tag = self.d_tag
else:
if src.d_tag != self.d_tag:
# Can't think of how this would happen -
# so not yet converted to .error()
raise ImportError('Different description tag')
src.aspects_extend(self.aspects)
class DescriptionDescription(Description):
d_sub = ('text', )
d_tag = 'description'
def gen_doc(self, out):
self.srcnode.arg_accept(out)
class Default(DescriptionDescription):
def gen_doc(self, out):
arglines = self.srcnode.arg.strip().split('\n')
default = arglines[0]
rest = '\n'.join(arglines[1:])
out.open('dl')
out.open('dt')
out.open('strong')
out.gen_text('Default: ')
out.close()
out.gen_text(default)
out.close()
out.open('dd')
out.gen_text(rest)
self.srcnode.children_accept(out)
out.close()
out.close('dl')
class DescriptionWithHeader(DescriptionDescription):
def gen_doc(self, out):
arglines = self.srcnode.arg.strip().split('\n')
header = arglines[0]
rest = '\n'.join(arglines[1:])
out.open('dl')
out.gen_outer_dt(header)
out.open('dd')
out.gen_text(rest)
self.srcnode.children_accept(out)
out.close()
out.close()
class Comment(DescriptionDescription):
d_tag = 'comment'
pass
class Either(Description):
d_type = 'with_args'
def get_atom_beams(self):
return [beam(self)]
def get_atom_kinds(self):
return [self]
def get_alt_kinds(self):
return self.find_kind_aspects()
class Import(Definition):
d_sub = ('from', 'resolve_by', 'using',
'attribute', 'condition', 'description', 'comment', 'constructor',
'mapping', 'method',
'operator', 'inplace_operator', 'reverse_operator', 'function_operator',
'delitem', 'getitem', 'setitem',
'self',
'subkind_of',
)
def resolve_tgt(self):
self.is_lookuped = 1
using_name, using_node = self.src.imp_using_map.get(
self.src.definame, (self.src.definame, self.src.node))
import_node = self.src.node
ds = [self.pac.import_package(from_name, from_node).
get_descr_by_name(using_name, using_node)
for (from_name, from_node) in self.src.imp_froms]
if len(ds) == 1:
d = ds[0]
else:
d = Product(self, ds, ProductSubject([x.src for x in ds]),
self.src.imp_resolve_mode)
self.tgt = d.tgt
self.tgtfullname = self.mod.tgt_prefix+self.tgt.fullname
self.the_less_specific_descr = d
self.init_localview(only_vars=1)
d.export_aspects(self)
self.aspects_extend_by_subjects(self.src.aspects)
self.deftgt()
def resolve_aspects(self):
pass
class Product(Description):
def __init__(self, env, ds, src, mode):
self.env = env
self.mod = env.mod
self.src = src
self.mode = mode
self.pac = env.pac
tgt = ds[0].tgt
for d in ds[1:]:
if d.tgt is not tgt:
self.error('Import error when importing from multiple packages:\n' +
' Can not make a product of %r (tgt = %r) with %r (tgt = %r)\n' % (
d.src.fullname, d.tgt.fullname, ds[0].src.fullname, ds[0].tgt.fullname) +
' because of different targets.',
d.src.node)
self.tgt = tgt
self.ds = ds
def export_aspects(self, src):
for d in self.ds:
d.export_aspects(src)
def is_more_specific_than(self, d):
for x in self.ds:
if x is d or x.is_more_specific_than(d):
return True
return False
class PackageDescription(UntypedDescription):
def __init__(self, env, tgt, src):
self.env = env
self.pac = self
self.mod = env.mod
self.tgt = tgt
self.src = src
class ErrorDescription:
d_tag = 'error'
def __init__(self, env):
self.env = env
def get_id_name(self):
return '<error>.<error>'
class Package(Description):
d_sub = ('and', 'comment', 'condition', 'document', 'import', 'kind', 'macro',
'superkind',
)
def get_tgtdicts(self):
seen = {id(self.tgtview): 1}
tgtdicts = [self.tgtview]
for p in list(self.imported_packages.values()):
sds = p.get_tgtdicts()
for sd in sds:
if id(sd) not in seen:
seen[id(sd)] = 1
tgtdicts.append(sd)
return tgtdicts
def get_descr_by_name(self, name, context=None):
if name.startswith(self.mod.tgt_prefix):
return self.get_descr_by_tgt_name(name, context)
e = self
parts = name.split('.')
for part in parts:
try:
e = e.localview[part]
except KeyError:
assert context
self.env.error(
'Undefined: %r in %r.' % (part, e.get_id_name()), context,
exception=UndefinedError)
e.resolve_lookuped()
return e
def get_descr_by_subject(self, subject):
name = subject.fullname
if name.startswith(self.srcfullname+'.'):
name = name[len(self.srcfullname)+1:].strip()
else:
self.error('Undefined: %r' % name, subject.node)
return self.get_descr_by_name(name, subject.node)
def get_descr_by_tgt_name(self, name, context=None):
tgtdicts = self.get_tgtdicts()
descrs = []
for tgtdict in tgtdicts:
if name in tgtdict:
d = tgtdict[name]
d.resolve_lookuped()
d = d.get_descr_for_aspect('*')
descrs.append(d)
if not descrs:
self.error('No definition of tgt %r' %
name, context, UndefinedError)
descrs = self.get_most_specific_descrs(descrs)
if len(descrs) > 1:
descrs = self.merge_policy(descrs)
if len(descrs) > 1:
self.error('Conflicting descriptions of %r:%r' % (
name, [d.src.fullname for d in descrs]),
context,
DuplicateError)
return descrs[0]
def get_filename(self):
return self.src.filename
def get_package(self):
return self
def resolve_tgt(self):
self.tgtview = {}
def resolve_aspects(self):
self.imported_packages = {}
self.init_localview()
def import_package(self, name, context):
pac = self.imported_packages.get(name)
if pac is None:
pac = self.env.import_package(name, context)
self.imported_packages[name] = pac
return pac
def get_documents(self):
documents = []
for doc in self.src.documents:
node = doc.node
doc = self.mod.Document.document(node, self)
documents.append(doc)
return documents
class Attribute(Definition):
d_sub = ('attribute', 'comment', 'description', 'description_with_header',
'either', 'kind_of', 'mapping', 'method', 'self')
def export_aspects(self, src):
src.__class__ = self.__class__
src.aspects_extend(self.aspects)
def get_attr_name(self):
return self.tgtlastname
def get_name(self):
return self.tgtlastname
def get_kind(self):
kas = self.find_kind_aspects()
return self.make_and_kind(kas)
def get_kind_name(self):
k = self.get_kind()
if k.d_tag == 'kind_of':
kas = k.find_kind_aspects()
if len(kas) == 1:
k = kas[0]
else:
raise ValueError("Don't know how to name this kind, %r" % self)
return k.tgtfullname
def get_link_name(self):
# xxx needs smoother logic
s = '%s.%s' % (self.get_descr_by_subject(
self.tgt.parent).get_link_name(), self.tgt.lastname)
return s
def get_test_kind(self):
kas = self.find_kind_aspects()
return self.make_and_test_kind(kas)
def is_method(self):
return (self.find_aspects('mapping') and
not self.find_aspects('kind_of'))
def get_op_name(self):
return self.get_attr_name()
class KindOf(Description):
d_type = 'with_args'
d_sub = ()
class SubkindOf(Description):
d_type = 'with_args'
d_sub = ('description',)
class Kind(Definition):
d_sub = ('attribute', 'condition', 'description', 'comment', 'constructor',
'example',
'mapping', 'method',
'operator', 'inplace_operator', 'reverse_operator', 'function_operator',
'self',
'subkind_of',
'delitem', 'getitem', 'setitem',
)
def get_attributes(self):
return self.find_aspects('attribute')
def get_mappings(self):
return self.find_aspects('mapping')
class Superkind(Definition):
d_sub = ('comment', 'description', 'example', 'superkind_of')
def get_local_name(self):
return self.srclastname
class SuperkindOf(Description):
d_type = 'with_args'
def get_examples(self, enough=1):
examples = Description.get_examples(self, enough)
if len(examples) < enough:
for ka in self.find_kind_aspects():
if ka is self:
continue
examples.extend(ka.get_examples(enough-len(examples)))
if len(examples) >= enough:
break
return examples
class Example(Description):
d_sub = ('comment', 'description', 'in_context')
partab = {"'''": "'''",
'"""': '"""',
'(': ')',
'[': ']',
'{': '}'
}
def get_ex_text(self):
return self.src.ex_text
def get_examples(self, get_all=False):
return [self]
def get_ctx_text(self):
asp = self.find_aspects('in_context')
if not asp:
return ''
# It is of length 1, has been checked.
return asp[0].tgt.node.arg.strip()
def get_use_text(self, x):
return x
class InContext(Description):
d_max_occur = 1
class Defines(Description):
d_type = 'with_args'
def get_defined_tgt_names(self):
return [x.tgtfullname for x in self.find_aspects('arg')]
class Macro(Definition):
def export_aspects(self, src):
src.__class__ = self.__class__
src.tgtnode = self.tgtnode
def use(self, options):
return self.mod.SpecNodes.node_of_taci(
'block', '', self.tgtnode.children, self.tgtnode.index)
class Self(Description):
d_max_occur = 1
class Mapping(Description):
d_type = 'other'
d_sub = ('alt', 'arg', 'args', 'comment', 'description', 'description_with_header',
'equation',
'draw',
'key_arg',
'optionals',
'precondition', 'postcondition',
'repeat', 'returns',
'self',
'seq',
)
def chk_num_args(self, min, max):
re = self.get_args_re({})
xs = re.sequni()
for x in xs:
try:
if min is not None and min == max and len(x) != min:
self.error(
'%s requires %d argument%s specified, got %d.' % (
self.d_tag, min, 's'[min == 1:], len(x)),
self.src.node)
elif min is not None and len(x) < min:
self.error(
'%s requires at least %d argument%s specified, got %d.' % (
self.d_tag, min, 's'[min == 1:], len(x)),
self.src.node)
elif max is not None and len(x) > min:
self.error(
'%s can take at most %d argument%s specified, got %d.' % (
self.d_tag, max, 's'[max == 1:], len(x)),
self.src.node)
except ReportedError:
pass
def get_arg_kinds(self):
ak = []
for a in self.find_aspects('args'):
ak.extend(list(a.args))
return ak
def get_args_examples(self, mapname, top_kind):
# Get arguments example, esp. for test purposes
try:
opt = {'get_examples': True}
re = self.get_args_re(opt)
coverage = 1
try:
xs = re.sequni()
except self.mod.RE.InfiniteError:
print('Infinitely long args example for %s' % self.srcfullname)
print(
'Limiting by expanding each Cleene closure 0 up to %d times.' % coverage)
re = re.limited(coverage)
xs = re.sequni()
examples = [ArgsExample(self, tuple(
x), mapname, top_kind) for x in xs]
except CoverageError:
return []
else:
return examples
def get_args_for_args(self, args, match):
arglist = []
for a in self.find_arg_aspects():
t = a.d_tag
if t == 'arg':
name = a.get_name()
if name in match:
v = args.get_arg_value(match[name])
else:
ex = a.get_examples()
if not ex:
# I have been able to cause this to happen in test67.
self.error(
'Test coverage error: Can not create precondition for %r\n -- no examples specified for the argument above.' % args.mapping.tgtfullname,
a.src.node
)
v = ex[0]
arglist.append(v)
else:
assert 0
# raise ConditionError, 'Can not match this precondition'
return ArgsExample(self, tuple(arglist), args.mapname, args.top_kind)
def get_args_re(self, opt):
re = self.mod.RE.Epsilon
for a in self.find_arg_aspects():
re += a.get_re(opt)
return re
def get_arguments(self):
# Get the arguments subjects, for doc description purposes
return self.find_arg_aspects()
def get_return_kind(self):
return self.make_and_kind([x.get_kind() for x in self.find_aspects('returns')])
def get_return_test_kind(self):
return self.make_and_test_kind([x.get_test_kind() for x in self.find_aspects('returns')])
class ArgsExample:
def __init__(self, mapping, egs, mapname, top_kind):
self.mapping = mapping
self.egs = egs
self.mapname = mapname
self.top_kind = top_kind
self.negs = [mapname(x) for x in egs]
def __str__(self):
return ', '.join(self.negs)
def get_arg_value(self, name):
i = 0
for a in self.mapping.find_arg_aspects():
t = a.d_tag
if t == 'arg':
if a.get_name() == name:
return self.egs[i]
else:
raise ConditionError('No argument matches: %r' % name)
i += 1
def get_preconditions(self):
return self.mapping.find_aspects('precondition')
def get_postconditions(self):
return self.mapping.find_aspects('postcondition')
def get_setups_for_preconditions(self):
pres = self.get_preconditions()
if not pres:
return []
kind = self.top_kind
map = self.mapping
pres = map.find_aspects('precondition')
if pres:
for a in kind.find_aspects('attribute'):
for m in a.find_aspects('mapping'):
mpre = m.find_aspects('precondition')
if mpre:
continue
match = self.match_to(m.find_aspects('postcondition'))
if match is not None:
# found one
args = m.get_args_for_args(self, match)
return [SetUp(a.get_attr_name(), args)]
break
else:
continue
break
else:
# Caller will do error reporting
return None
return []
def match_to_kind(self, kind):
pass
def match_to(self, posts):
match = {}
for pre in self.get_preconditions():
for pos in posts:
if pos.cond_id == pre.cond_id:
if len(pos.arg_names) != len(pre.arg_names):
continue
upd = {}
for a, b in zip(pos.arg_names, pre.arg_names):
if a in match:
break
upd[a] = b
else:
match.update(upd)
break
else:
return None
assert ',' not in match
return match
class SetUp:
def __init__(self, name, args):
self.name = name
self.args = args
def get_name(self):
return self.name
def get_args(self):
return self.args
class Operator(Mapping):
d_is_def = 1
d_type = 'operator'
d_sub = ('arg', 'comment', 'description', 'description_with_header',
'equation',
'postcondition', 'precondition',
'self', 'returns', )
def get_op_name(self):
return self.src.node.arg.strip()
def resolve_special(self):
self.chk_num_args(1, 1)
class ReverseOperator(Operator):
pass
class FunctionOperator(Operator):
def resolve_special(self):
self.chk_num_args(0, 0)
class InplaceOperator(Operator):
pass
class SetItem(Mapping):
d_type = 'other'
d_sub = ('arg', 'comment', 'description', 'description_with_header',
'equation',
'postcondition', 'precondition',
'self')
def get_op_name(self):
return '[]'
def resolve_special(self):
self.chk_num_args(2, None)
class DelItem(SetItem):
def resolve_special(self):
self.chk_num_args(1, None)
class GetItem(SetItem):
d_sub = SetItem.d_sub + ('returns', )
def resolve_special(self):
self.chk_num_args(1, None)
class Condition(Description):
d_is_def = 1
d_sub = ('self', 'arg', 'comment', 'description', 'python_code')
def get_arg_names(self):
an = []
for a in self.find_aspects('*'):
if a.d_tag in ('self', 'arg'):
an.append(a.src.node.arg.strip())
return an
def get_def_name(self):
dn = self.src.lastname
return dn
def_name = property(get_def_name)
class PythonCode(Description):
d_sub = ('comment', 'description', 'in_context')
class ConditionRef(Description):
d_sub = ('comment', 'description',)
def __repr__(self):
try:
return self.cond_expr
except AttributeError:
return Description.__repr__(self)
def get_cond_id(self):
cond_id = self.cond_definition.tgtfullname
if self.is_not:
cond_id = 'not ' + cond_id
self.cond_id = cond_id
return cond_id
cond_id = property_nondata(get_cond_id)
def get_definition(self):
return self.cond_definition
def resolve_special(self):
cond_def = self.src.cond_definition
self.cond_definition = self.env.get_descr_by_subject(cond_def)
self.cond_doc_name = cond_def.parent.lastname + '.' + cond_def.lastname
self.cond_expr = self.src.node.arg.strip() # Mostly for information
self.arg_names = self.src.arg_names
self.is_not = self.src.is_not
class Precondition(ConditionRef):
#doc_name = 'Before'
doc_name = 'Precondition'
class Postcondition(ConditionRef):
#doc_name = 'After'
doc_name = 'Postcondition'
class PostcondCase:
# Postcondition with specific variables
def __init__(postcond, variables):
self.postcond = postcond
self.variables = variables
class Constructor(Description):
d_type = 'with_args'
d_sub = ('comment', 'description',)
class Equation(Description):
d_sub = ('comment', 'description', 'precondition', 'postcondition')
class Args(Description):
d_type = 'with_args'
d_sub = ('comment', 'description', 'optionals', )
def get_re(self, opt):
re = self.mod.RE.Epsilon
for a in self.find_arg_aspects():
re += a.get_re(opt)
return re
class NoArg(Description):
def get_re(self, opt):
return self.mod.RE.Epsilon
class Arg(Description):
d_sub = ('comment', 'default', 'description', 'superkind_of', 'name', )
def get_kind(self):
return self.make_or_kind(self.find_kind_aspects())
def get_name(self):
try:
return self.get_arg_name()
except AttributeError:
return '?'
def get_arg_name(self):
return self.src.specified_name
def get_examples(self, get_all=False):
examples = []
exs = self.find_aspects('example')
for ex in exs:
examples.extend(ex.get_examples())
if not exs or get_all:
k = self.get_kind()
examples.extend(k.get_examples())
return examples
class KeyArgEG:
def __init__(self, name, eg):
self.name = name
self.eg = eg
def get_ex_text(self):
return self.eg.get_ex_text()
def get_ctx_text(self):
return self.eg.get_ctx_text()
def get_use_text(self, x):
return '%s=%s' % (self.name, x)
class KeyArg(Arg):
# Spec with keyarg means it is:
# NOT to be used as positional argument
# ONLY as keyword argument
def get_examples(self, get_all=False):
name = self.get_arg_name()
return [KeyArgEG(name, eg) for eg in Arg.get_examples(self, get_all)]
class Draw(Description):
d_sub = ('comment', 'description', 'key_arg', 'seq', )
def get_re(self, opt):
re = self.mod.RE.Epsilon
for a in self.find_arg_aspects():
re += a.get_re(opt)('?')
return re
class Optionals(Description):
d_sub = ('arg', 'args', 'key_arg', 'comment', 'seq', )
d_type = 'with_args'
def get_re(self, opt):
def opt_ra(aspects):
if not aspects:
return self.mod.RE.Epsilon
return (aspects[0].get_re(opt) + opt_ra(aspects[1:]))('?')
return opt_ra(self.find_arg_aspects())
class Repeat(Description):
d_sub = ('alt', 'arg', 'args', 'comment', 'description')
def get_arg(self):
return self.src.node.arg.strip()
def get_re(self, opt):
asp = self.find_arg_aspects()
if not asp:
self.error('No argument aspects.', self.src.node)
re = asp[0].get_re(opt)
for a in asp[1:]:
re += a.get_re(opt)
arg = self.get_arg()
sep = '..'
if sep in arg:
args = arg.split(sep)
if len(args) != 2:
self.error('More than one %r in argument.' %
sep, self.src.node)
lo, hi = [x.strip() for x in args]
try:
lo = int(lo)
except ValueError:
self.error('Expected int in lower bound.', self.src.node)
if hi != '*':
try:
hi = int(hi)
except ValueError:
self.error('Expected int or * in upper bound.',
self.src.node)
else:
try:
lo = int(arg)
except ValueError:
self.error(
'Expected int, int..int or int..* in argument.', self.src.node)
hi = lo
if lo < 0 or (hi != '*' and hi < 0):
self.error('Expected non-negative repetition count.',
self.src.node)
if hi == '*':
res = re('*')
for i in range(lo):
res = re + res
else:
if hi < lo:
self.error('Expected upper bound >= lower bound.',
self.src.node)
a = self.mod.RE.Epsilon
for i in range(lo):
a += re
b = self.mod.RE.Epsilon
for i in range(lo, hi):
b = (re + b)('?')
res = a + b
return res
class Seq(Description):
d_sub = ('arg', 'comment', 'description', 'optionals',)
d_sub += ('key_arg', ) # May perhaps be optionally disabled
d_type = 'with_args'
def get_re(self, opt):
re = self.mod.RE.Epsilon
for a in self.find_arg_aspects():
re += a.get_re(opt)
return re
class Alt(Description):
d_sub = ('arg', 'comment', 'descripton', 'key_arg', 'no_arg', 'seq', )
d_type = 'with_args'
def get_re(self, opt):
asp = self.find_arg_aspects()
if not asp:
self.error('No alternatives.', self.src.node)
re = asp[0].get_re(opt)
for a in asp[1:]:
re |= a.get_re(opt)
return re
class Returns(Description):
d_sub = ('attribute', 'comment', 'description', 'description_with_header',
'either', 'mapping', 'method')
d_type = 'with_opt_args'
def get_kind(self):
return self.make_and_kind(self.find_kind_aspects())
def get_test_kind(self):
return self.make_and_test_kind(self.find_kind_aspects())
# help functions
def find_aspects_inseq(seq, tag):
as_ = []
for o in seq:
as_.extend(o.find_aspects(tag))
return as_
# Beam base class
class Beam:
def __init__(self, k_tag, *objects):
self.src = objects[0]
self.tgt = objects[-1]
self.k_tag = k_tag
self.objects = objects
def __add__(self, other):
return compose(self, other)
class KindBeam(Beam):
pass
class AtomKindBeam(Beam):
pass
class KindMappingBeam(Beam):
pass
class KindOpBeam(Beam):
op_index = 1
op_name_index = 1
def find_equations(self):
return find_aspects_inseq(self.get_op_seq(), 'equation')
def find_postconditions(self):
return find_aspects_inseq(self.get_op_seq(), 'postcondition')
def find_preconditions(self):
return find_aspects_inseq(self.get_op_seq(), 'precondition')
def get_args_examples(self, mapname):
top_kind = self.objects[0]
return self.get_the_op().get_args_examples(mapname, top_kind)
def get_op_id_name(self):
return self.objects[self.op_name_index].get_id_name()
def get_op_name(self):
return self.objects[self.op_name_index].get_op_name()
def get_op_seq(self):
return self.objects[self.op_index:]
def get_self_name(self):
return self.get_the_op().get_self_name()
def get_the_op(self):
return self.objects[self.op_index]
def get_return_test_kind(self):
return self.get_the_op().get_return_test_kind()
class KindAttributeBeam(KindOpBeam):
def get_the_op(self):
assert 0
class KindAttributeMappingBeam(KindOpBeam):
op_index = 2
class KindMappingBeam(KindOpBeam):
def get_op_name(self):
return '()'
class KOKOpBeam(KindOpBeam):
op_index = 2
op_name_index = 2
def subkind_of_kind(*objects):
return beam(*objects[2:])
def compose(a, b):
if a.tgt is not b.src:
raise "Composition error, tgt %r is not src %r" % (a.tgt, b.src)
objects = a.objects + b.objects[1:]
return beam(*objects)
def remove_1_2(k_tag, *objects):
return beam(objects[0], *objects[3:])
def remove_0(k_tag, *objects):
return beam(*objects[1:])
beam_table = {
('attribute', 'attribute'): Beam,
('attribute', 'either'): Beam,
('attribute', 'kind_of'): Beam,
('attribute', 'kind_of', 'kind', 'attribute'): Beam,
('attribute', 'kind_of', 'kind', 'function_operator'): Beam,
('attribute', 'kind_of', 'kind', 'inplace_operator'): Beam,
('attribute', 'kind_of', 'kind', 'mapping'): Beam,
('attribute', 'kind_of', 'kind', 'operator'): Beam,
('attribute', 'kind_of', 'kind', 'reverse_operator'): Beam,
('attribute', 'kind_of', 'kind', 'delitem'): Beam,
('attribute', 'kind_of', 'kind', 'getitem'): Beam,
('attribute', 'kind_of', 'kind', 'setitem'): Beam,
('attribute', 'mapping'): Beam,
('either', ): Beam,
('either', 'kind'): Beam,
('either', 'kind', 'attribute'): Beam,
('kind', 'attribute'): Beam,
('kind', 'attribute', 'kind_of', 'kind', 'mapping'): KindAttributeBeam,
('kind', 'attribute', 'mapping'): KindAttributeMappingBeam,
('kind', 'either'): Beam,
('kind', 'function_operator'): KindOpBeam,
('kind', 'delitem'): KindOpBeam,
('kind', 'getitem'): KindOpBeam,
('kind', 'inplace_operator'): KindOpBeam,
('kind', 'kind_of'): Beam,
('kind', 'kind_of', 'kind', 'attribute'): Beam,
('kind', 'mapping'): KindMappingBeam,
('kind', 'operator'): KindOpBeam,
('kind', 'reverse_operator'): KindOpBeam,
('kind', 'setitem'): KindOpBeam,
('kind', 'subkind_of'): Beam,
('kind', 'subkind_of', 'kind', 'attribute'): remove_1_2,
('kind', 'subkind_of', 'kind', 'function_operator'): remove_1_2,
('kind', 'subkind_of', 'kind', 'delitem'): remove_1_2,
('kind', 'subkind_of', 'kind', 'getitem'): remove_1_2,
('kind', 'subkind_of', 'kind', 'inplace_operator'): remove_1_2,
('kind', 'subkind_of', 'kind', 'mapping'): remove_1_2,
('kind', 'subkind_of', 'kind', 'operator'): remove_1_2,
('kind', 'subkind_of', 'kind', 'reverse_operator'): remove_1_2,
('kind', 'subkind_of', 'kind', 'setitem'): remove_1_2,
('kind_of', 'kind'): Beam,
('kind_of', 'kind', 'attribute'): Beam,
('kind_of', 'kind', 'function_operator'): KOKOpBeam,
('kind_of', 'kind', 'delitem'): KOKOpBeam,
('kind_of', 'kind', 'getitem'): KOKOpBeam,
('kind_of', 'kind', 'inplace_operator'): KOKOpBeam,
('kind_of', 'kind', 'operator'): KOKOpBeam,
('kind_of', 'kind', 'reverse_operator'): KOKOpBeam,
('kind_of', 'kind', 'setitem'): KOKOpBeam,
('kind_of', 'kind', 'mapping'): Beam,
('subkind_of', 'kind'): Beam,
('subkind_of', 'kind', 'attribute'): Beam,
('subkind_of', 'kind', 'function_operator'): Beam,
('subkind_of', 'kind', 'delitem'): Beam,
('subkind_of', 'kind', 'getitem'): Beam,
('subkind_of', 'kind', 'inplace_operator'): Beam,
('subkind_of', 'kind', 'mapping'): Beam,
('subkind_of', 'kind', 'operator'): Beam,
('subkind_of', 'kind', 'reverse_operator'): Beam,
('subkind_of', 'kind', 'setitem'): Beam,
}
def beam(*objects):
k_tag = tuple([x.d_tag for x in objects])
C = beam_table[k_tag]
return C(k_tag, *objects)
class ProductSubject:
def __init__(self, subjects):
self.subjects = subjects
self.fullname = '(%s)' % '*'.join([x.fullname for x in subjects])
class Subject:
args = ()
specified_name = None
def __init__(self, parent, node, lastname):
self.parent = parent
self.pac = parent.pac
self.mod = self.pac.mod
self.node = node
self.filename = self.pac.filename
self.lastname = lastname
self.aspects = []
self.subjects = {}
self.node_index = 0
self.tag = node.tag
self.description_class = self.mod.get_description_class(node.tag)
self.aspect_mode = None
if self.parent is not self:
self.fullname = self.parent.make_child_name(self.lastname)
else:
self.fullname = self.lastname
def _visit_type_definition(self, node):
names = self.get_arglist(node, min=1)
for name in names:
self.add_new_subject(node, name)
def _visit_type_operator(self, node):
shtag = self.mod.SpecNodes.reverse_node_aliases[node.tag]
names = self.get_arglist(node, min=1)
for name in names:
name = '%s:%s' % (shtag, name)
self.add_new_subject(node, name)
def _visit_type_other(self, node):
self.add_new_subject(node)
def _visit_type_with_args(self, node):
names = self.get_arglist(node)
args = [self.find_subject(name, node) for name in names]
subject = self.add_new_subject(node)
if args:
subject.args = args
def _visit_type_with_opt_args(self, node):
names = self.get_arglist(node, min=0)
args = [self.find_subject(name, node) for name in names]
subject = self.add_new_subject(node)
if args:
subject.args = args
def add_new_subject(self, node, lastname=None):
subject = self.new_subject(node, lastname)
self.add_subject(subject)
return subject
def add_subject(self, subject):
self.def_subject(subject)
subject.add_top_node()
return subject
def add_top_node(self):
node = self.node
self._visit_children(node)
def def_new_subject(self, node, lastname=None):
subject = self.new_subject(node, lastname)
self.def_subject(subject)
return subject
def def_subject(self, subject):
if subject.description_class.d_is_def:
name = subject.lastname
if name in self.subjects:
self.error('Redefinition of %r.' % name, subject.node,
more=[(
'Previous definition of %r.' % name,
self.subjects[name].node)]
)
return # For clarity; there's most certainly an exception
subject.definame = name
self.subjects[name] = subject
else:
subject.definame = None
self.aspects.append(subject)
def error(self, msg, node=None, exception=ReportedError, **kwds):
return self.pac.error(msg, node, exception, **kwds)
def find_subject(self, name, node):
return self.pac.find_subject(name, node, self)
def get_arglist(self, node, min=0):
arglist = node.get_arglist()
for arg in node.get_arglist():
if not arg:
if node.arg.strip().startswith(',') or node.arg.strip().endswith(','):
m = 'Arg list to definition can not start or end with a comma.'
else:
m = 'Missing argument to definition.'
self.error(m, node, exception=None)
arglist = [x for x in arglist if x]
break
if len(arglist) < min:
self.error(
'Not enough arguments, minimum %d expected to node %s' % (
min, node),
node)
return arglist
def get_arglist_only(self, node, min=0):
al = self.get_arglist(node, min)
self.no_children(node)
return al
def get_line(self, index):
try:
with open(self.filename) as f:
text = list(f.readlines())[index].rstrip()
except Exception:
text = None
return text
def _visit_aspect(self, node, mode):
if self.aspect_mode is None:
self.aspect_mode = mode
else:
if self.aspect_mode != mode:
self.error('Inconsistent aspect mode: %r, was: %r' % (mode, self.aspect_mode),
node)
self._visit_children(node)
def _visit_children(self, node):
for ch in node.children:
try:
if ch.tag not in self.description_class.d_sub:
self.error('Invalid tag: %r in: %r. Allowed = %s' % (
ch.tag, self.tag, self.description_class.d_sub), node)
if self.mod.cover_check is not None:
self.mod.cover_check.setdefault(self.tag, {})[ch.tag] = 1
ch.accept(self)
except ReportedError:
pass
self.node_index += 1
def make_child_name(self, child_lastname):
return '%s.%s' % (self.fullname, child_lastname)
def new_subject(self, node, name=None):
is_def = self.mod.get_description_class(node.tag).d_is_def
assert is_def == (name is not None)
if name is None:
name = '<%d>' % self.node_index
tag = node.tag
if tag == 'macro':
return MacroSubject(self, node, name)
elif tag == 'document':
return DocumentSubject(self, node, name)
else:
return Subject(self, node, name)
def new_tag_node(self, tag, node):
return self.mod.SpecNodes.node_of_taci(tag, '', node.children, node.index)
def no_children(self, node):
if node.children:
self.error('No children expected for node with tag %r' % node.tag,
node,
exception=None)
def visit_and(self, node):
for name in self.get_arglist(node, min=1):
ofsubject = self.find_subject(name, node)
ofsubject._visit_aspect(node, 'and')
def visit_aspects_of(self, node):
for name in self.get_arglist(node, min=1):
ofsubject = self.find_subject(name, node)
ofsubject._visit_aspect(node, 'aspect')
def visit_arg(self, node, must_have_name=False):
arg = node.arg.strip()
arg_name = None
kind = None
if arg:
if ':' in arg:
nk = arg.split(':')
if len(nk) > 2:
self.error('More than 1 colon in argument.', node)
name, kind_name = [x.strip() for x in nk]
if kind_name:
kind = self.find_subject(kind_name, node)
if name:
arg_name = name
else:
# Is there an obvious default ?
# For KeyArg, yes, the name is always.
# let's say it's the name
arg_name = arg
subject = self.new_subject(node)
if arg_name:
subject.specified_name = arg_name
self.add_subject(subject)
if must_have_name and subject.specified_name is None:
self.error('No argument name specified.', node)
if kind is not None:
subject.args = [kind]
def visit_comment(self, node):
pass
def visit_condition(self, node):
names = self.get_arglist(node, min=1)
for name in names:
self.add_new_subject(node, 'cond:%s' % name)
def visit_default(self, node):
description_class = self.mod.get_description_class(node.tag)
arg = node.arg.strip()
colon = arg.startswith(':')
if (description_class.d_type == 'definition') != colon:
if colon:
msg = 'Tag %r is not a definition, should not have ::' % node.tag
else:
msg = 'Tag %r is a definition, requires ::' % node.tag
self.error(msg, node, exception=None)
getattr(self, '_visit_type_%s' % description_class.d_type)(node)
def visit_description(self, node):
self.def_new_subject(node)
def visit_description_with_header(self, node):
self.visit_description(node)
def visit_example(self, node):
subject = self.add_new_subject(node)
partab = subject.description_class.partab
ex = node.arg.strip()
if '\n' in ex:
if not (partab.get(ex[:1]) == ex[-1:] or
partab.get(ex[:3]) == ex[-3:]):
self.error('Multi-line expression should be in parentheses (for clarity).', node,
exception=None, harmless=1)
ex = '(%s)' % ex
subject.ex_text = ex
def visit_import(self, node):
my_names = self.get_arglist(node, min=1)
resolve_mode = None
usings = None
froms = []
for ch in node.children:
t = ch.tag
if t == 'from':
for name in self.get_arglist_only(ch):
froms.append((name, ch))
elif t == 'resolve_by':
if resolve_mode:
self.error("More than 1 'resolve' clause.",
ch.node, exception=None)
else:
resolve_mode = ch.arg.strip()
if not resolve_mode in ('and', 'or'):
self.error("Resolve by: and / or expected.",
ch,
exception=None)
resolve_mode = 'and'
elif t == 'using':
if usings is None:
usings = []
for name in self.get_arglist_only(ch):
usings.append((name, ch))
else:
self.error('Unexpected clause in import', ch, exception=None)
using_map = {}
if usings is not None:
if len(usings) != len(my_names):
if len(using_names) < len(my_names):
manyfew = 'few'
else:
manyfew = 'many'
self.error(
"Too %s 'using' names, should match number of names in .import" % manyfew,
using_node,
exception=None)
for m, u in zip(my_names, usings):
# zip stops at the shortest list, ok
using_map[m] = u
if len(froms) == 0:
self.error("No 'from' clause", node)
if len(froms) > 1:
if not resolve_mode:
self.error("Importing from multiple packages but no 'resolve by' clause",
node, exception=None)
resolve_mode = 'and'
for name in my_names:
subject = self.def_new_subject(node, name)
subject.imp_resolve_mode = resolve_mode
subject.imp_using_map = using_map
subject.imp_froms = froms
def visit_key_arg(self, node):
self.visit_arg(node, must_have_name=True)
def visit_method(self, node):
arg = node.arg.strip()
if not arg.startswith(':'):
self.error("Tag 'method' is a definition, requires ::", node)
self.mod.node_of_taci('attribute', arg,
(self.mod.node_of_taci('mapping', '', node.children),)).accept(self)
def visit_name(self, node):
if self.specified_name is not None:
self.error('Duplicate name specification.', node)
name = node.arg.strip()
if not name:
self.error('No name specification.', node)
self.specified_name = name
def visit_or(self, node):
for name in self.get_arglist(node, min=1):
ofsubject = self.find_subject(name, node)
ofsubject._visit_aspect(node, 'or')
def visit_postcondition(self, node):
arg = node.arg.strip()
if not '(' in arg:
self.error('No left parenthesis', node)
lpar = arg.index('(')
rpar = arg.find(')')
if rpar < lpar:
self.error('None or misplaced right parenthesis', node)
n = arg[lpar+1:rpar].strip()
if ',' in n:
n = [x.strip() for x in n.split(',')]
else:
n = [n]
arg_names = n
cond_name = arg[:lpar].strip()
if not cond_name:
self.error('No condition name', node)
is_not = 0
if cond_name.startswith('not '):
cond_name = cond_name[4:].strip()
is_not = 1
parts = cond_name.split('.')
if not parts[-1].startswith('cond:'):
parts[-1] = 'cond:'+parts[-1]
cond_name = '.'.join(parts)
cond_def = self.find_subject(cond_name, node)
subject = self.add_new_subject(node)
subject.cond_definition = cond_def
subject.cond_name = cond_name
subject.arg_names = arg_names
subject.is_not = is_not
def visit_precondition(self, node):
self.visit_postcondition(node)
class ErrorSubject(Subject):
pass
class PackageSubject(Subject):
def __init__(self, mod, specenv, node, name, filename):
self.mod = mod
self.specenv = specenv
self.pac = self
self.filename = filename
#name = 'package_%s'%(name,)
name = '%s' % (name,)
Subject.__init__(self, self, node, name)
self.lastname = name.split('.')[-1]
self.tag = 'package'
self.description_class = Package
self.documents = []
for s in mod.predefined_subjects:
s = s(self)
self.subjects[s.fullname] = s
self._visit_children(node)
del self.specenv # It was used only for error report
def error(self, msg, node=None, exception=ReportedError, **kwds):
return self.specenv.error(msg, node, exception, **kwds)
def find_subject(self, name, node, context=None):
if not name:
self.error('Invalid subject name: %r' % name, node)
parts = [x.strip() for x in name.split('.')]
if not parts[0]:
tag = parts[1]
parts = parts[2:]
else:
tag = 'myfile'
if tag == 'myfile':
s = self
elif tag == 'mykind':
s = context
if s is not None:
kind_tags = ('kind', 'and', 'import')
while s.parent != self and s.tag not in kind_tags:
s = s.parent
if s.tag not in kind_tags:
s = None
if s is None:
self.error('mykind tag without such a context: %r' %
name, node)
else:
self.error('Invalid tag %r in %r' % (tag, name), node)
sname = s.lastname
for i, n in enumerate(parts):
ns = s.subjects.get(n)
if ns is None:
if s.tag != 'import':
self.error('No such subject: %r in %r.' %
(n, sname), node)
return SubImportSubject(s, node, parts[i:])
sname = sname + '.' + n
s = ns
return s
class SubImportSubject:
def __init__(self, parent, node, rnparts):
self.parent = parent
self.node = node
self.rnparts = rnparts
self.fullname = '.'.join([parent.fullname]+rnparts)
self.lastname = rnparts[-1]
class MacroSubject(Subject):
def add_top_node(self):
pass
class DocumentSubject(Subject):
def add_top_node(self):
self.parent.documents.append(self)
class GuppyWorld(Subject):
def __init__(self, env):
self.pac = env
self.fullname = self.lastname = "Guppy_World"
self.node = None
self.tag = '<GuppyWorld>'
self.aspects = []
self.description_class = Description
class _GLUECLAMP_:
_imports_ = (
'_parent:Document',
'_parent:FileIO',
'_parent.FileIO:IO',
'_parent:Filer',
'_parent:Html',
'_parent:Latex',
'_parent:SpecNodes',
'_parent.SpecNodes:node_of_taci',
'_parent:Tester',
'_root.hashlib:md5',
'_root.guppy.etc:iterpermute',
'_root.guppy.etc:RE',
)
_chgable_ = ('cover_check', 'io_dir', 'max_errors')
description_classes = {
'alt': Alt,
'arg': Arg,
'args': Args,
'attribute': Attribute,
'comment': Comment,
'condition': Condition,
'constructor': Constructor,
'default': Default,
'defines': Defines,
'delitem': DelItem,
'description': DescriptionDescription,
'description_with_header': DescriptionWithHeader,
'equation': Equation,
'example': Example,
'either': Either,
'draw': Draw,
'function_operator': FunctionOperator,
'getitem': GetItem,
'import': Import,
'in_context': InContext,
'inplace_operator': InplaceOperator,
'key_arg': KeyArg,
'kind': Kind,
'kind_of': KindOf,
'macro': Macro,
'mapping': Mapping,
'no_arg': NoArg,
'operator': Operator,
'postcondition': Postcondition,
'precondition': Precondition,
'python_code': PythonCode,
'reverse_operator': ReverseOperator,
'optionals': Optionals,
'package': Package,
'repeat': Repeat,
'returns': Returns,
'self': Self,
'seq': Seq,
'setitem': SetItem,
'subkind_of': SubkindOf,
'superkind': Superkind,
'superkind_of': SuperkindOf,
}
tgt_prefix = '.tgt.'
cover_check = None
io_dir = None
max_errors = 10
def get_description_class(self, tag):
return self.description_classes.get(tag, Description)
def _get_predefined_subjects(self):
return (GuppyWorld,)
def _get_package_cache(self):
return {}
def main(self, filename, **kwds):
se = SpecEnv(self)
se.process_main(filename, **kwds)
def _test_main_(self):
pass
def set_input_dir(self, dir):
dir = self.IO.path.abspath(dir)
self.input_dir = dir
Zerion Mini Shell 1.0