From 5220d76eb17d0a2184fc4f5142c702f8e6544dac Mon Sep 17 00:00:00 2001 From: umarcor Date: Mon, 28 Dec 2020 20:35:32 +0100 Subject: scripts: move 'pyGHDL/xtools' to 'scripts', update Makefiles and docs accordingly --- Makefile.in | 2 +- README.md | 2 +- configure | 2 +- doc/internals/AST.rst | 2 +- pyGHDL/lsp/README | 2 +- pyGHDL/xtools/pnodes.py | 988 ---------------------------------------------- pyGHDL/xtools/pnodespy.py | 263 ------------ scripts/pnodes.py | 988 ++++++++++++++++++++++++++++++++++++++++++++++ scripts/pnodespy.py | 263 ++++++++++++ src/edif/Makefile | 12 +- src/psl/Makefile | 11 +- src/vhdl/Makefile | 35 +- 12 files changed, 1295 insertions(+), 1275 deletions(-) delete mode 100755 pyGHDL/xtools/pnodes.py delete mode 100755 pyGHDL/xtools/pnodespy.py create mode 100755 scripts/pnodes.py create mode 100755 scripts/pnodespy.py diff --git a/Makefile.in b/Makefile.in index 1ef92ac8d..c089789d5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -457,7 +457,7 @@ uninstall.libghdl: libghdl-py.tgz: [ -d pythonb ] || $(MKDIR) pythonb - $(CP) -r $(srcdir)/python/libghdl $(srcdir)/python/setup.py pythonb + $(CP) -r $(srcdir)/pyGHDL/libghdl $(srcdir)/setup.py pythonb tar -zcvf $@ -C pythonb . ################ ghwdump ################################################# diff --git a/README.md b/README.md index becdbf3bf..ae032c91d 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ That's all! - `libghdl` is a shared library that includes a subset of the regular features plus some features to be used by extension tools (i.e. `libghdl-py`). This is built along with the regular GHDL and it supports both non-synthesisable and synthesisable code. Nonetheless, this is not for users, but for tools built on top of the core. When configured along with `--enable-synth`, this shared library includes **[experimental]** synthesis features too. -- [libghdl-py](python/libghdl) is a Python interface to `libghdl`. Currently, it is only used by `ghdl-ls`; however, it can be useful for advanced users which are willing to build Python utilities based on GHDL. +- [pyGHDL](pyGHDL) is a Python interface to `libghdl`. Currently, it is only used by `ghdl-ls`; however, it can be useful for advanced users which are willing to build Python utilities based on GHDL. - **[experimental]** [ghdl-yosys-plugin](https://github.com/ghdl/ghdl-yosys-plugin) is the integration of GHDL as a frontend plugin module for [Yosys Open SYnthesis Suite](http://www.clifford.at/yosys/), which uses the `libghdl` library (built with `--enable-synth`). diff --git a/configure b/configure index 83d9b2628..75599d776 100755 --- a/configure +++ b/configure @@ -190,7 +190,7 @@ fi # Check the version of libghdl is correct. if [ "$enable_libghdl" = true ]; then - libghdl_version="$srcdir/python/libghdl/version.py" + libghdl_version="$srcdir/pyGHDL/libghdl/version.py" # Extract content between single quotes in version.py, to avoid false positives due to LF/CRLF mismatch. if [ "$ghdl_version" != "`sed 's/.*"\(.*\)".*/\1/g' $libghdl_version`" ]; then echo "Sorry, the version of $libghdl_version is not correct" diff --git a/doc/internals/AST.rst b/doc/internals/AST.rst index 488fa6d71..ad52f0286 100644 --- a/doc/internals/AST.rst +++ b/doc/internals/AST.rst @@ -75,7 +75,7 @@ either a node reference, a boolean flag or a enumerated type (like node or to a list. The accessors for the node are generated automatically by the python -script :file:`src/xtools/pnodes.py`. +script :file:`src/scripts/pnodes.py`. Why a meta-model ? ****************** diff --git a/pyGHDL/lsp/README b/pyGHDL/lsp/README index c82ccc4d4..f9595f15f 100644 --- a/pyGHDL/lsp/README +++ b/pyGHDL/lsp/README @@ -9,7 +9,7 @@ develop tools around the parser and analyzer. To install: 1) First install ghdl (add --enable-python during configuration). This is needed so that the libraries are available -2) In ghdl/python, install pyghdl. There is a setup.py script, so you can do: +2) In ghdl, install pyGHDL. There is a setup.py script, so you can do: $ pip install . To install for development: pip install -e . Add --user to install in your home directory. diff --git a/pyGHDL/xtools/pnodes.py b/pyGHDL/xtools/pnodes.py deleted file mode 100755 index 793c1c712..000000000 --- a/pyGHDL/xtools/pnodes.py +++ /dev/null @@ -1,988 +0,0 @@ -#!/usr/bin/env python - -import re -import sys -import argparse - -field_file = "nodes.ads" -kind_file = "iirs.ads" -node_file = "iirs.ads" -template_file = "iirs.adb.in" -meta_base_file = "nodes_meta" -prefix_name = "Iir_Kind_" -prefix_range_name = "Iir_Kinds_" -type_name = "Iir_Kind" -node_type = "Iir" -conversions = ["uc", "pos", "grp"] - - -class FuncDesc: - def __init__(self, name, fields, conv, acc, pname, ptype, rname, rtype): - self.name = name - self.fields = fields # List of physical fields used - self.conv = conv - self.acc = acc # access: Chain, Chain_Next, Ref, Of_Ref, Maybe_Ref, - # Forward_Ref, Maybe_Forward_Ref - self.pname = pname # Parameter mame - self.ptype = ptype # Parameter type - self.rname = rname # value name (for procedure) - self.rtype = rtype # value type - - -class NodeDesc: - def __init__(self, name, format, fields, attrs): - self.name = name - self.format = format - self.fields = fields # {field: FuncDesc} dict, defined for all fields - self.attrs = attrs # A {attr: FuncDesc} dict - self.order = [] # List of fields name, in order of appearance. - - -class line: - def __init__(self, string, no): - self.l = string - self.n = no - - -class EndOfFile(Exception): - def __init__(self, filename): - self.filename = filename - - def __str__(self): - return "end of file " + self.filename - - -class linereader: - def __init__(self, filename): - self.filename = filename - self.f = open(filename) - self.lineno = 0 - self.l = "" - - def get(self): - self.l = self.f.readline() - if not self.l: - raise EndOfFile(self.filename) - self.lineno = self.lineno + 1 - return self.l - - -class ParseError(Exception): - def __init__(self, lr, msg): - self.lr = lr - self.msg = msg - - def __str__(self): - return "Error: " + self.msg - return ( - "Parse error at " + self.lr.filname + ":" + self.lr.lineno + ": " + self.msg - ) - - -# Return fields description. -# This is a dictionary. The keys represent the possible format of a node. -# The values are dictionnaries representing fields. Keys are fields name, and -# values are fields type. -def read_fields(file): - fields = {} - formats = [] - lr = linereader(file) - - # Search for 'type Format_Type is' - while lr.get() != " type Format_Type is\n": - pass - - # Skip '(' - if lr.get() != " (\n": - raise "no open parenthesis after Format_Type" - - # Read formats - l = lr.get() - pat_field_name = re.compile(" Format_(\w+),?\n") - while l != " );\n": - m = pat_field_name.match(l) - if m is None: - print l - raise "bad literal within Format_Type" - name = m.group(1) - formats.append(name) - fields[name] = {} - l = lr.get() - - # Read fields - l = lr.get() - pat_fields = re.compile(" -- Fields of Format_(\w+):\n") - pat_field_desc = re.compile(" -- (\w+) : (\w+).*\n") - format_name = "" - common_desc = {} - - # Read until common fields. - while l != " -- Common fields are:\n": - l = lr.get() - format_name = "Common" - nbr_formats = 0 - - while True: - # 1) Read field description - l = lr.get() - desc = common_desc.copy() - while True: - m = pat_field_desc.match(l) - if m is None: - break - desc[m.group(1)] = m.group(2) - l = lr.get() - # print 'For: ' + format_name + ': ' + m.group(1) - - # 2) Disp - if format_name == "Common": - common_desc = desc - else: - fields[format_name] = desc - - # 3) Read next format - if l == "\n": - if nbr_formats == len(fields): - break - else: - l = lr.get() - - # One for a format - m = pat_fields.match(l) - if m is not None: - format_name = m.group(1) - if format_name not in fields: - raise ParseError(lr, "Format " + format_name + " is unknown") - nbr_formats = nbr_formats + 1 - else: - raise ParseError(lr, "unhandled format line") - - return (formats, fields) - - -# Read kinds and kinds ranges. -def read_kinds(filename): - lr = linereader(filename) - kinds = [] - # Search for 'type Iir_Kind is' - while lr.get() != " type " + type_name + " is\n": - pass - # Skip '(' - if lr.get() != " (\n": - raise ParseError(lr, 'no open parenthesis after "type ' + type_name + '"') - - # Read literals - pat_node = re.compile(" " + prefix_name + "(\w+),?( +-- .*)?\n") - pat_comment = re.compile("( +-- .*)?\n") - while True: - l = lr.get() - if l == " );\n": - break - m = pat_node.match(l) - if m: - kinds.append(m.group(1)) - continue - m = pat_comment.match(l) - if not m: - raise ParseError(lr, "Unknown line within kind declaration") - - # Check subtypes - pat_subtype = re.compile(" subtype " + r"(\w+) is " + type_name + " range\n") - pat_first = re.compile(" " + prefix_name + r"(\w+) ..\n") - pat_last = re.compile(" " + prefix_name + r"(\w+);\n") - pat_middle = re.compile(" --" + prefix_name + r"(\w+)\n") - kinds_ranges = {} - while True: - l = lr.get() - # Start of methods is also end of subtypes. - if l == " -- General methods.\n": - break - # Found a subtype. - m = pat_subtype.match(l) - if m: - # Check first bound - name = m.group(1) - if not name.startswith(prefix_range_name): - raise ParseError(lr, "incorrect prefix for subtype") - name = name[len(prefix_range_name) :] - l = lr.get() - mf = pat_first.match(l) - if not mf: - raise ParseError(lr, "badly formated first bound of subtype") - first = kinds.index(mf.group(1)) - idx = first - has_middle = None - # Read until last bound - while True: - l = lr.get() - ml = pat_middle.match(l) - if ml: - # Check element in the middle - n = ml.group(1) - if n not in kinds: - raise ParseError(lr, "unknown kind " + n + " in subtype") - if kinds.index(n) != idx + 1: - raise ParseError( - lr, "missing " + kinds[idx + 1] + " in subtype" - ) - has_middle = True - idx = idx + 1 - else: - # Check last bound - ml = pat_last.match(l) - if ml: - last = kinds.index(ml.group(1)) - if last != idx + 1 and has_middle: - raise ParseError( - lr, "missing " + kinds[idx] + " in subtype" - ) - break - raise ParseError(lr, "unhandled line in subtype") - kinds_ranges[name] = kinds[first : last + 1] - return (kinds, kinds_ranges) - - -# Read functions -def read_methods(filename): - lr = linereader(filename) - funcs = [] - pat_field = re.compile(r" -- Field: ([\w,]+)( \w+)?( \(\w+\))?\n") - pat_conv = re.compile(r"^ \((\w+)\)$") - pat_func = re.compile(r" function Get_(\w+) \((\w+) : (\w+)\) return (\w+);\n") - pat_proc = re.compile(r" procedure Set_(\w+) \((\w+) : (\w+); (\w+) : (\w+)\);\n") - pat_end = re.compile("end [A-Za-z.]+;\n") - while True: - l = lr.get() - # Start of methods - if l == " -- General methods.\n": - break - while True: - l = lr.get() - if pat_end.match(l): - break - m = pat_field.match(l) - if m: - fields = m.group(1).split(",") - # Extract access modifier - acc = m.group(2) - if acc: - acc = acc.strip() - # Extract conversion - conv = m.group(3) - if conv: - mc = pat_conv.match(conv) - if not mc: - raise ParseError(lr, "conversion ill formed") - conv = mc.group(1) - if conv not in conversions: - raise ParseError(lr, "unknown conversion " + conv) - else: - conv = None - if len(fields) > 1 and conv != "grp": - raise ParseError(lr, "bad conversion for multiple fields") - # Read function - l = lr.get() - mf = pat_func.match(l) - if not mf: - raise ParseError(lr, "function declaration expected after Field") - # Read procedure - l = lr.get() - mp = pat_proc.match(l) - if not mp: - raise ParseError(lr, "procedure declaration expected after function") - # Consistency check between function and procedure - if mf.group(1) != mp.group(1): - raise ParseError(lr, "function and procedure name mismatch") - if mf.group(2) != mp.group(2): - raise ParseError(lr, "parameter name mismatch with function") - if mf.group(3) != mp.group(3): - raise ParseError(lr, "parameter type mismatch with function") - if mf.group(4) != mp.group(5): - raise ParseError(lr, "result type mismatch with function") - funcs.append( - FuncDesc( - mf.group(1), - fields, - conv, - acc, - mp.group(2), - mp.group(3), - mp.group(4), - mp.group(5), - ) - ) - - return funcs - - -# Read description for one node -# LR is the line reader. NAMES is the list of (node name, format) -# (one description may describe several nodes). -# A comment start at column 2 or 4 or later. -def read_nodes_fields(lr, names, fields, nodes, funcs_dict): - pat_only = re.compile(" -- Only for " + prefix_name + "(\w+):\n") - pat_only_bad = re.compile(" -- *Only for.*\n") - pat_field = re.compile(" -- Get/Set_(\w+) \((Alias )?([\w,]+)\)\n") - pat_comment = re.compile(" --(| [^ ].*| .*)\n") - - # Create nodes - cur_nodes = [] - for (nm, fmt) in names: - if fmt not in fields: - raise ParseError(lr, 'unknown format "{}"'.format(fmt)) - n = NodeDesc(nm, fmt, {x: None for x in fields[fmt]}, {}) - nodes[nm] = n - cur_nodes.append(n) - - # Skip comments - l = lr.l - while pat_comment.match(l): - l = lr.get() - - # Look for fields - while l != "\n": - # Skip comments - while pat_comment.match(l): - l = lr.get() - - # Handle 'Only ...' - m = pat_only.match(l) - if m: - only_nodes = [] - while True: - name = m.group(1) - n = nodes.get(name, None) - if n is None: - raise ParseError(lr, "node is unknown") - if n not in cur_nodes: - raise ParseError(lr, "node not currently described") - only_nodes.append(n) - l = lr.get() - m = pat_only.match(l) - if not m: - break - else: - # By default a field applies to all nodes. - only_nodes = cur_nodes - - # Skip comments - while pat_comment.match(l): - l = lr.get() - - # Handle field: '-- Get/Set_FUNC (Alias? FIELD)' - m = pat_field.match(l) - if not m: - if pat_only_bad.match(l): - raise ParseError(lr, "misleading 'Only for' comment") - else: - raise ParseError(lr, "bad line in node description") - - func = m.group(1) - alias = m.group(2) - fields = m.group(3).split(",") - - # Check the function exists and if the field is correct. - if func not in funcs_dict: - raise ParseError(lr, "unknown function") - func = funcs_dict[func] - if func.fields != fields: - raise ParseError(lr, "fields mismatch") - - for c in only_nodes: - for f in fields: - if f not in c.fields: - raise ParseError(lr, "field " + f + " does not exist in node") - if not alias: - for f in fields: - if c.fields[f]: - raise ParseError(lr, "field " + f + " already used") - c.fields[f] = func - c.order.append(f) - c.attrs[func.name] = func - - l = lr.get() - - -def read_nodes(filename, kinds, kinds_ranges, fields, funcs): - """Read description for all nodes.""" - lr = linereader(filename) - funcs_dict = {x.name: x for x in funcs} - nodes = {} - - # Skip until start - while lr.get() != " -- Start of " + type_name + ".\n": - pass - - pat_decl = re.compile(" -- " + prefix_name + "(\w+) \((\w+)\)\n") - pat_decls = re.compile(" -- " + prefix_range_name + "(\w+) \((\w+)\)\n") - pat_comment_line = re.compile(" --+\n") - pat_comment_box = re.compile(" --( .*)?\n") - while True: - l = lr.get() - if l == " -- End of " + type_name + ".\n": - break - if l == "\n": - continue - m = pat_decl.match(l) - if m: - # List of nodes being described by the current description. - names = [] - - # Declaration of the first node - while True: - name = m.group(1) - if name not in kinds: - raise ParseError(lr, "unknown node") - fmt = m.group(2) - names.append((name, fmt)) - if name in nodes: - raise ParseError(lr, "node {} already described".format(name)) - # There might be several nodes described at once. - l = lr.get() - m = pat_decl.match(l) - if not m: - break - read_nodes_fields(lr, names, fields, nodes, funcs_dict) - continue - m = pat_decls.match(l) - if m: - # List of nodes being described by the current description. - name = m.group(1) - fmt = m.group(2) - names = [(k, fmt) for k in kinds_ranges[name]] - l = lr.get() - read_nodes_fields(lr, names, fields, nodes, funcs_dict) - continue - if pat_comment_line.match(l) or pat_comment_box.match(l): - continue - raise ParseError(lr, "bad line in node description") - - for k in kinds: - if k not in nodes: - raise ParseError(lr, 'no description for "{}"'.format(k)) - return nodes - - -def gen_choices(choices): - """Generate a choice 'when A | B ... Z =>' using elements of CHOICES.""" - is_first = True - for c in choices: - if is_first: - print " ", - print "when", - else: - print - print " ", - print " |", - print prefix_name + c, - is_first = False - print "=>" - - -def gen_get_format(formats, nodes, kinds): - """Generate the Get_Format function.""" - print " function Get_Format (Kind : " + type_name + ") " + "return Format_Type is" - print " begin" - print " case Kind is" - for f in formats: - choices = [k for k in kinds if nodes[k].format == f] - gen_choices(choices) - print " return Format_" + f + ";" - print " end case;" - print " end Get_Format;" - - -def gen_subprg_header(decl): - if len(decl) < 76: - print decl + " is" - else: - print decl - print " is" - print " begin" - - -def gen_assert(func): - print " pragma Assert (" + func.pname + " /= Null_" + node_type + ");" - cond = "(Has_" + func.name + " (Get_Kind (" + func.pname + "))," - msg = '"no field ' + func.name + '");' - if len(cond) < 60: - print " pragma Assert " + cond - print " " + msg - else: - print " pragma Assert" - print " " + cond - print " " + msg - - -def get_field_type(fields, f): - for fld in fields.values(): - if f in fld: - return fld[f] - return None - - -def gen_get_set(func, nodes, fields): - """Generate Get_XXX/Set_XXX subprograms for FUNC.""" - rtype = func.rtype - # If the function needs several fields, it must be user defined - if func.conv == "grp": - print " type %s_Conv is record" % rtype - for f in func.fields: - print " %s: %s;" % (f, get_field_type(fields, f)) - print " end record;" - print " pragma Pack (%s_Conv);" % rtype - print " pragma Assert (%s_Conv'Size = %s'Size);" % (rtype, rtype) - print - else: - f = func.fields[0] - g = "Get_" + f + " (" + func.pname + ")" - - s = func.rname - if func.conv: - if func.conv == "uc": - field_type = get_field_type(fields, f) - g = field_type + "_To_" + rtype + " (" + g + ")" - s = rtype + "_To_" + field_type + " (" + s + ")" - elif func.conv == "pos": - g = rtype + "'Val (" + g + ")" - s = rtype + "'Pos (" + s + ")" - - subprg = ( - " function Get_" - + func.name - + " (" - + func.pname - + " : " - + func.ptype - + ") return " - + rtype - ) - if func.conv == "grp": - print subprg - print " is" - print " function To_%s is new Ada.Unchecked_Conversion" % func.rtype - print " (%s_Conv, %s);" % (rtype, rtype) - print " Conv : %s_Conv;" % rtype - print " begin" - else: - gen_subprg_header(subprg) - gen_assert(func) - if func.conv == "grp": - for f in func.fields: - print " Conv.%s := Get_%s (%s);" % (f, f, func.pname) - g = "To_%s (Conv)" % rtype - print " return " + g + ";" - print " end Get_" + func.name + ";" - print - - subprg = ( - " procedure Set_" - + func.name - + " (" - + func.pname - + " : " - + func.ptype - + "; " - + func.rname - + " : " - + func.rtype - + ")" - ) - if func.conv == "grp": - print subprg - print " is" - print " function To_%s_Conv is new Ada.Unchecked_Conversion" % func.rtype - print " (%s, %s_Conv);" % (rtype, rtype) - print " Conv : %s_Conv;" % rtype - print " begin" - else: - gen_subprg_header(subprg) - gen_assert(func) - if func.conv == "grp": - print " Conv := To_%s_Conv (%s);" % (rtype, func.rname) - for f in func.fields: - print " Set_%s (%s, Conv.%s);" % (f, func.pname, f) - else: - print " Set_" + f + " (" + func.pname + ", " + s + ");" - print " end Set_" + func.name + ";" - print - - -def funcs_of_node(n): - return sorted([fv.name for fv in n.fields.values() if fv]) - - -def gen_has_func_spec(name, suff): - spec = " function Has_" + name + " (K : " + type_name + ")" - ret = " return Boolean" + suff - if len(spec) < 60: - print spec + ret - else: - print spec - print " " + ret - - -def do_disp_formats(): - for fmt in fields: - print "Fields of Format_" + fmt - fld = fields[fmt] - for k in fld: - print " " + k + " (" + fld[k] + ")" - - -def do_disp_kinds(): - print "Kinds are:" - for k in kinds: - print " " + prefix_name + k - - -def do_disp_funcs(): - print "Functions are:" - for f in funcs: - s = "{0} ({1}: {2}".format(f.name, f.field, f.rtype) - if f.acc: - s += " acc:" + f.acc - if f.conv: - s += " conv:" + f.conv - s += ")" - print s - - -def do_disp_types(): - print "Types are:" - s = set([]) - for f in funcs: - s |= set([f.rtype]) - for t in sorted(s): - print " " + t - - -def do_disp_nodes(): - for k in kinds: - v = nodes[k] - print prefix_name + k + " (" + v.format + ")" - flds = [fk for fk, fv in v.fields.items() if fv] - for fk in sorted(flds): - print " " + fk + ": " + v.fields[fk].name - - -def do_get_format(): - gen_get_format(formats, nodes) - - -def do_body(): - lr = linereader(template_file) - while True: - l = lr.get().rstrip() - print l - if l == " -- Subprograms": - gen_get_format(formats, nodes, kinds) - print - for f in funcs: - gen_get_set(f, nodes, fields) - if l[0:3] == "end": - break - - -def get_types(): - s = set([]) - for f in funcs: - s |= set([f.rtype]) - return [t for t in sorted(s)] - - -def get_attributes(): - s = set([]) - for f in funcs: - if f.acc: - s |= set([f.acc]) - res = [t for t in sorted(s)] - res.insert(0, "None") - return res - - -def gen_enum(prefix, vals): - last = None - for v in vals: - if last: - print last + "," - last = prefix + v - print last - - -def do_meta_specs(): - lr = linereader(meta_base_file + ".ads.in") - types = get_types() - while True: - l = lr.get().rstrip() - if l == " -- TYPES": - gen_enum(" Type_", types) - elif l == " -- FIELDS": - gen_enum(" Field_", [f.name for f in funcs]) - elif l == " -- ATTRS": - gen_enum(" Attr_", get_attributes()) - elif l == " -- FUNCS": - for t in types: - print " function Get_" + t - print " (N : " + node_type + "; F : Fields_Enum) return " + t + ";" - print " procedure Set_" + t - print " (N : " + node_type + "; F : Fields_Enum; V: " + t + ");" - print - for f in funcs: - gen_has_func_spec(f.name, ";") - elif l[0:3] == "end": - print l - break - else: - print l - - -def do_meta_body(): - lr = linereader(meta_base_file + ".adb.in") - while True: - l = lr.get().rstrip() - if l == " -- FIELDS_TYPE": - last = None - for f in funcs: - if last: - print last + "," - last = " Field_" + f.name + " => Type_" + f.rtype - print last - elif l == " -- FIELD_IMAGE": - for f in funcs: - print " when Field_" + f.name + " =>" - print ' return "' + f.name.lower() + '";' - elif l == " -- IIR_IMAGE": - for k in kinds: - print " when " + prefix_name + k + " =>" - print ' return "' + k.lower() + '";' - elif l == " -- FIELD_ATTRIBUTE": - for f in funcs: - print " when Field_" + f.name + " =>" - if f.acc: - attr = f.acc - else: - attr = "None" - print " return Attr_" + attr + ";" - elif l == " -- FIELDS_ARRAY": - last = None - nodes_types = [node_type, node_type + "_List", node_type + "_Flist"] - for k in kinds: - v = nodes[k] - if last: - print last + "," - last = None - print " -- " + prefix_name + k - # Get list of physical fields for V, in some order. - if flag_keep_order: - flds = v.order - else: - # First non Iir and no Iir_List. - flds = sorted( - [ - fk - for fk, fv in v.fields.items() - if fv and fv.rtype not in nodes_types - ] - ) - # Then Iir and Iir_List in order of appearance - flds += (fv for fv in v.order if v.fields[fv].rtype in nodes_types) - # Print the corresponding node field, but remove duplicate due - # to 'grp'. - fldsn = [] - for fk in flds: - if last: - print last + "," - # Remove duplicate - fn = v.fields[fk].name - if fn not in fldsn: - last = " Field_" + fn - fldsn.append(fn) - else: - last = None - if last: - print last - elif l == " -- FIELDS_ARRAY_POS": - pos = -1 - last = None - for k in kinds: - v = nodes[k] - # Create a set to remove duplicate for 'grp'. - flds = set([fv.name for fk, fv in v.fields.items() if fv]) - pos += len(flds) - if last: - print last + "," - last = " " + prefix_name + k + " => {}".format(pos) - print last - elif l == " -- FUNCS_BODY": - # Build list of types - s = set([]) - for f in funcs: - s |= set([f.rtype]) - types = [t for t in sorted(s)] - for t in types: - print " function Get_" + t - print " (N : " + node_type + "; F : Fields_Enum) return " + t + " is" - print " begin" - print " pragma Assert (Fields_Type (F) = Type_" + t + ");" - print " case F is" - for f in funcs: - if f.rtype == t: - print " when Field_" + f.name + " =>" - print " return Get_" + f.name + " (N);" - print " when others =>" - print " raise Internal_Error;" - print " end case;" - print " end Get_" + t + ";" - print - print " procedure Set_" + t - print " (N : " + node_type + "; F : Fields_Enum; V: " + t + ") is" - print " begin" - print " pragma Assert (Fields_Type (F) = Type_" + t + ");" - print " case F is" - for f in funcs: - if f.rtype == t: - print " when Field_" + f.name + " =>" - print " Set_" + f.name + " (N, V);" - print " when others =>" - print " raise Internal_Error;" - print " end case;" - print " end Set_" + t + ";" - print - for f in funcs: - gen_has_func_spec(f.name, " is") - choices = [k for k in kinds if f.name in nodes[k].attrs] - if len(choices) == 0: - print " pragma Unreferenced (K);" - print " begin" - if len(choices) == 0: - print " return False;" - elif len(choices) == 1: - print " return K = " + prefix_name + choices[0] + ";" - else: - print " case K is" - gen_choices(choices) - print " return True;" - print " when others =>" - print " return False;" - print " end case;" - print " end Has_" + f.name + ";" - print - elif l[0:3] == "end": - print l - break - else: - print l - - -actions = { - "disp-nodes": do_disp_nodes, - "disp-kinds": do_disp_kinds, - "disp-formats": do_disp_formats, - "disp-funcs": do_disp_funcs, - "disp-types": do_disp_types, - "get_format": do_get_format, - "body": do_body, - "meta_specs": do_meta_specs, - "meta_body": do_meta_body, -} - - -def main(): - parser = argparse.ArgumentParser(description="Meta-grammar processor") - parser.add_argument("action", choices=actions.keys(), default="disp-nodes") - parser.add_argument( - "--field-file", - dest="field_file", - default="nodes.ads", - help="specify file which defines fields", - ) - parser.add_argument( - "--kind-file", - dest="kind_file", - default="iirs.ads", - help="specify file which defines nodes kind", - ) - parser.add_argument( - "--node-file", - dest="node_file", - default="iirs.ads", - help="specify file which defines nodes and methods", - ) - parser.add_argument( - "--template-file", - dest="template_file", - default="iirs.adb.in", - help="specify template body file", - ) - parser.add_argument( - "--meta-basename", - dest="meta_basename", - default="nodes_meta", - help="specify base name of meta files", - ) - parser.add_argument( - "--kind-type", dest="kind_type", default="Iir_Kind", help="name of kind type" - ) - parser.add_argument( - "--kind-prefix", - dest="kind_prefix", - default="Iir_Kind_", - help="prefix for kind literals", - ) - parser.add_argument( - "--kind-range-prefix", - dest="kind_range_prefix", - default="Iir_Kinds_", - help="prefix for kind subtype (range)", - ) - parser.add_argument( - "--node-type", dest="node_type", default="Iir", help="name of the node type" - ) - parser.add_argument( - "--keep-order", - dest="flag_keep_order", - action="store_true", - help="keep field order of nodes", - ) - parser.set_defaults(flag_keep_order=False) - args = parser.parse_args() - - # At some point, it would be simpler to create a class... - global formats, fields, nodes, kinds, kinds_ranges, funcs - - global type_name, prefix_name, template_file, node_type, meta_base_file - global prefix_range_name, flag_keep_order, kind_file - - type_name = args.kind_type - prefix_name = args.kind_prefix - prefix_range_name = args.kind_range_prefix - template_file = args.template_file - node_type = args.node_type - meta_base_file = args.meta_basename - flag_keep_order = args.flag_keep_order - - field_file = args.field_file - kind_file = args.kind_file - node_file = args.node_file - - try: - (formats, fields) = read_fields(field_file) - (kinds, kinds_ranges) = read_kinds(kind_file) - funcs = read_methods(node_file) - nodes = read_nodes(node_file, kinds, kinds_ranges, fields, funcs) - - except ParseError as e: - print >> sys.stderr, e - print >> sys.stderr, "in {0}:{1}:{2}".format(e.lr.filename, e.lr.lineno, e.lr.l) - sys.exit(1) - - f = actions.get(args.action, None) - if not f: - print >> sys.stderr, "Action {0} is unknown".format(args.action) - sys.exit(1) - f() - - -if __name__ == "__main__": - main() diff --git a/pyGHDL/xtools/pnodespy.py b/pyGHDL/xtools/pnodespy.py deleted file mode 100755 index 0e0f5ba9e..000000000 --- a/pyGHDL/xtools/pnodespy.py +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/env python - -"""Like pnodes but output for python""" - -from __future__ import print_function -import pnodes -import re - -libname = "libghdl" - - -def print_enum(name, vals): - print() - print() - print("class {0}:".format(name)) - for n, k in enumerate(vals): - if k == "None": - k = "PNone" - print(" {0} = {1}".format(k, n)) - - -def do_class_kinds(): - print_enum(pnodes.prefix_name.rstrip("_"), pnodes.kinds) - print() - print() - print("class Iir_Kinds:") - for k, v in pnodes.kinds_ranges.items(): - print(" {0} = [".format(k)) - for e in v: - print(" Iir_Kind.{},".format(e)) - print(" ]") - print() - - -def do_iirs_subprg(): - classname = "vhdl__nodes" - print() - print("Get_Kind = {0}.{1}__get_kind".format(libname, classname)) - print("Get_Location = {0}.{1}__get_location".format(libname, classname)) - for k in pnodes.funcs: - print() - print( - "Get_{0} = {1}.{2}__get_{3}".format( - k.name, libname, classname, k.name.lower() - ) - ) - print() - print( - "Set_{0} = {1}.{2}__set_{3}".format( - k.name, libname, classname, k.name.lower(), k.pname, k.rname - ) - ) - - -def do_libghdl_elocations(): - classname = "vhdl__elocations" - print("from libghdl import libghdl") - print() - for k in pnodes.funcs: - print() - print( - "Get_{0} = {1}.{2}__get_{3}".format( - k.name, libname, classname, k.name.lower() - ) - ) - print() - print( - "Set_{0} = {1}.{2}__set_{3}".format( - k.name, libname, classname, k.name.lower(), k.pname, k.rname - ) - ) - - -def do_class_types(): - print_enum("types", pnodes.get_types()) - - -def do_types_subprg(): - print() - for k in pnodes.get_types(): - print() - print("Get_{0} = {1}.vhdl__nodes_meta__get_{2}".format(k, libname, k.lower())) - - -def do_has_subprg(): - print() - for f in pnodes.funcs: - print() - print("Has_{0} =\\".format(f.name)) - print(" {0}.vhdl__nodes_meta__has_{1}".format(libname, f.name.lower())) - - -def do_class_field_attributes(): - print_enum("Attr", ["ANone" if a == "None" else a for a in pnodes.get_attributes()]) - - -def do_class_fields(): - print_enum("fields", [f.name for f in pnodes.funcs]) - - -def read_enum(filename, type_name, prefix, class_name, g=lambda m: m.group(1)): - """Read an enumeration declaration from :param filename:""" - pat_decl = re.compile(r" type {0} is$".format(type_name)) - pat_enum = re.compile(r" {0}(\w+),?( *-- .*)?$".format(prefix)) - pat_comment = re.compile(r" *-- .*$") - lr = pnodes.linereader(filename) - while not pat_decl.match(lr.get()): - pass - line = lr.get() - if line != " (\n": - raise pnodes.ParseError( - lr, "{}:{}: missing open parenthesis".format(filename, lr.lineno) - ) - toks = [] - while True: - line = lr.get() - if line == " );\n": - break - m = pat_enum.match(line) - if m: - toks.append(g(m)) - elif pat_comment.match(line): - pass - elif line == "\n": - pass - else: - print(line, file=sys.stderr) - raise pnodes.ParseError( - lr, - "{}:{}: incorrect line in enum {}".format( - filename, lr.lineno, type_name - ), - ) - print_enum(class_name, toks) - - -def read_spec_enum(type_name, prefix, class_name): - """Read an enumeration declaration from iirs.ads""" - read_enum(pnodes.kind_file, type_name, prefix, class_name) - - -def do_libghdl_nodes(): - print("from libghdl import libghdl") - print( - """ -Null_Iir = 0 - -Null_Iir_List = 0 -Iir_List_All = 1 - -Null_Iir_Flist = 0 -Iir_Flist_Others = 1 -Iir_Flist_All = 2 -""" - ) - do_class_kinds() - read_spec_enum("Iir_Mode", "Iir_", "Iir_Mode") - read_spec_enum("Iir_Staticness", "", "Iir_Staticness") - read_spec_enum("Iir_Constraint", "", "Iir_Constraint") - read_spec_enum("Iir_Delay_Mechanism", "Iir_", "Iir_Delay_Mechanism") - read_spec_enum("Date_State_Type", "Date_", "Date_State") - read_spec_enum("Iir_Predefined_Functions", "Iir_Predefined_", "Iir_Predefined") - do_iirs_subprg() - - -def do_libghdl_meta(): - print("from libghdl import libghdl") - print( - """ - -# From nodes_meta -get_fields_first = libghdl.vhdl__nodes_meta__get_fields_first - -get_fields_last = libghdl.vhdl__nodes_meta__get_fields_last - -get_field_by_index = libghdl.vhdl__nodes_meta__get_field_by_index - -get_field_type = libghdl.vhdl__nodes_meta__get_field_type - -get_field_attribute = libghdl.vhdl__nodes_meta__get_field_attribute""" - ) - do_class_types() - do_class_field_attributes() - do_class_fields() - do_types_subprg() - do_has_subprg() - - -def do_libghdl_names(): - pat_name_first = re.compile(r" Name_(\w+)\s+: constant Name_Id := (\d+);") - pat_name_def = re.compile( - r" Name_(\w+)\s+:\s+constant Name_Id :=\s+Name_(\w+)( \+ (\d+))?;" - ) - dict = {} - lr = pnodes.linereader("../std_names.ads") - while True: - line = lr.get() - m = pat_name_first.match(line) - if m: - name_def = m.group(1) - val = int(m.group(2)) - dict[name_def] = val - res = [(name_def, val)] - break - val_max = 1 - while True: - line = lr.get() - if line == "end Std_Names;\n": - break - if line.endswith(":=\n"): - line = line.rstrip() + lr.get() - m = pat_name_def.match(line) - if m: - name_def = m.group(1) - name_ref = m.group(2) - val = m.group(3) - if not val: - val = 0 - val_ref = dict.get(name_ref, None) - if not val_ref: - raise pnodes.ParseError(lr, "name {0} not found".format(name_ref)) - val = val_ref + int(val) - val_max = max(val_max, val) - dict[name_def] = val - res.append((name_def, val)) - print("class Name:") - for n, v in res: - # Avoid clash with Python names - if n in ["False", "True", "None"]: - n = "N" + n - print(" {0} = {1}".format(n, v)) - - -def do_libghdl_tokens(): - read_enum("vhdl-tokens.ads", "Token_Type", "Tok_", "Tok") - - -def do_libghdl_errorout(): - print("from libghdl import libghdl") - print("\n" "Enable_Warning = libghdl.errorout__enable_warning") - read_enum( - "../errorout.ads", - "Msgid_Type", - "(Msgid|Warnid)_", - "Msgid", - g=lambda m: m.group(1) + "_" + m.group(2), - ) - - -pnodes.actions.update( - { - "class-kinds": do_class_kinds, - "libghdl-nodes": do_libghdl_nodes, - "libghdl-meta": do_libghdl_meta, - "libghdl-names": do_libghdl_names, - "libghdl-tokens": do_libghdl_tokens, - "libghdl-elocs": do_libghdl_elocations, - "libghdl-errorout": do_libghdl_errorout, - } -) - - -pnodes.main() diff --git a/scripts/pnodes.py b/scripts/pnodes.py new file mode 100755 index 000000000..793c1c712 --- /dev/null +++ b/scripts/pnodes.py @@ -0,0 +1,988 @@ +#!/usr/bin/env python + +import re +import sys +import argparse + +field_file = "nodes.ads" +kind_file = "iirs.ads" +node_file = "iirs.ads" +template_file = "iirs.adb.in" +meta_base_file = "nodes_meta" +prefix_name = "Iir_Kind_" +prefix_range_name = "Iir_Kinds_" +type_name = "Iir_Kind" +node_type = "Iir" +conversions = ["uc", "pos", "grp"] + + +class FuncDesc: + def __init__(self, name, fields, conv, acc, pname, ptype, rname, rtype): + self.name = name + self.fields = fields # List of physical fields used + self.conv = conv + self.acc = acc # access: Chain, Chain_Next, Ref, Of_Ref, Maybe_Ref, + # Forward_Ref, Maybe_Forward_Ref + self.pname = pname # Parameter mame + self.ptype = ptype # Parameter type + self.rname = rname # value name (for procedure) + self.rtype = rtype # value type + + +class NodeDesc: + def __init__(self, name, format, fields, attrs): + self.name = name + self.format = format + self.fields = fields # {field: FuncDesc} dict, defined for all fields + self.attrs = attrs # A {attr: FuncDesc} dict + self.order = [] # List of fields name, in order of appearance. + + +class line: + def __init__(self, string, no): + self.l = string + self.n = no + + +class EndOfFile(Exception): + def __init__(self, filename): + self.filename = filename + + def __str__(self): + return "end of file " + self.filename + + +class linereader: + def __init__(self, filename): + self.filename = filename + self.f = open(filename) + self.lineno = 0 + self.l = "" + + def get(self): + self.l = self.f.readline() + if not self.l: + raise EndOfFile(self.filename) + self.lineno = self.lineno + 1 + return self.l + + +class ParseError(Exception): + def __init__(self, lr, msg): + self.lr = lr + self.msg = msg + + def __str__(self): + return "Error: " + self.msg + return ( + "Parse error at " + self.lr.filname + ":" + self.lr.lineno + ": " + self.msg + ) + + +# Return fields description. +# This is a dictionary. The keys represent the possible format of a node. +# The values are dictionnaries representing fields. Keys are fields name, and +# values are fields type. +def read_fields(file): + fields = {} + formats = [] + lr = linereader(file) + + # Search for 'type Format_Type is' + while lr.get() != " type Format_Type is\n": + pass + + # Skip '(' + if lr.get() != " (\n": + raise "no open parenthesis after Format_Type" + + # Read formats + l = lr.get() + pat_field_name = re.compile(" Format_(\w+),?\n") + while l != " );\n": + m = pat_field_name.match(l) + if m is None: + print l + raise "bad literal within Format_Type" + name = m.group(1) + formats.append(name) + fields[name] = {} + l = lr.get() + + # Read fields + l = lr.get() + pat_fields = re.compile(" -- Fields of Format_(\w+):\n") + pat_field_desc = re.compile(" -- (\w+) : (\w+).*\n") + format_name = "" + common_desc = {} + + # Read until common fields. + while l != " -- Common fields are:\n": + l = lr.get() + format_name = "Common" + nbr_formats = 0 + + while True: + # 1) Read field description + l = lr.get() + desc = common_desc.copy() + while True: + m = pat_field_desc.match(l) + if m is None: + break + desc[m.group(1)] = m.group(2) + l = lr.get() + # print 'For: ' + format_name + ': ' + m.group(1) + + # 2) Disp + if format_name == "Common": + common_desc = desc + else: + fields[format_name] = desc + + # 3) Read next format + if l == "\n": + if nbr_formats == len(fields): + break + else: + l = lr.get() + + # One for a format + m = pat_fields.match(l) + if m is not None: + format_name = m.group(1) + if format_name not in fields: + raise ParseError(lr, "Format " + format_name + " is unknown") + nbr_formats = nbr_formats + 1 + else: + raise ParseError(lr, "unhandled format line") + + return (formats, fields) + + +# Read kinds and kinds ranges. +def read_kinds(filename): + lr = linereader(filename) + kinds = [] + # Search for 'type Iir_Kind is' + while lr.get() != " type " + type_name + " is\n": + pass + # Skip '(' + if lr.get() != " (\n": + raise ParseError(lr, 'no open parenthesis after "type ' + type_name + '"') + + # Read literals + pat_node = re.compile(" " + prefix_name + "(\w+),?( +-- .*)?\n") + pat_comment = re.compile("( +-- .*)?\n") + while True: + l = lr.get() + if l == " );\n": + break + m = pat_node.match(l) + if m: + kinds.append(m.group(1)) + continue + m = pat_comment.match(l) + if not m: + raise ParseError(lr, "Unknown line within kind declaration") + + # Check subtypes + pat_subtype = re.compile(" subtype " + r"(\w+) is " + type_name + " range\n") + pat_first = re.compile(" " + prefix_name + r"(\w+) ..\n") + pat_last = re.compile(" " + prefix_name + r"(\w+);\n") + pat_middle = re.compile(" --" + prefix_name + r"(\w+)\n") + kinds_ranges = {} + while True: + l = lr.get() + # Start of methods is also end of subtypes. + if l == " -- General methods.\n": + break + # Found a subtype. + m = pat_subtype.match(l) + if m: + # Check first bound + name = m.group(1) + if not name.startswith(prefix_range_name): + raise ParseError(lr, "incorrect prefix for subtype") + name = name[len(prefix_range_name) :] + l = lr.get() + mf = pat_first.match(l) + if not mf: + raise ParseError(lr, "badly formated first bound of subtype") + first = kinds.index(mf.group(1)) + idx = first + has_middle = None + # Read until last bound + while True: + l = lr.get() + ml = pat_middle.match(l) + if ml: + # Check element in the middle + n = ml.group(1) + if n not in kinds: + raise ParseError(lr, "unknown kind " + n + " in subtype") + if kinds.index(n) != idx + 1: + raise ParseError( + lr, "missing " + kinds[idx + 1] + " in subtype" + ) + has_middle = True + idx = idx + 1 + else: + # Check last bound + ml = pat_last.match(l) + if ml: + last = kinds.index(ml.group(1)) + if last != idx + 1 and has_middle: + raise ParseError( + lr, "missing " + kinds[idx] + " in subtype" + ) + break + raise ParseError(lr, "unhandled line in subtype") + kinds_ranges[name] = kinds[first : last + 1] + return (kinds, kinds_ranges) + + +# Read functions +def read_methods(filename): + lr = linereader(filename) + funcs = [] + pat_field = re.compile(r" -- Field: ([\w,]+)( \w+)?( \(\w+\))?\n") + pat_conv = re.compile(r"^ \((\w+)\)$") + pat_func = re.compile(r" function Get_(\w+) \((\w+) : (\w+)\) return (\w+);\n") + pat_proc = re.compile(r" procedure Set_(\w+) \((\w+) : (\w+); (\w+) : (\w+)\);\n") + pat_end = re.compile("end [A-Za-z.]+;\n") + while True: + l = lr.get() + # Start of methods + if l == " -- General methods.\n": + break + while True: + l = lr.get() + if pat_end.match(l): + break + m = pat_field.match(l) + if m: + fields = m.group(1).split(",") + # Extract access modifier + acc = m.group(2) + if acc: + acc = acc.strip() + # Extract conversion + conv = m.group(3) + if conv: + mc = pat_conv.match(conv) + if not mc: + raise ParseError(lr, "conversion ill formed") + conv = mc.group(1) + if conv not in conversions: + raise ParseError(lr, "unknown conversion " + conv) + else: + conv = None + if len(fields) > 1 and conv != "grp": + raise ParseError(lr, "bad conversion for multiple fields") + # Read function + l = lr.get() + mf = pat_func.match(l) + if not mf: + raise ParseError(lr, "function declaration expected after Field") + # Read procedure + l = lr.get() + mp = pat_proc.match(l) + if not mp: + raise ParseError(lr, "procedure declaration expected after function") + # Consistency check between function and procedure + if mf.group(1) != mp.group(1): + raise ParseError(lr, "function and procedure name mismatch") + if mf.group(2) != mp.group(2): + raise ParseError(lr, "parameter name mismatch with function") + if mf.group(3) != mp.group(3): + raise ParseError(lr, "parameter type mismatch with function") + if mf.group(4) != mp.group(5): + raise ParseError(lr, "result type mismatch with function") + funcs.append( + FuncDesc( + mf.group(1), + fields, + conv, + acc, + mp.group(2), + mp.group(3), + mp.group(4), + mp.group(5), + ) + ) + + return funcs + + +# Read description for one node +# LR is the line reader. NAMES is the list of (node name, format) +# (one description may describe several nodes). +# A comment start at column 2 or 4 or later. +def read_nodes_fields(lr, names, fields, nodes, funcs_dict): + pat_only = re.compile(" -- Only for " + prefix_name + "(\w+):\n") + pat_only_bad = re.compile(" -- *Only for.*\n") + pat_field = re.compile(" -- Get/Set_(\w+) \((Alias )?([\w,]+)\)\n") + pat_comment = re.compile(" --(| [^ ].*| .*)\n") + + # Create nodes + cur_nodes = [] + for (nm, fmt) in names: + if fmt not in fields: + raise ParseError(lr, 'unknown format "{}"'.format(fmt)) + n = NodeDesc(nm, fmt, {x: None for x in fields[fmt]}, {}) + nodes[nm] = n + cur_nodes.append(n) + + # Skip comments + l = lr.l + while pat_comment.match(l): + l = lr.get() + + # Look for fields + while l != "\n": + # Skip comments + while pat_comment.match(l): + l = lr.get() + + # Handle 'Only ...' + m = pat_only.match(l) + if m: + only_nodes = [] + while True: + name = m.group(1) + n = nodes.get(name, None) + if n is None: + raise ParseError(lr, "node is unknown") + if n not in cur_nodes: + raise ParseError(lr, "node not currently described") + only_nodes.append(n) + l = lr.get() + m = pat_only.match(l) + if not m: + break + else: + # By default a field applies to all nodes. + only_nodes = cur_nodes + + # Skip comments + while pat_comment.match(l): + l = lr.get() + + # Handle field: '-- Get/Set_FUNC (Alias? FIELD)' + m = pat_field.match(l) + if not m: + if pat_only_bad.match(l): + raise ParseError(lr, "misleading 'Only for' comment") + else: + raise ParseError(lr, "bad line in node description") + + func = m.group(1) + alias = m.group(2) + fields = m.group(3).split(",") + + # Check the function exists and if the field is correct. + if func not in funcs_dict: + raise ParseError(lr, "unknown function") + func = funcs_dict[func] + if func.fields != fields: + raise ParseError(lr, "fields mismatch") + + for c in only_nodes: + for f in fields: + if f not in c.fields: + raise ParseError(lr, "field " + f + " does not exist in node") + if not alias: + for f in fields: + if c.fields[f]: + raise ParseError(lr, "field " + f + " already used") + c.fields[f] = func + c.order.append(f) + c.attrs[func.name] = func + + l = lr.get() + + +def read_nodes(filename, kinds, kinds_ranges, fields, funcs): + """Read description for all nodes.""" + lr = linereader(filename) + funcs_dict = {x.name: x for x in funcs} + nodes = {} + + # Skip until start + while lr.get() != " -- Start of " + type_name + ".\n": + pass + + pat_decl = re.compile(" -- " + prefix_name + "(\w+) \((\w+)\)\n") + pat_decls = re.compile(" -- " + prefix_range_name + "(\w+) \((\w+)\)\n") + pat_comment_line = re.compile(" --+\n") + pat_comment_box = re.compile(" --( .*)?\n") + while True: + l = lr.get() + if l == " -- End of " + type_name + ".\n": + break + if l == "\n": + continue + m = pat_decl.match(l) + if m: + # List of nodes being described by the current description. + names = [] + + # Declaration of the first node + while True: + name = m.group(1) + if name not in kinds: + raise ParseError(lr, "unknown node") + fmt = m.group(2) + names.append((name, fmt)) + if name in nodes: + raise ParseError(lr, "node {} already described".format(name)) + # There might be several nodes described at once. + l = lr.get() + m = pat_decl.match(l) + if not m: + break + read_nodes_fields(lr, names, fields, nodes, funcs_dict) + continue + m = pat_decls.match(l) + if m: + # List of nodes being described by the current description. + name = m.group(1) + fmt = m.group(2) + names = [(k, fmt) for k in kinds_ranges[name]] + l = lr.get() + read_nodes_fields(lr, names, fields, nodes, funcs_dict) + continue + if pat_comment_line.match(l) or pat_comment_box.match(l): + continue + raise ParseError(lr, "bad line in node description") + + for k in kinds: + if k not in nodes: + raise ParseError(lr, 'no description for "{}"'.format(k)) + return nodes + + +def gen_choices(choices): + """Generate a choice 'when A | B ... Z =>' using elements of CHOICES.""" + is_first = True + for c in choices: + if is_first: + print " ", + print "when", + else: + print + print " ", + print " |", + print prefix_name + c, + is_first = False + print "=>" + + +def gen_get_format(formats, nodes, kinds): + """Generate the Get_Format function.""" + print " function Get_Format (Kind : " + type_name + ") " + "return Format_Type is" + print " begin" + print " case Kind is" + for f in formats: + choices = [k for k in kinds if nodes[k].format == f] + gen_choices(choices) + print " return Format_" + f + ";" + print " end case;" + print " end Get_Format;" + + +def gen_subprg_header(decl): + if len(decl) < 76: + print decl + " is" + else: + print decl + print " is" + print " begin" + + +def gen_assert(func): + print " pragma Assert (" + func.pname + " /= Null_" + node_type + ");" + cond = "(Has_" + func.name + " (Get_Kind (" + func.pname + "))," + msg = '"no field ' + func.name + '");' + if len(cond) < 60: + print " pragma Assert " + cond + print " " + msg + else: + print " pragma Assert" + print " " + cond + print " " + msg + + +def get_field_type(fields, f): + for fld in fields.values(): + if f in fld: + return fld[f] + return None + + +def gen_get_set(func, nodes, fields): + """Generate Get_XXX/Set_XXX subprograms for FUNC.""" + rtype = func.rtype + # If the function needs several fields, it must be user defined + if func.conv == "grp": + print " type %s_Conv is record" % rtype + for f in func.fields: + print " %s: %s;" % (f, get_field_type(fields, f)) + print " end record;" + print " pragma Pack (%s_Conv);" % rtype + print " pragma Assert (%s_Conv'Size = %s'Size);" % (rtype, rtype) + print + else: + f = func.fields[0] + g = "Get_" + f + " (" + func.pname + ")" + + s = func.rname + if func.conv: + if func.conv == "uc": + field_type = get_field_type(fields, f) + g = field_type + "_To_" + rtype + " (" + g + ")" + s = rtype + "_To_" + field_type + " (" + s + ")" + elif func.conv == "pos": + g = rtype + "'Val (" + g + ")" + s = rtype + "'Pos (" + s + ")" + + subprg = ( + " function Get_" + + func.name + + " (" + + func.pname + + " : " + + func.ptype + + ") return " + + rtype + ) + if func.conv == "grp": + print subprg + print " is" + print " function To_%s is new Ada.Unchecked_Conversion" % func.rtype + print " (%s_Conv, %s);" % (rtype, rtype) + print " Conv : %s_Conv;" % rtype + print " begin" + else: + gen_subprg_header(subprg) + gen_assert(func) + if func.conv == "grp": + for f in func.fields: + print " Conv.%s := Get_%s (%s);" % (f, f, func.pname) + g = "To_%s (Conv)" % rtype + print " return " + g + ";" + print " end Get_" + func.name + ";" + print + + subprg = ( + " procedure Set_" + + func.name + + " (" + + func.pname + + " : " + + func.ptype + + "; " + + func.rname + + " : " + + func.rtype + + ")" + ) + if func.conv == "grp": + print subprg + print " is" + print " function To_%s_Conv is new Ada.Unchecked_Conversion" % func.rtype + print " (%s, %s_Conv);" % (rtype, rtype) + print " Conv : %s_Conv;" % rtype + print " begin" + else: + gen_subprg_header(subprg) + gen_assert(func) + if func.conv == "grp": + print " Conv := To_%s_Conv (%s);" % (rtype, func.rname) + for f in func.fields: + print " Set_%s (%s, Conv.%s);" % (f, func.pname, f) + else: + print " Set_" + f + " (" + func.pname + ", " + s + ");" + print " end Set_" + func.name + ";" + print + + +def funcs_of_node(n): + return sorted([fv.name for fv in n.fields.values() if fv]) + + +def gen_has_func_spec(name, suff): + spec = " function Has_" + name + " (K : " + type_name + ")" + ret = " return Boolean" + suff + if len(spec) < 60: + print spec + ret + else: + print spec + print " " + ret + + +def do_disp_formats(): + for fmt in fields: + print "Fields of Format_" + fmt + fld = fields[fmt] + for k in fld: + print " " + k + " (" + fld[k] + ")" + + +def do_disp_kinds(): + print "Kinds are:" + for k in kinds: + print " " + prefix_name + k + + +def do_disp_funcs(): + print "Functions are:" + for f in funcs: + s = "{0} ({1}: {2}".format(f.name, f.field, f.rtype) + if f.acc: + s += " acc:" + f.acc + if f.conv: + s += " conv:" + f.conv + s += ")" + print s + + +def do_disp_types(): + print "Types are:" + s = set([]) + for f in funcs: + s |= set([f.rtype]) + for t in sorted(s): + print " " + t + + +def do_disp_nodes(): + for k in kinds: + v = nodes[k] + print prefix_name + k + " (" + v.format + ")" + flds = [fk for fk, fv in v.fields.items() if fv] + for fk in sorted(flds): + print " " + fk + ": " + v.fields[fk].name + + +def do_get_format(): + gen_get_format(formats, nodes) + + +def do_body(): + lr = linereader(template_file) + while True: + l = lr.get().rstrip() + print l + if l == " -- Subprograms": + gen_get_format(formats, nodes, kinds) + print + for f in funcs: + gen_get_set(f, nodes, fields) + if l[0:3] == "end": + break + + +def get_types(): + s = set([]) + for f in funcs: + s |= set([f.rtype]) + return [t for t in sorted(s)] + + +def get_attributes(): + s = set([]) + for f in funcs: + if f.acc: + s |= set([f.acc]) + res = [t for t in sorted(s)] + res.insert(0, "None") + return res + + +def gen_enum(prefix, vals): + last = None + for v in vals: + if last: + print last + "," + last = prefix + v + print last + + +def do_meta_specs(): + lr = linereader(meta_base_file + ".ads.in") + types = get_types() + while True: + l = lr.get().rstrip() + if l == " -- TYPES": + gen_enum(" Type_", types) + elif l == " -- FIELDS": + gen_enum(" Field_", [f.name for f in funcs]) + elif l == " -- ATTRS": + gen_enum(" Attr_", get_attributes()) + elif l == " -- FUNCS": + for t in types: + print " function Get_" + t + print " (N : " + node_type + "; F : Fields_Enum) return " + t + ";" + print " procedure Set_" + t + print " (N : " + node_type + "; F : Fields_Enum; V: " + t + ");" + print + for f in funcs: + gen_has_func_spec(f.name, ";") + elif l[0:3] == "end": + print l + break + else: + print l + + +def do_meta_body(): + lr = linereader(meta_base_file + ".adb.in") + while True: + l = lr.get().rstrip() + if l == " -- FIELDS_TYPE": + last = None + for f in funcs: + if last: + print last + "," + last = " Field_" + f.name + " => Type_" + f.rtype + print last + elif l == " -- FIELD_IMAGE": + for f in funcs: + print " when Field_" + f.name + " =>" + print ' return "' + f.name.lower() + '";' + elif l == " -- IIR_IMAGE": + for k in kinds: + print " when " + prefix_name + k + " =>" + print ' return "' + k.lower() + '";' + elif l == " -- FIELD_ATTRIBUTE": + for f in funcs: + print " when Field_" + f.name + " =>" + if f.acc: + attr = f.acc + else: + attr = "None" + print " return Attr_" + attr + ";" + elif l == " -- FIELDS_ARRAY": + last = None + nodes_types = [node_type, node_type + "_List", node_type + "_Flist"] + for k in kinds: + v = nodes[k] + if last: + print last + "," + last = None + print " -- " + prefix_name + k + # Get list of physical fields for V, in some order. + if flag_keep_order: + flds = v.order + else: + # First non Iir and no Iir_List. + flds = sorted( + [ + fk + for fk, fv in v.fields.items() + if fv and fv.rtype not in nodes_types + ] + ) + # Then Iir and Iir_List in order of appearance + flds += (fv for fv in v.order if v.fields[fv].rtype in nodes_types) + # Print the corresponding node field, but remove duplicate due + # to 'grp'. + fldsn = [] + for fk in flds: + if last: + print last + "," + # Remove duplicate + fn = v.fields[fk].name + if fn not in fldsn: + last = " Field_" + fn + fldsn.append(fn) + else: + last = None + if last: + print last + elif l == " -- FIELDS_ARRAY_POS": + pos = -1 + last = None + for k in kinds: + v = nodes[k] + # Create a set to remove duplicate for 'grp'. + flds = set([fv.name for fk, fv in v.fields.items() if fv]) + pos += len(flds) + if last: + print last + "," + last = " " + prefix_name + k + " => {}".format(pos) + print last + elif l == " -- FUNCS_BODY": + # Build list of types + s = set([]) + for f in funcs: + s |= set([f.rtype]) + types = [t for t in sorted(s)] + for t in types: + print " function Get_" + t + print " (N : " + node_type + "; F : Fields_Enum) return " + t + " is" + print " begin" + print " pragma Assert (Fields_Type (F) = Type_" + t + ");" + print " case F is" + for f in funcs: + if f.rtype == t: + print " when Field_" + f.name + " =>" + print " return Get_" + f.name + " (N);" + print " when others =>" + print " raise Internal_Error;" + print " end case;" + print " end Get_" + t + ";" + print + print " procedure Set_" + t + print " (N : " + node_type + "; F : Fields_Enum; V: " + t + ") is" + print " begin" + print " pragma Assert (Fields_Type (F) = Type_" + t + ");" + print " case F is" + for f in funcs: + if f.rtype == t: + print " when Field_" + f.name + " =>" + print " Set_" + f.name + " (N, V);" + print " when others =>" + print " raise Internal_Error;" + print " end case;" + print " end Set_" + t + ";" + print + for f in funcs: + gen_has_func_spec(f.name, " is") + choices = [k for k in kinds if f.name in nodes[k].attrs] + if len(choices) == 0: + print " pragma Unreferenced (K);" + print " begin" + if len(choices) == 0: + print " return False;" + elif len(choices) == 1: + print " return K = " + prefix_name + choices[0] + ";" + else: + print " case K is" + gen_choices(choices) + print " return True;" + print " when others =>" + print " return False;" + print " end case;" + print " end Has_" + f.name + ";" + print + elif l[0:3] == "end": + print l + break + else: + print l + + +actions = { + "disp-nodes": do_disp_nodes, + "disp-kinds": do_disp_kinds, + "disp-formats": do_disp_formats, + "disp-funcs": do_disp_funcs, + "disp-types": do_disp_types, + "get_format": do_get_format, + "body": do_body, + "meta_specs": do_meta_specs, + "meta_body": do_meta_body, +} + + +def main(): + parser = argparse.ArgumentParser(description="Meta-grammar processor") + parser.add_argument("action", choices=actions.keys(), default="disp-nodes") + parser.add_argument( + "--field-file", + dest="field_file", + default="nodes.ads", + help="specify file which defines fields", + ) + parser.add_argument( + "--kind-file", + dest="kind_file", + default="iirs.ads", + help="specify file which defines nodes kind", + ) + parser.add_argument( + "--node-file", + dest="node_file", + default="iirs.ads", + help="specify file which defines nodes and methods", + ) + parser.add_argument( + "--template-file", + dest="template_file", + default="iirs.adb.in", + help="specify template body file", + ) + parser.add_argument( + "--meta-basename", + dest="meta_basename", + default="nodes_meta", + help="specify base name of meta files", + ) + parser.add_argument( + "--kind-type", dest="kind_type", default="Iir_Kind", help="name of kind type" + ) + parser.add_argument( + "--kind-prefix", + dest="kind_prefix", + default="Iir_Kind_", + help="prefix for kind literals", + ) + parser.add_argument( + "--kind-range-prefix", + dest="kind_range_prefix", + default="Iir_Kinds_", + help="prefix for kind subtype (range)", + ) + parser.add_argument( + "--node-type", dest="node_type", default="Iir", help="name of the node type" + ) + parser.add_argument( + "--keep-order", + dest="flag_keep_order", + action="store_true", + help="keep field order of nodes", + ) + parser.set_defaults(flag_keep_order=False) + args = parser.parse_args() + + # At some point, it would be simpler to create a class... + global formats, fields, nodes, kinds, kinds_ranges, funcs + + global type_name, prefix_name, template_file, node_type, meta_base_file + global prefix_range_name, flag_keep_order, kind_file + + type_name = args.kind_type + prefix_name = args.kind_prefix + prefix_range_name = args.kind_range_prefix + template_file = args.template_file + node_type = args.node_type + meta_base_file = args.meta_basename + flag_keep_order = args.flag_keep_order + + field_file = args.field_file + kind_file = args.kind_file + node_file = args.node_file + + try: + (formats, fields) = read_fields(field_file) + (kinds, kinds_ranges) = read_kinds(kind_file) + funcs = read_methods(node_file) + nodes = read_nodes(node_file, kinds, kinds_ranges, fields, funcs) + + except ParseError as e: + print >> sys.stderr, e + print >> sys.stderr, "in {0}:{1}:{2}".format(e.lr.filename, e.lr.lineno, e.lr.l) + sys.exit(1) + + f = actions.get(args.action, None) + if not f: + print >> sys.stderr, "Action {0} is unknown".format(args.action) + sys.exit(1) + f() + + +if __name__ == "__main__": + main() diff --git a/scripts/pnodespy.py b/scripts/pnodespy.py new file mode 100755 index 000000000..0e0f5ba9e --- /dev/null +++ b/scripts/pnodespy.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python + +"""Like pnodes but output for python""" + +from __future__ import print_function +import pnodes +import re + +libname = "libghdl" + + +def print_enum(name, vals): + print() + print() + print("class {0}:".format(name)) + for n, k in enumerate(vals): + if k == "None": + k = "PNone" + print(" {0} = {1}".format(k, n)) + + +def do_class_kinds(): + print_enum(pnodes.prefix_name.rstrip("_"), pnodes.kinds) + print() + print() + print("class Iir_Kinds:") + for k, v in pnodes.kinds_ranges.items(): + print(" {0} = [".format(k)) + for e in v: + print(" Iir_Kind.{},".format(e)) + print(" ]") + print() + + +def do_iirs_subprg(): + classname = "vhdl__nodes" + print() + print("Get_Kind = {0}.{1}__get_kind".format(libname, classname)) + print("Get_Location = {0}.{1}__get_location".format(libname, classname)) + for k in pnodes.funcs: + print() + print( + "Get_{0} = {1}.{2}__get_{3}".format( + k.name, libname, classname, k.name.lower() + ) + ) + print() + print( + "Set_{0} = {1}.{2}__set_{3}".format( + k.name, libname, classname, k.name.lower(), k.pname, k.rname + ) + ) + + +def do_libghdl_elocations(): + classname = "vhdl__elocations" + print("from libghdl import libghdl") + print() + for k in pnodes.funcs: + print() + print( + "Get_{0} = {1}.{2}__get_{3}".format( + k.name, libname, classname, k.name.lower() + ) + ) + print() + print( + "Set_{0} = {1}.{2}__set_{3}".format( + k.name, libname, classname, k.name.lower(), k.pname, k.rname + ) + ) + + +def do_class_types(): + print_enum("types", pnodes.get_types()) + + +def do_types_subprg(): + print() + for k in pnodes.get_types(): + print() + print("Get_{0} = {1}.vhdl__nodes_meta__get_{2}".format(k, libname, k.lower())) + + +def do_has_subprg(): + print() + for f in pnodes.funcs: + print() + print("Has_{0} =\\".format(f.name)) + print(" {0}.vhdl__nodes_meta__has_{1}".format(libname, f.name.lower())) + + +def do_class_field_attributes(): + print_enum("Attr", ["ANone" if a == "None" else a for a in pnodes.get_attributes()]) + + +def do_class_fields(): + print_enum("fields", [f.name for f in pnodes.funcs]) + + +def read_enum(filename, type_name, prefix, class_name, g=lambda m: m.group(1)): + """Read an enumeration declaration from :param filename:""" + pat_decl = re.compile(r" type {0} is$".format(type_name)) + pat_enum = re.compile(r" {0}(\w+),?( *-- .*)?$".format(prefix)) + pat_comment = re.compile(r" *-- .*$") + lr = pnodes.linereader(filename) + while not pat_decl.match(lr.get()): + pass + line = lr.get() + if line != " (\n": + raise pnodes.ParseError( + lr, "{}:{}: missing open parenthesis".format(filename, lr.lineno) + ) + toks = [] + while True: + line = lr.get() + if line == " );\n": + break + m = pat_enum.match(line) + if m: + toks.append(g(m)) + elif pat_comment.match(line): + pass + elif line == "\n": + pass + else: + print(line, file=sys.stderr) + raise pnodes.ParseError( + lr, + "{}:{}: incorrect line in enum {}".format( + filename, lr.lineno, type_name + ), + ) + print_enum(class_name, toks) + + +def read_spec_enum(type_name, prefix, class_name): + """Read an enumeration declaration from iirs.ads""" + read_enum(pnodes.kind_file, type_name, prefix, class_name) + + +def do_libghdl_nodes(): + print("from libghdl import libghdl") + print( + """ +Null_Iir = 0 + +Null_Iir_List = 0 +Iir_List_All = 1 + +Null_Iir_Flist = 0 +Iir_Flist_Others = 1 +Iir_Flist_All = 2 +""" + ) + do_class_kinds() + read_spec_enum("Iir_Mode", "Iir_", "Iir_Mode") + read_spec_enum("Iir_Staticness", "", "Iir_Staticness") + read_spec_enum("Iir_Constraint", "", "Iir_Constraint") + read_spec_enum("Iir_Delay_Mechanism", "Iir_", "Iir_Delay_Mechanism") + read_spec_enum("Date_State_Type", "Date_", "Date_State") + read_spec_enum("Iir_Predefined_Functions", "Iir_Predefined_", "Iir_Predefined") + do_iirs_subprg() + + +def do_libghdl_meta(): + print("from libghdl import libghdl") + print( + """ + +# From nodes_meta +get_fields_first = libghdl.vhdl__nodes_meta__get_fields_first + +get_fields_last = libghdl.vhdl__nodes_meta__get_fields_last + +get_field_by_index = libghdl.vhdl__nodes_meta__get_field_by_index + +get_field_type = libghdl.vhdl__nodes_meta__get_field_type + +get_field_attribute = libghdl.vhdl__nodes_meta__get_field_attribute""" + ) + do_class_types() + do_class_field_attributes() + do_class_fields() + do_types_subprg() + do_has_subprg() + + +def do_libghdl_names(): + pat_name_first = re.compile(r" Name_(\w+)\s+: constant Name_Id := (\d+);") + pat_name_def = re.compile( + r" Name_(\w+)\s+:\s+constant Name_Id :=\s+Name_(\w+)( \+ (\d+))?;" + ) + dict = {} + lr = pnodes.linereader("../std_names.ads") + while True: + line = lr.get() + m = pat_name_first.match(line) + if m: + name_def = m.group(1) + val = int(m.group(2)) + dict[name_def] = val + res = [(name_def, val)] + break + val_max = 1 + while True: + line = lr.get() + if line == "end Std_Names;\n": + break + if line.endswith(":=\n"): + line = line.rstrip() + lr.get() + m = pat_name_def.match(line) + if m: + name_def = m.group(1) + name_ref = m.group(2) + val = m.group(3) + if not val: + val = 0 + val_ref = dict.get(name_ref, None) + if not val_ref: + raise pnodes.ParseError(lr, "name {0} not found".format(name_ref)) + val = val_ref + int(val) + val_max = max(val_max, val) + dict[name_def] = val + res.append((name_def, val)) + print("class Name:") + for n, v in res: + # Avoid clash with Python names + if n in ["False", "True", "None"]: + n = "N" + n + print(" {0} = {1}".format(n, v)) + + +def do_libghdl_tokens(): + read_enum("vhdl-tokens.ads", "Token_Type", "Tok_", "Tok") + + +def do_libghdl_errorout(): + print("from libghdl import libghdl") + print("\n" "Enable_Warning = libghdl.errorout__enable_warning") + read_enum( + "../errorout.ads", + "Msgid_Type", + "(Msgid|Warnid)_", + "Msgid", + g=lambda m: m.group(1) + "_" + m.group(2), + ) + + +pnodes.actions.update( + { + "class-kinds": do_class_kinds, + "libghdl-nodes": do_libghdl_nodes, + "libghdl-meta": do_libghdl_meta, + "libghdl-names": do_libghdl_names, + "libghdl-tokens": do_libghdl_tokens, + "libghdl-elocs": do_libghdl_elocations, + "libghdl-errorout": do_libghdl_errorout, + } +) + + +pnodes.main() diff --git a/src/edif/Makefile b/src/edif/Makefile index 3a3cb4a8b..e7e449483 100644 --- a/src/edif/Makefile +++ b/src/edif/Makefile @@ -6,8 +6,16 @@ ortho_srcdir=../ortho GEN_SRCS=edif-nodes.adb edif-nodes_meta.ads edif-nodes_meta.adb CC=gcc -PNODES=../../python/xtools/pnodes.py -PNODES_ARGS=--field-file=edif-nodes.adb.in --kind-file=edif-nodes.ads --node-file=edif-nodes.ads --template-file=edif-nodes.adb.in --meta-basename=edif-nodes_meta --kind-type=Nkind --kind-range-prefix=Nkinds_ --kind-prefix=N_ --node-type=Node +PNODES=../../scripts/pnodes.py +PNODES_ARGS=--field-file=edif-nodes.adb.in \ + --kind-file=edif-nodes.ads \ + --node-file=edif-nodes.ads \ + --template-file=edif-nodes.adb.in \ + --meta-basename=edif-nodes_meta \ + --kind-type=Nkind \ + --kind-range-prefix=Nkinds_ \ + --kind-prefix=N_ \ + --node-type=Node all: dump_edif diff --git a/src/psl/Makefile b/src/psl/Makefile index fdcfccaf7..9d7627263 100644 --- a/src/psl/Makefile +++ b/src/psl/Makefile @@ -20,11 +20,18 @@ # be committed and distribued with the sources, so that users don't need to # regenerate them (and don't need to have python installed). -PNODES=../../python/xtools/pnodes.py +PNODES=../../scripts/pnodes.py DEPS=psl-nodes.ads psl-nodes.adb.in $(PNODES) -PNODES_FLAGS=--field-file=psl-nodes.adb.in --kind-file=psl-nodes.ads --node-file=psl-nodes.ads --template-file=psl-nodes.adb.in --meta-basename=psl-nodes_meta --kind-type=Nkind --kind-prefix=N_ --node-type=Node +PNODES_FLAGS=--field-file=psl-nodes.adb.in \ + --kind-file=psl-nodes.ads \ + --node-file=psl-nodes.ads \ + --template-file=psl-nodes.adb.in \ + --meta-basename=psl-nodes_meta \ + --kind-type=Nkind \ + --kind-prefix=N_ \ + --node-type=Node GEN_FILES=psl-nodes.adb psl-nodes_meta.ads psl-nodes_meta.adb diff --git a/src/vhdl/Makefile b/src/vhdl/Makefile index 754f063dd..08277b4d5 100644 --- a/src/vhdl/Makefile +++ b/src/vhdl/Makefile @@ -20,18 +20,23 @@ # be committed and distribued with the sources, so that users don't need to # regenerate them (and don't need to have python installed). -PNODES=../../python/xtools/pnodes.py -PNODESPY=../../python/xtools/pnodespy.py +PNODES=../../scripts/pnodes.py +PNODESPY=../../scripts/pnodespy.py DEPS=vhdl-nodes.ads vhdl-nodes.adb.in $(PNODES) -GEN_FILES=vhdl-nodes.adb vhdl-nodes_meta.ads vhdl-nodes_meta.adb \ - vhdl-elocations.adb vhdl-elocations_meta.ads vhdl-elocations_meta.adb \ - ../../python/libghdl/thin/vhdl/nodes.py \ - ../../python/libghdl/thin/vhdl/nodes_meta.py \ - ../../python/libghdl/thin/vhdl/tokens.py \ - ../../python/libghdl/thin/vhdl/elocations.py \ - ../../python/libghdl/thin/errorout.py ../../python/libghdl/thin/std_names.py +GEN_FILES=vhdl-nodes.adb \ + vhdl-nodes_meta.ads \ + vhdl-nodes_meta.adb \ + vhdl-elocations.adb \ + vhdl-elocations_meta.ads \ + vhdl-elocations_meta.adb \ + ../../pyGHDL/libghdl/vhdl/nodes.py \ + ../../pyGHDL/libghdl/vhdl/nodes_meta.py \ + ../../pyGHDL/libghdl/vhdl/tokens.py \ + ../../pyGHDL/libghdl/vhdl/elocations.py \ + ../../pyGHDL/libghdl/errorout.py \ + ../../pyGHDL/libghdl/std_names.py NODES_FLAGS=--node-file=vhdl-nodes.ads --field-file=vhdl-nodes.adb.in \ --template-file=vhdl-nodes.adb.in --kind-file=vhdl-nodes.ads \ @@ -73,32 +78,32 @@ vhdl-elocations_meta.adb: vhdl-elocations_meta.adb.in vhdl-elocations.ads $(DEPS $(PNODES) $(ELOCATIONS_FLAGS) meta_body > $@ chmod -w $@ -../../python/libghdl/thin/vhdl/nodes.py: $(DEPS) $(PNODESPY) +../../pyGHDL/libghdl/vhdl/nodes.py: $(DEPS) $(PNODESPY) $(RM) $@ $(PNODESPY) $(NODES_FLAGS) libghdl-nodes > $@ chmod -w $@ -../../python/libghdl/thin/vhdl/nodes_meta.py: $(DEPS) $(PNODESPY) +../../pyGHDL/libghdl/vhdl/nodes_meta.py: $(DEPS) $(PNODESPY) $(RM) $@ $(PNODESPY) $(NODES_FLAGS) libghdl-meta > $@ chmod -w $@ -../../python/libghdl/thin/std_names.py: $(PNODESPY) ../std_names.ads +../../pyGHDL/libghdl/std_names.py: $(PNODESPY) ../std_names.ads $(RM) $@ $(PNODESPY) $(NODES_FLAGS) libghdl-names > $@ chmod -w $@ -../../python/libghdl/thin/vhdl/tokens.py: $(PNODESPY) vhdl-tokens.ads +../../pyGHDL/libghdl/vhdl/tokens.py: $(PNODESPY) vhdl-tokens.ads $(RM) $@ $(PNODESPY) $(NODES_FLAGS) libghdl-tokens > $@ chmod -w $@ -../../python/libghdl/thin/vhdl/elocations.py: $(PNODESPY) vhdl-elocations.ads +../../pyGHDL/libghdl/vhdl/elocations.py: $(PNODESPY) vhdl-elocations.ads $(RM) $@ $(PNODESPY) $(ELOCATIONS_FLAGS) libghdl-elocs > $@ chmod -w $@ -../../python/libghdl/thin/errorout.py: $(PNODESPY) ../errorout.ads +../../pyGHDL/libghdl/errorout.py: $(PNODESPY) ../errorout.ads $(RM) $@ $(PNODESPY) $(ELOCATIONS_FLAGS) libghdl-errorout > $@ chmod -w $@ -- cgit v1.2.3 From aec9873b7f2a175611f431b7f67840cdb74eee96 Mon Sep 17 00:00:00 2001 From: umarcor Date: Mon, 28 Dec 2020 21:17:56 +0100 Subject: doc: update 'using/py' -> 'using/pyGHDL' --- .github/workflows/doc.yml | 2 +- doc/index.rst | 2 +- doc/using/py/libghdl.rst | 13 -------- doc/using/py/pyutils.rst | 4 --- doc/using/py/thin.rst | 48 --------------------------- doc/using/py/vhdl.rst | 79 -------------------------------------------- doc/using/pyGHDL/index.rst | 11 ++++++ doc/using/pyGHDL/libghdl.rst | 49 +++++++++++++++++++++++++++ doc/using/pyGHDL/utils.rst | 4 +++ doc/using/pyGHDL/vhdl.rst | 79 ++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 145 insertions(+), 146 deletions(-) delete mode 100644 doc/using/py/libghdl.rst delete mode 100644 doc/using/py/pyutils.rst delete mode 100644 doc/using/py/thin.rst delete mode 100644 doc/using/py/vhdl.rst create mode 100644 doc/using/pyGHDL/index.rst create mode 100644 doc/using/pyGHDL/libghdl.rst create mode 100644 doc/using/pyGHDL/utils.rst create mode 100644 doc/using/pyGHDL/vhdl.rst diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 5cd33e03b..3ca172187 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -16,7 +16,7 @@ jobs: run: | docker build -t ghdl/doc - <<-EOF FROM ghdl/vunit:llvm - ENV PYTHONPATH=/src/python + ENV PYTHONPATH=/src/pyGHDL RUN apt update -qq && apt install -y gnat-gps \ && ln -s /usr/bin/pip3 /usr/bin/pip EOF diff --git a/doc/index.rst b/doc/index.rst index 8ea01b675..3fc554d56 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -145,7 +145,7 @@ GHDL using/Foreign using/ImplementationOfVHDL using/ImplementationOfVITAL - using/py/libghdl + using/pyGHDL/index .. raw:: latex diff --git a/doc/using/py/libghdl.rst b/doc/using/py/libghdl.rst deleted file mode 100644 index 7c95ab8c1..000000000 --- a/doc/using/py/libghdl.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _python_interface: - -Python Interface -################ - -.. automodule:: libghdl - -.. toctree:: - :hidden: - - thin - vhdl - pyutils diff --git a/doc/using/py/pyutils.rst b/doc/using/py/pyutils.rst deleted file mode 100644 index 58a84496a..000000000 --- a/doc/using/py/pyutils.rst +++ /dev/null @@ -1,4 +0,0 @@ -libghdl.thin.vhdl.pyutils -========================= - -.. automodule:: libghdl.thin.vhdl.pyutils diff --git a/doc/using/py/thin.rst b/doc/using/py/thin.rst deleted file mode 100644 index e02b48aec..000000000 --- a/doc/using/py/thin.rst +++ /dev/null @@ -1,48 +0,0 @@ -libghdl.thin -============ - -libghdl.thin.errorout ---------------------- - -.. automodule:: libghdl.thin.errorout - -libghdl.thin.errorout_console ------------------------------ - -.. automodule:: libghdl.thin.errorout_console - -libghdl.thin.errorout_memory ------------------------------ - -.. automodule:: libghdl.thin.errorout_memory - -libghdl.thin.files_map ----------------------- - -.. automodule:: libghdl.thin.files_map - -libghdl.thin.files_map_editor ------------------------------ - -.. automodule:: libghdl.thin.files_map_editor - -libghdl.thin.flags ------------------- - -.. automodule:: libghdl.thin.flags - -libghdl.thin.libraries ----------------------- - -.. automodule:: libghdl.thin.libraries - -libghdl.thin.name_table ------------------------ - -.. automodule:: libghdl.thin.name_table - -libghdl.thin.std_names ----------------------- - -.. automodule:: libghdl.thin.std_names - diff --git a/doc/using/py/vhdl.rst b/doc/using/py/vhdl.rst deleted file mode 100644 index e978cc6e8..000000000 --- a/doc/using/py/vhdl.rst +++ /dev/null @@ -1,79 +0,0 @@ -libghdl.thin.vhdl -================= - -.. automodule:: libghdl.thin.vhdl - -libghdl.thin.vhdl.canon ------------------------ - -.. automodule:: libghdl.thin.vhdl.canon - -libghdl.thin.vhdl.elocations ----------------------------- - -.. automodule:: libghdl.thin.vhdl.elocations - -libghdl.thin.vhdl.flists ------------------------- - -.. automodule:: libghdl.thin.vhdl.flists - -libghdl.thin.vhdl.formatters ----------------------------- - -.. automodule:: libghdl.thin.vhdl.formatters - -libghdl.thin.vhdl.ieee ----------------------- - -.. automodule:: libghdl.thin.vhdl.ieee - -libghdl.thin.vhdl.lists ------------------------ - -.. automodule:: libghdl.thin.vhdl.lists - -libghdl.thin.vhdl.nodes ------------------------ - -.. automodule:: libghdl.thin.vhdl.nodes - -libghdl.thin.vhdl.nodes_meta ----------------------------- - -.. automodule:: libghdl.thin.vhdl.nodes_meta - -libghdl.thin.vhdl.nodes_utils ------------------------------ - -.. automodule:: libghdl.thin.vhdl.nodes_utils - -libghdl.thin.vhdl.parse ------------------------ - -.. automodule:: libghdl.thin.vhdl.parse - -libghdl.thin.vhdl.scanner -------------------------- - -.. automodule:: libghdl.thin.vhdl.scanner - -libghdl.thin.vhdl.sem ---------------------- - -.. automodule:: libghdl.thin.vhdl.sem - -libghdl.thin.vhdl.sem_lib -------------------------- - -.. automodule:: libghdl.thin.vhdl.sem_lib - -libghdl.thin.vhdl.std_package ------------------------------ - -.. automodule:: libghdl.thin.vhdl.std_package - -libghdl.thin.vhdl.tokens ------------------------- - -.. automodule:: libghdl.thin.vhdl.tokens diff --git a/doc/using/pyGHDL/index.rst b/doc/using/pyGHDL/index.rst new file mode 100644 index 000000000..2b2191798 --- /dev/null +++ b/doc/using/pyGHDL/index.rst @@ -0,0 +1,11 @@ +.. _python_interface: + +Python Interface +################ + +.. toctree:: + :hidden: + + libghdl + vhdl + utils diff --git a/doc/using/pyGHDL/libghdl.rst b/doc/using/pyGHDL/libghdl.rst new file mode 100644 index 000000000..cc73b3a96 --- /dev/null +++ b/doc/using/pyGHDL/libghdl.rst @@ -0,0 +1,49 @@ +libghdl +======= + +.. automodule:: libghdl + +libghdl.errorout +---------------- + +.. automodule:: libghdl.errorout + +libghdl.errorout_console +------------------------ + +.. automodule:: libghdl.errorout_console + +libghdl.errorout_memory +----------------------- + +.. automodule:: libghdl.errorout_memory + +libghdl.files_map +----------------- + +.. automodule:: libghdl.files_map + +libghdl.files_map_editor +------------------------ + +.. automodule:: libghdl.files_map_editor + +libghdl.flags +------------- + +.. automodule:: libghdl.flags + +libghdl.libraries +----------------- + +.. automodule:: libghdl.libraries + +libghdl.name_table +------------------ + +.. automodule:: libghdl.name_table + +libghdl.std_names +----------------- + +.. automodule:: libghdl.std_names diff --git a/doc/using/pyGHDL/utils.rst b/doc/using/pyGHDL/utils.rst new file mode 100644 index 000000000..682cb198b --- /dev/null +++ b/doc/using/pyGHDL/utils.rst @@ -0,0 +1,4 @@ +libghdl.utils +=============== + +.. automodule:: libghdl.utils diff --git a/doc/using/pyGHDL/vhdl.rst b/doc/using/pyGHDL/vhdl.rst new file mode 100644 index 000000000..a18538011 --- /dev/null +++ b/doc/using/pyGHDL/vhdl.rst @@ -0,0 +1,79 @@ +libghdl.vhdl +============ + +.. automodule:: libghdl.vhdl + +libghdl.vhdl.canon +------------------ + +.. automodule:: libghdl.vhdl.canon + +libghdl.vhdl.elocations +----------------------- + +.. automodule:: libghdl.vhdl.elocations + +libghdl.vhdl.flists +------------------- + +.. automodule:: libghdl.vhdl.flists + +libghdl.vhdl.formatters +----------------------- + +.. automodule:: libghdl.vhdl.formatters + +libghdl.vhdl.ieee +----------------- + +.. automodule:: libghdl.vhdl.ieee + +libghdl.vhdl.lists +------------------ + +.. automodule:: libghdl.vhdl.lists + +libghdl.vhdl.nodes +------------------ + +.. automodule:: libghdl.vhdl.nodes + +libghdl.vhdl.nodes_meta +----------------------- + +.. automodule:: libghdl.vhdl.nodes_meta + +libghdl.vhdl.nodes_utils +------------------------ + +.. automodule:: libghdl.vhdl.nodes_utils + +libghdl.vhdl.parse +------------------ + +.. automodule:: libghdl.vhdl.parse + +libghdl.vhdl.scanner +-------------------- + +.. automodule:: libghdl.vhdl.scanner + +libghdl.vhdl.sem +---------------- + +.. automodule:: libghdl.vhdl.sem + +libghdl.vhdl.sem_lib +-------------------- + +.. automodule:: libghdl.vhdl.sem_lib + +libghdl.vhdl.std_package +------------------------ + +.. automodule:: libghdl.vhdl.std_package + +libghdl.vhdl.tokens +------------------- + +.. automodule:: libghdl.vhdl.tokens -- cgit v1.2.3 From 147375c38a56820595df54047ad904cdc21d94ec Mon Sep 17 00:00:00 2001 From: umarcor Date: Mon, 28 Dec 2020 20:49:18 +0100 Subject: merge testsuite/python into testsuite/pyunit --- dist/ci-run.sh | 4 +- testsuite/python/testsuite.sh | 53 ---------------- testsuite/python/units01/demo.vhdl | 12 ---- testsuite/python/units01/show_ports.py | 111 --------------------------------- testsuite/python/units01/show_units.py | 55 ---------------- testsuite/python/units01/testsuite.sh | 11 ---- testsuite/pyunit/testsuite.sh | 57 +++++++++++++++++ testsuite/pyunit/units01/demo.vhdl | 12 ++++ testsuite/pyunit/units01/show_ports.py | 111 +++++++++++++++++++++++++++++++++ testsuite/pyunit/units01/show_units.py | 55 ++++++++++++++++ testsuite/pyunit/units01/testsuite.sh | 11 ++++ testsuite/testsuite.sh | 28 ++++++++- 12 files changed, 273 insertions(+), 247 deletions(-) delete mode 100755 testsuite/python/testsuite.sh delete mode 100644 testsuite/python/units01/demo.vhdl delete mode 100644 testsuite/python/units01/show_ports.py delete mode 100755 testsuite/python/units01/show_units.py delete mode 100755 testsuite/python/units01/testsuite.sh create mode 100755 testsuite/pyunit/testsuite.sh create mode 100644 testsuite/pyunit/units01/demo.vhdl create mode 100644 testsuite/pyunit/units01/show_ports.py create mode 100755 testsuite/pyunit/units01/show_units.py create mode 100755 testsuite/pyunit/units01/testsuite.sh diff --git a/dist/ci-run.sh b/dist/ci-run.sh index cd4a2572b..eb82c7e99 100755 --- a/dist/ci-run.sh +++ b/dist/ci-run.sh @@ -420,12 +420,12 @@ ci_run () { if [ "x$IS_MACOS" = "xtrue" ]; then CC=clang \ prefix="`cd ./install-mcode; pwd`/usr/local" \ - ./testsuite/testsuite.sh sanity gna vests vpi + ./testsuite/testsuite.sh sanity pyunit gna vests vpi else # Build ghdl/ghdl:$GHDL_IMAGE_TAG image build_img_ghdl # Run test in docker container - tests="sanity" + tests="sanity pyunit" if [ "x$ISGPL" != "xtrue" ]; then tests="$tests gna" fi diff --git a/testsuite/python/testsuite.sh b/testsuite/python/testsuite.sh deleted file mode 100755 index 12b367f2c..000000000 --- a/testsuite/python/testsuite.sh +++ /dev/null @@ -1,53 +0,0 @@ -#! /bin/sh - -# Driver for a testsuite. - -set -e - -# This is the only place where test dirs are specified. Do not duplicate this -# line -dirs="*[0-9]" - -failures="" -full=n - -for opt; do - case "$opt" in - -k | --keep-going) full=y ;; - --dir=*) dirs=`echo $opt | sed -e 's/--dir=//'` ;; - --skip=*) d=`echo $opt | sed -e 's/--skip=//'` - dirs=`echo "" $dirs | sed -e "s/ $d//"` ;; - --start-at=*) d=`echo $opt | sed -e 's/--start-at=//'` - dirs=`echo "" $dirs | sed -e "s/^.* $d//"` - dirs="$d $dirs" ;; - --list-tests) echo $dirs; exit 0;; - *) echo "Unknown option $opt" - exit 2 - ;; - esac -done - -singlerun() { - echo "" - echo "dir $1:" - cd $1 - if ! ./testsuite.sh; then - echo "#################################################################" - echo "######### FAILURE: $1" - echo "#################################################################" - if [ $2 = "y" ]; then - failures="$failures $1" - else - exit 1; - fi - fi - cd .. -} - -for i in $dirs; do singlerun $i $full; done - -if [ x"$failures" = x"" ]; then - echo "tests are successful" && exit 0 -else - echo "test failed ($failures)" && exit 1 -fi diff --git a/testsuite/python/units01/demo.vhdl b/testsuite/python/units01/demo.vhdl deleted file mode 100644 index ed98c936a..000000000 --- a/testsuite/python/units01/demo.vhdl +++ /dev/null @@ -1,12 +0,0 @@ -entity e1 is -port ( - CLK: in std_logic; - RST: in std_logic; - Q: out std_logic_vector(7 downto 0) -); -end e1; - -architecture behav of e1 is -begin - assert false report "arch" severity note; -end behav; diff --git a/testsuite/python/units01/show_ports.py b/testsuite/python/units01/show_ports.py deleted file mode 100644 index a11f2acbd..000000000 --- a/testsuite/python/units01/show_ports.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python -from sys import argv -from pathlib import Path - -import libghdl -from libghdl.thin import name_table -from libghdl.thin import files_map -from libghdl.thin.vhdl import nodes -from libghdl.thin.vhdl import sem_lib -from libghdl.thin.vhdl import pyutils -from libghdl.thin import errorout_console - - -def get_identifier_ptr(n): - """Return the python string from node :param n: identifier""" - return name_table.Get_Name_Ptr(nodes.Get_Identifier(n)).decode("utf-8") - - -def get_port_mode(port) -> str: - """Return the Mode of a port, as a string""" - mode = nodes.Get_Mode(port) - return ( - "in" - if mode == nodes.Iir_Mode.In_Mode - else "out" - if mode == nodes.Iir_Mode.Out_Mode - else "inout" - if mode == nodes.Iir_Mode.Inout_Mode - else "buffer" - if mode == nodes.Iir_Mode.Buffer_Mode - else "linkage" - if mode == nodes.Iir_Mode.Linkage_Mode - else "unknown" - ) - - -def get_port_type(port) -> str: - "Return the Type of a port, as a string" - subtype = nodes.Get_Subtype_Indication(port) - skind = nodes.Get_Kind(subtype) - - if skind == nodes.Iir_Kind.Simple_Name: - return get_identifier_ptr(subtype) - - if skind == nodes.Iir_Kind.Array_Subtype_Definition: - mark = get_identifier_ptr(nodes.Get_Subtype_Type_Mark(subtype)) - - for rng in pyutils.flist_iter(nodes.Get_Index_Constraint_List(subtype)): - if nodes.Get_Kind(rng) == nodes.Iir_Kind.Range_Expression: - return "%s(%d %s %d)" % ( - mark, - nodes.Get_Value(nodes.Get_Left_Limit_Expr(rng)), - "downto" if nodes.Get_Direction(rng) else "to", - nodes.Get_Value(nodes.Get_Right_Limit_Expr(rng)), - ) - return "UNSUPPORTED array_subtype_definition" - - return "UNSUPPORTED" - - -def list_units(filename): - # Load the file - file_id = name_table.Get_Identifier(filename.encode("utf_8")) - sfe = files_map.Read_Source_File(name_table.Null_Identifier, file_id) - if sfe == files_map.No_Source_File_Entry: - print("cannot open file '%s'" % filename) - return - - # Parse - file = sem_lib.Load_File(sfe) - - # Display all design units - unit = nodes.Get_First_Design_Unit(file) - while unit != nodes.Null_Iir: - lib_unit = nodes.Get_Library_Unit(unit) - if nodes.Get_Kind(lib_unit) == nodes.Iir_Kind.Entity_Declaration: - print(" - entity %s" % get_identifier_ptr(lib_unit)) - for port in pyutils.chain_iter(nodes.Get_Port_Chain(lib_unit)): - print( - " * %s %s %s" - % ( - get_identifier_ptr(port), - get_port_mode(port), - get_port_type(port), - ) - ) - elif nodes.Get_Kind(lib_unit) == nodes.Iir_Kind.Architecture_Body: - print( - " - architecture %s of %s" - % ( - get_identifier_ptr(lib_unit), - get_identifier_ptr(nodes.Get_Entity_Name(lib_unit)), - ) - ) - else: - print("unknown unit!") - unit = nodes.Get_Chain(unit) - - -if __name__ == "__main__": - # Initialization: set options and then load libaries - errorout_console.Install_Handler() - libghdl.set_option(b"--std=08") - if libghdl.analyze_init_status() != 0: - raise Exception("libghdl initialization error") - - # Recursively find and parse all the files with extension *.vhdl - if len(argv) > 1: - for file in Path(argv[1]).glob("**/*.vhdl"): - print("· %s" % file) - list_units(str(file)) diff --git a/testsuite/python/units01/show_units.py b/testsuite/python/units01/show_units.py deleted file mode 100755 index 43baf9aed..000000000 --- a/testsuite/python/units01/show_units.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -import libghdl -from libghdl.thin import name_table -from libghdl.thin import files_map -from libghdl.thin.vhdl import nodes -from libghdl.thin.vhdl import sem_lib -from libghdl.thin import errorout_console - - -def init(): - """Initialization: set options and then load libaries""" - # Print error messages on the console - errorout_console.Install_Handler() - # Set options. This must be done before analyze_init() - libghdl.set_option(b"--std=08") - # Finish initialization. This will load the standard package - if libghdl.analyze_init_status() != 0: - raise Exception("libghdl initialization error") - -def get_identifier_ptr(n): - """Return the python string from node :param n: identifier""" - return name_table.Get_Name_Ptr(nodes.Get_Identifier(n)).decode("utf-8") - - -def list_units(filename): - # Load the file - file_id = name_table.Get_Identifier(filename.encode("utf_8")) - sfe = files_map.Read_Source_File(name_table.Null_Identifier, file_id) - if sfe == files_map.No_Source_File_Entry: - print("cannot open file '%s'" % filename) - return - - # Parse - file = sem_lib.Load_File(sfe) - - # Display all design units - unit = nodes.Get_First_Design_Unit(file) - while unit != nodes.Null_Iir: - lib_unit = nodes.Get_Library_Unit(unit) - if nodes.Get_Kind(lib_unit) == nodes.Iir_Kind.Entity_Declaration: - print("entity %s" % get_identifier_ptr(lib_unit)) - elif nodes.Get_Kind(lib_unit) == nodes.Iir_Kind.Architecture_Body: - print("architecture %s" % get_identifier_ptr(lib_unit)) - else: - print("unknown unit!") - unit = nodes.Get_Chain(unit) - - -def main(): - init() - list_units("demo.vhdl") - - -if __name__ == "__main__": - main() diff --git a/testsuite/python/units01/testsuite.sh b/testsuite/python/units01/testsuite.sh deleted file mode 100755 index f45d12ac3..000000000 --- a/testsuite/python/units01/testsuite.sh +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/sh - -. ../../testenv.sh - -$PYTHON show_units.py - -echo "" - -$PYTHON show_ports.py ./ - -echo "Test successful" diff --git a/testsuite/pyunit/testsuite.sh b/testsuite/pyunit/testsuite.sh new file mode 100755 index 000000000..7eac028ca --- /dev/null +++ b/testsuite/pyunit/testsuite.sh @@ -0,0 +1,57 @@ +#! /bin/sh + +# Driver for a testsuite. + +set -e + +# This is the only place where test dirs are specified. Do not duplicate this +# line +#dirs="*[0-9]" +# +#failures="" +#full=n +# +#for opt; do +# case "$opt" in +# -k | --keep-going) full=y ;; +# --dir=*) dirs=`echo $opt | sed -e 's/--dir=//'` ;; +# --skip=*) d=`echo $opt | sed -e 's/--skip=//'` +# dirs=`echo "" $dirs | sed -e "s/ $d//"` ;; +# --start-at=*) d=`echo $opt | sed -e 's/--start-at=//'` +# dirs=`echo "" $dirs | sed -e "s/^.* $d//"` +# dirs="$d $dirs" ;; +# --list-tests) echo $dirs; exit 0;; +# *) echo "Unknown option $opt" +# exit 2 +# ;; +# esac +#done +# +#singlerun() { +# echo "" +# echo "dir $1:" +# cd $1 +# if ! ./testsuite.sh; then +# echo "#################################################################" +# echo "######### FAILURE: $1" +# echo "#################################################################" +# if [ $2 = "y" ]; then +# failures="$failures $1" +# else +# exit 1; +# fi +# fi +# cd .. +#} +# +#for i in $dirs; do singlerun $i $full; done +# +#if [ x"$failures" = x"" ]; then +# echo "tests are successful" && exit 0 +#else +# echo "test failed ($failures)" && exit 1 +#fi + +cd $(dirname "$0")/.. + +python3 -m unittest pyunit diff --git a/testsuite/pyunit/units01/demo.vhdl b/testsuite/pyunit/units01/demo.vhdl new file mode 100644 index 000000000..ed98c936a --- /dev/null +++ b/testsuite/pyunit/units01/demo.vhdl @@ -0,0 +1,12 @@ +entity e1 is +port ( + CLK: in std_logic; + RST: in std_logic; + Q: out std_logic_vector(7 downto 0) +); +end e1; + +architecture behav of e1 is +begin + assert false report "arch" severity note; +end behav; diff --git a/testsuite/pyunit/units01/show_ports.py b/testsuite/pyunit/units01/show_ports.py new file mode 100644 index 000000000..a11f2acbd --- /dev/null +++ b/testsuite/pyunit/units01/show_ports.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +from sys import argv +from pathlib import Path + +import libghdl +from libghdl.thin import name_table +from libghdl.thin import files_map +from libghdl.thin.vhdl import nodes +from libghdl.thin.vhdl import sem_lib +from libghdl.thin.vhdl import pyutils +from libghdl.thin import errorout_console + + +def get_identifier_ptr(n): + """Return the python string from node :param n: identifier""" + return name_table.Get_Name_Ptr(nodes.Get_Identifier(n)).decode("utf-8") + + +def get_port_mode(port) -> str: + """Return the Mode of a port, as a string""" + mode = nodes.Get_Mode(port) + return ( + "in" + if mode == nodes.Iir_Mode.In_Mode + else "out" + if mode == nodes.Iir_Mode.Out_Mode + else "inout" + if mode == nodes.Iir_Mode.Inout_Mode + else "buffer" + if mode == nodes.Iir_Mode.Buffer_Mode + else "linkage" + if mode == nodes.Iir_Mode.Linkage_Mode + else "unknown" + ) + + +def get_port_type(port) -> str: + "Return the Type of a port, as a string" + subtype = nodes.Get_Subtype_Indication(port) + skind = nodes.Get_Kind(subtype) + + if skind == nodes.Iir_Kind.Simple_Name: + return get_identifier_ptr(subtype) + + if skind == nodes.Iir_Kind.Array_Subtype_Definition: + mark = get_identifier_ptr(nodes.Get_Subtype_Type_Mark(subtype)) + + for rng in pyutils.flist_iter(nodes.Get_Index_Constraint_List(subtype)): + if nodes.Get_Kind(rng) == nodes.Iir_Kind.Range_Expression: + return "%s(%d %s %d)" % ( + mark, + nodes.Get_Value(nodes.Get_Left_Limit_Expr(rng)), + "downto" if nodes.Get_Direction(rng) else "to", + nodes.Get_Value(nodes.Get_Right_Limit_Expr(rng)), + ) + return "UNSUPPORTED array_subtype_definition" + + return "UNSUPPORTED" + + +def list_units(filename): + # Load the file + file_id = name_table.Get_Identifier(filename.encode("utf_8")) + sfe = files_map.Read_Source_File(name_table.Null_Identifier, file_id) + if sfe == files_map.No_Source_File_Entry: + print("cannot open file '%s'" % filename) + return + + # Parse + file = sem_lib.Load_File(sfe) + + # Display all design units + unit = nodes.Get_First_Design_Unit(file) + while unit != nodes.Null_Iir: + lib_unit = nodes.Get_Library_Unit(unit) + if nodes.Get_Kind(lib_unit) == nodes.Iir_Kind.Entity_Declaration: + print(" - entity %s" % get_identifier_ptr(lib_unit)) + for port in pyutils.chain_iter(nodes.Get_Port_Chain(lib_unit)): + print( + " * %s %s %s" + % ( + get_identifier_ptr(port), + get_port_mode(port), + get_port_type(port), + ) + ) + elif nodes.Get_Kind(lib_unit) == nodes.Iir_Kind.Architecture_Body: + print( + " - architecture %s of %s" + % ( + get_identifier_ptr(lib_unit), + get_identifier_ptr(nodes.Get_Entity_Name(lib_unit)), + ) + ) + else: + print("unknown unit!") + unit = nodes.Get_Chain(unit) + + +if __name__ == "__main__": + # Initialization: set options and then load libaries + errorout_console.Install_Handler() + libghdl.set_option(b"--std=08") + if libghdl.analyze_init_status() != 0: + raise Exception("libghdl initialization error") + + # Recursively find and parse all the files with extension *.vhdl + if len(argv) > 1: + for file in Path(argv[1]).glob("**/*.vhdl"): + print("· %s" % file) + list_units(str(file)) diff --git a/testsuite/pyunit/units01/show_units.py b/testsuite/pyunit/units01/show_units.py new file mode 100755 index 000000000..43baf9aed --- /dev/null +++ b/testsuite/pyunit/units01/show_units.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +import libghdl +from libghdl.thin import name_table +from libghdl.thin import files_map +from libghdl.thin.vhdl import nodes +from libghdl.thin.vhdl import sem_lib +from libghdl.thin import errorout_console + + +def init(): + """Initialization: set options and then load libaries""" + # Print error messages on the console + errorout_console.Install_Handler() + # Set options. This must be done before analyze_init() + libghdl.set_option(b"--std=08") + # Finish initialization. This will load the standard package + if libghdl.analyze_init_status() != 0: + raise Exception("libghdl initialization error") + +def get_identifier_ptr(n): + """Return the python string from node :param n: identifier""" + return name_table.Get_Name_Ptr(nodes.Get_Identifier(n)).decode("utf-8") + + +def list_units(filename): + # Load the file + file_id = name_table.Get_Identifier(filename.encode("utf_8")) + sfe = files_map.Read_Source_File(name_table.Null_Identifier, file_id) + if sfe == files_map.No_Source_File_Entry: + print("cannot open file '%s'" % filename) + return + + # Parse + file = sem_lib.Load_File(sfe) + + # Display all design units + unit = nodes.Get_First_Design_Unit(file) + while unit != nodes.Null_Iir: + lib_unit = nodes.Get_Library_Unit(unit) + if nodes.Get_Kind(lib_unit) == nodes.Iir_Kind.Entity_Declaration: + print("entity %s" % get_identifier_ptr(lib_unit)) + elif nodes.Get_Kind(lib_unit) == nodes.Iir_Kind.Architecture_Body: + print("architecture %s" % get_identifier_ptr(lib_unit)) + else: + print("unknown unit!") + unit = nodes.Get_Chain(unit) + + +def main(): + init() + list_units("demo.vhdl") + + +if __name__ == "__main__": + main() diff --git a/testsuite/pyunit/units01/testsuite.sh b/testsuite/pyunit/units01/testsuite.sh new file mode 100755 index 000000000..f45d12ac3 --- /dev/null +++ b/testsuite/pyunit/units01/testsuite.sh @@ -0,0 +1,11 @@ +#! /bin/sh + +. ../../testenv.sh + +$PYTHON show_units.py + +echo "" + +$PYTHON show_ports.py ./ + +echo "Test successful" diff --git a/testsuite/testsuite.sh b/testsuite/testsuite.sh index fd686ccd0..b46ffcdc4 100755 --- a/testsuite/testsuite.sh +++ b/testsuite/testsuite.sh @@ -112,7 +112,7 @@ do_sanity () { [ "$failures" = "" ] || exit 1 } -# The GNA testsuite: regression testsuite using reports/issues from gna.org +# The GNA testsuite: regression testsuite using reports/issues from gna.org and from GitHub do_gna () { gstart "[GHDL - test] gna" cd gna @@ -138,6 +138,27 @@ do_gna () { [ "$failures" = "" ] || exit 1 } +# The Python Unit testsuite: regression testsuite for Python bindings to libghdl +do_pyunit () { + gstart "[GHDL - test] pyunit" + cd pyunit + + ./testsuite.sh + +# if ./testsuite.sh > test.log 2>&1 ; then +# printf "pyunit: ${ANSI_GREEN}ok${ANSI_NOCOLOR}\n" +# # Don't disp log +# else +# printf "pyunit: ${ANSI_RED}failed${ANSI_NOCOLOR}\n" +# cat test.log +# failures="$failures" +# fi + + cd .. + gend + [ "$failures" = "" ] || exit 1 +} + # The VESTS testsuite: compliance testsuite, from: https://github.com/nickg/vests.git 388250486a do_vests () { gstart "[GHDL - test] vests" @@ -226,7 +247,7 @@ for opt; do esac done -if [ "x$tests" = "x" ]; then tests="sanity gna vests synth vpi"; fi +if [ "x$tests" = "x" ]; then tests="sanity pyunit gna vests synth vpi"; fi echo "tests: $tests" @@ -234,10 +255,11 @@ echo "tests: $tests" do_test() { case $1 in sanity) do_sanity;; + pyunit) do_pyunit;; gna) do_gna;; vests) do_vests;; synth) do_synth;; - vpi) do_vpi;; + vpi) do_vpi;; *) printf "${ANSI_RED}$0: test name '$1' is unknown${ANSI_NOCOLOR}\n" exit 1;; -- cgit v1.2.3 From 1880a6086c63994029b2c56b4a9f9183b11f5d63 Mon Sep 17 00:00:00 2001 From: umarcor Date: Mon, 28 Dec 2020 21:46:06 +0100 Subject: ci: on ubuntu jobs, add temporary image with Python for testing 'pyunit' testsuite --- dist/ci-run.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dist/ci-run.sh b/dist/ci-run.sh index eb82c7e99..70e6b6d44 100755 --- a/dist/ci-run.sh +++ b/dist/ci-run.sh @@ -424,6 +424,18 @@ ci_run () { else # Build ghdl/ghdl:$GHDL_IMAGE_TAG image build_img_ghdl + case "$GHDL_IMAGE_TAG" in + *ubuntu*) + GHDL_TEST_IMAGE="test:$GHDL_IMAGE_TAG-py" + docker build -t "$GHDL_TEST_IMAGE" - <<-EOF +FROM ghdl/ghdl:$GHDL_IMAGE_TAG +RUN apt update -qq && apt install -y python3 +EOF + ;; + *) + GHDL_TEST_IMAGE="ghdl/ghdl:$GHDL_IMAGE_TAG" + ;; + esac # Run test in docker container tests="sanity pyunit" if [ "x$ISGPL" != "xtrue" ]; then @@ -434,7 +446,7 @@ ci_run () { tests="$tests synth" fi tests="$tests vpi" - $RUN "ghdl/ghdl:$GHDL_IMAGE_TAG" bash -c "GHDL=ghdl ./testsuite/testsuite.sh $tests" + $RUN "$GHDL_TEST_IMAGE" bash -c "GHDL=ghdl ./testsuite/testsuite.sh $tests" fi if [ ! -f testsuite/test_ok ]; then -- cgit v1.2.3 From 262c531cd39412ee3ea1e019f102b9cbfc698da0 Mon Sep 17 00:00:00 2001 From: umarcor Date: Mon, 28 Dec 2020 21:53:53 +0100 Subject: ci: MSYS2 job cleanup --- .github/workflows/push.yml | 32 ++++++++++----- dist/msys2-llvm/PKGBUILD | 24 +++++++++++ dist/msys2-mcode/PKGBUILD | 22 ++++++++++ dist/msys2-mingw/llvm/PKGBUILD | 24 ----------- dist/msys2-mingw/mcode/PKGBUILD | 22 ---------- dist/msys2-mingw/run.sh | 91 ----------------------------------------- 6 files changed, 67 insertions(+), 148 deletions(-) create mode 100644 dist/msys2-llvm/PKGBUILD create mode 100644 dist/msys2-mcode/PKGBUILD delete mode 100644 dist/msys2-mingw/llvm/PKGBUILD delete mode 100644 dist/msys2-mingw/mcode/PKGBUILD delete mode 100644 dist/msys2-mingw/run.sh diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 179b833e0..46346ae1e 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -115,15 +115,14 @@ jobs: max-parallel: 2 matrix: include: [ - {installs: "MINGW32", pkg: "mcode"}, - #{installs: "MINGW32", pkg: "llvm"}, ! Not yet functional - #{installs: "MINGW64", pkg: "mcode"}, ! mcode is not yet supported on win64 - {installs: "MINGW64", pkg: "llvm"}, + {installs: "MINGW32", arch: i686, pkg: "mcode"}, + #{installs: "MINGW32", arch: i686, pkg: "llvm"}, ! Not yet functional + #{installs: "MINGW64", arch: x86_64, pkg: "mcode"}, ! mcode is not yet supported on win64 + {installs: "MINGW64", arch: x86_64, pkg: "llvm"}, ] name: '🟪 MSYS2 · ${{ matrix.installs }} · ${{ matrix.pkg }}' env: MINGW_INSTALLS: ${{ matrix.installs }} - TARGET: ${{ matrix.pkg }} defaults: run: shell: msys2 {0} @@ -134,29 +133,40 @@ jobs: with: msystem: MSYS update: true - install: base-devel git + install: > + base-devel + git + mingw-w64-${{ matrix.arch }}-toolchain - run: git config --global core.autocrlf input shell: bash - name: '🧰 Checkout' uses: actions/checkout@v2 + with: + # The command 'git describe' (used for version) needs the history. + fetch-depth: 0 + + - name: Build package + run: | + cd dist/msys2-${{ matrix.pkg }} + makepkg-mingw --noconfirm --noprogressbar -sCLf - - name: Build and (hopefully) install package - run: ./dist/msys2-mingw/run.sh -b + - name: Install package + run: pacman --noconfirm -U dist/msys2-${{ matrix.pkg }}/mingw-w64-*-any.pkg.tar.zst - name: '📤 Upload artifact: builddir' uses: actions/upload-artifact@v2 with: name: ${{ matrix.installs }}-${{ matrix.pkg }}-builddir path: | - ./dist/msys2-mingw/${{ matrix.pkg }}/src/ - ./dist/msys2-mingw/${{ matrix.pkg }}/pkg/ + ./dist/msys2-${{ matrix.pkg }}/src/ + ./dist/msys2-${{ matrix.pkg }}/pkg/ - name: '📤 Upload artifact: package' uses: actions/upload-artifact@v2 with: - path: ./dist/msys2-mingw/${{ matrix.pkg }}/mingw-*ghdl*.pkg.tar.zst + path: ./dist/msys2-${{ matrix.pkg }}/mingw-*ghdl*.pkg.tar.zst - name: Test package run: | diff --git a/dist/msys2-llvm/PKGBUILD b/dist/msys2-llvm/PKGBUILD new file mode 100644 index 000000000..6de6916dc --- /dev/null +++ b/dist/msys2-llvm/PKGBUILD @@ -0,0 +1,24 @@ +_realname=ghdl-llvm +pkgbase=mingw-w64-${_realname} +pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}") +pkgver=ci +pkgrel=1 +pkgdesc="GHDL: the open-source analyzer, compiler, simulator and (experimental) synthesizer for VHDL (LLVM backend) (mingw-w64)" +arch=('any') +depends=('zlib-devel' "${MINGW_PACKAGE_PREFIX}-clang") +makedepends=("${MINGW_PACKAGE_PREFIX}-gcc-ada") + +build() { + mkdir "${srcdir}/builddir" + cd "${srcdir}/builddir" + export CC=clang + export CXX=clang++ + ../../../../configure --prefix=${MINGW_PREFIX} --with-llvm-config="llvm-config --link-static" LDFLAGS="-static" --enable-libghdl --enable-synth + make GNATMAKE="gnatmake -j$(nproc)" +} + +package() { + cd "${srcdir}/builddir" + mkdir -p "${pkgdir}${MINGW_PREFIX}/lib" + make DESTDIR="${pkgdir}" install +} diff --git a/dist/msys2-mcode/PKGBUILD b/dist/msys2-mcode/PKGBUILD new file mode 100644 index 000000000..70423d64d --- /dev/null +++ b/dist/msys2-mcode/PKGBUILD @@ -0,0 +1,22 @@ +_realname=ghdl-mcode +pkgbase=mingw-w64-${_realname} +pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}") +pkgver=ci +pkgrel=1 +pkgdesc="GHDL: the open-source analyzer, compiler, simulator and (experimental) synthesizer for VHDL (mcode backend) (mingw-w64)" +arch=('any') +depends=('zlib-devel') +makedepends=("${MINGW_PACKAGE_PREFIX}-gcc" "${MINGW_PACKAGE_PREFIX}-gcc-ada") + +build() { + mkdir "${srcdir}/builddir" + cd "${srcdir}/builddir" + ../../../../configure --prefix=${MINGW_PREFIX} LDFLAGS=-static --enable-libghdl --enable-synth + make GNATMAKE="gnatmake -j$(nproc)" +} + +package() { + cd "${srcdir}/builddir" + mkdir -p "${pkgdir}${MINGW_PREFIX}/lib" + make DESTDIR="${pkgdir}" install +} diff --git a/dist/msys2-mingw/llvm/PKGBUILD b/dist/msys2-mingw/llvm/PKGBUILD deleted file mode 100644 index 9fe2c28bd..000000000 --- a/dist/msys2-mingw/llvm/PKGBUILD +++ /dev/null @@ -1,24 +0,0 @@ -_realname=ghdl-llvm -pkgbase=mingw-w64-${_realname} -pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}") -pkgver=ci -pkgrel=1 -pkgdesc="GHDL: the open-source analyzer, compiler, simulator and (experimental) synthesizer for VHDL (LLVM backend) (mingw-w64)" -arch=('any') -depends=('zlib-devel' "${MINGW_PACKAGE_PREFIX}-clang") -makedepends=("${MINGW_PACKAGE_PREFIX}-gcc-ada") - -build() { - mkdir "${srcdir}/builddir" - cd "${srcdir}/builddir" - export CC=clang - export CXX=clang++ - ../../../../../configure --prefix=${MINGW_PREFIX} --with-llvm-config="llvm-config --link-static" LDFLAGS="-static" --enable-libghdl --enable-synth - make GNATMAKE="gnatmake -j$(nproc)" -} - -package() { - cd "${srcdir}/builddir" - mkdir -p "${pkgdir}${MINGW_PREFIX}/lib" - make DESTDIR="${pkgdir}" install -} diff --git a/dist/msys2-mingw/mcode/PKGBUILD b/dist/msys2-mingw/mcode/PKGBUILD deleted file mode 100644 index 75205b025..000000000 --- a/dist/msys2-mingw/mcode/PKGBUILD +++ /dev/null @@ -1,22 +0,0 @@ -_realname=ghdl-mcode -pkgbase=mingw-w64-${_realname} -pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}") -pkgver=ci -pkgrel=1 -pkgdesc="GHDL: the open-source analyzer, compiler, simulator and (experimental) synthesizer for VHDL (mcode backend) (mingw-w64)" -arch=('any') -depends=('zlib-devel') -makedepends=("${MINGW_PACKAGE_PREFIX}-gcc" "${MINGW_PACKAGE_PREFIX}-gcc-ada") - -build() { - mkdir "${srcdir}/builddir" - cd "${srcdir}/builddir" - ../../../../../configure --prefix=${MINGW_PREFIX} LDFLAGS=-static --enable-libghdl --enable-synth - make GNATMAKE="gnatmake -j$(nproc)" -} - -package() { - cd "${srcdir}/builddir" - mkdir -p "${pkgdir}${MINGW_PREFIX}/lib" - make DESTDIR="${pkgdir}" install -} diff --git a/dist/msys2-mingw/run.sh b/dist/msys2-mingw/run.sh deleted file mode 100644 index 186520b05..000000000 --- a/dist/msys2-mingw/run.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/sh - -cd $(dirname $0) - -# Stop in case of error -set -e - -enable_color() { - ENABLECOLOR='-c ' - ANSI_RED="\033[31m" - ANSI_GREEN="\033[32m" - ANSI_YELLOW="\033[33m" - ANSI_BLUE="\033[34m" - ANSI_MAGENTA="\033[35m" - ANSI_GRAY="\033[90m" - ANSI_CYAN="\033[36;1m" - ANSI_DARKCYAN="\033[36m" - ANSI_NOCOLOR="\033[0m" -} - -disable_color() { unset ENABLECOLOR ANSI_RED ANSI_GREEN ANSI_YELLOW ANSI_BLUE ANSI_MAGENTA ANSI_CYAN ANSI_DARKCYAN ANSI_NOCOLOR; } -enable_color - -print_start() { - if [ "x$2" != "x" ]; then - COL="$2" - elif [ "x$BASE_COL" != "x" ]; then - COL="$BASE_COL" - else - COL="$ANSI_YELLOW" - fi - printf "${COL}${1}$ANSI_NOCOLOR\n" -} - -gstart () { - print_start "$@" -} -gend () { - : -} -gblock () { - gstart "$1" - shift - $@ - gend -} - -[ -n "$CI" ] && { - echo "INFO: set 'gstart' and 'gend' for CI" - gstart () { - printf '::group::' - print_start "$@" - SECONDS=0 - } - - gend () { - duration=$SECONDS - echo '::endgroup::' - printf "${ANSI_GRAY}took $(($duration / 60)) min $(($duration % 60)) sec.${ANSI_NOCOLOR}\n" - } -} || echo "INFO: not in CI" - -#--- - -if [ -z "$TARGET" ]; then - printf "${ANSI_RED}Undefined TARGET!$ANSI_NOCOLOR" - exit 1 -fi -cd "$TARGET" - -# The command 'git describe' (used for version) needs the history. Get it. -# But the following command fails if the repository is complete. -gblock "Fetch --unshallow" git fetch --unshallow || true - -case "$MINGW_INSTALLS" in - *32) - TARBALL_ARCH="i686" - ;; - *64) - TARBALL_ARCH="x86_64" - ;; - *) - printf "${ANSI_RED}Unknown MINGW_INSTALLS=${MINGW_INSTALLS}!$ANSI_NOCOLOR" - exit 1 -esac - -gblock 'Install toolchain' pacman -S --noconfirm --needed base-devel mingw-w64-${TARBALL_ARCH}-toolchain -gblock 'Build package' makepkg-mingw --noconfirm --noprogressbar -sCLf --noarchive -gblock 'Archive package' makepkg-mingw --noconfirm --noprogressbar -R -gblock 'List artifacts' ls -la -gblock 'Install package' pacman --noconfirm -U "mingw-w64-${TARBALL_ARCH}-ghdl-${TARGET}-ci"-*-any.pkg.tar.zst -- cgit v1.2.3