def makechunk(nameofchunk="", typename="", **dictionary):
    """
    Create a chunk.

    Three values can be specified:
    
    (i) the name of the chunk (the name could be used if the chunk appears as a value of other chunks or production rules)
    (ii) its type
    (ii) slot-value pairs.

    For example:
    >>> makechunk(nameofchunk='example0', typename='chunktype_example0', value='one')
    chunktype_example0(value= one)

    This creates a chunk of type chunk1, which has one slot (value) and the value of that slot is one.
    """
    if not nameofchunk:
        nameofchunk = "unnamedchunk"
    if not typename:
        typename = "undefined" + str(Chunk._undefinedchunktypecounter)
        Chunk._undefinedchunktypecounter += 1
    for key in dictionary:
        if isinstance(dictionary[key], Chunk):
            pass
        elif isinstance(dictionary[key], utilities.VarvalClass):
            pass
        else:
            try:
                temp_dict = utilities.stringsplitting(str(dictionary[key]))
            except utilities.ACTRError as e:
                raise utilities.ACTRError(
                    "The chunk value %s is not defined correctly; %s" %
                    (dictionary[key], e))
            loop_dict = temp_dict.copy()
            for x in loop_dict:
                if x == "negvariables" or x == "negvalues":
                    val = tuple(temp_dict[x])
                else:
                    try:
                        val = temp_dict[x].pop()
                    except KeyError:
                        val = None
                temp_dict[x] = val
            dictionary[key] = utilities.VarvalClass(**temp_dict)

    created_chunk = Chunk(typename, **dictionary)
    created_chunk._chunks[nameofchunk] = created_chunk
    return created_chunk
    def __init__(self, typename, **dictionary):
        self.typename = typename
        self.boundvars = {}  #dict of bound variables

        kwargs = {}
        for key in dictionary:

            #change values (and values in a tuple) into string, when possible (when the value is not another chunk)
            if isinstance(dictionary[key], Chunk):
                dictionary[key] = utilities.VarvalClass(variables=None,
                                                        values=dictionary[key],
                                                        negvariables=(),
                                                        negvalues=())

            elif isinstance(dictionary[key], utilities.VarvalClass):
                for x in dictionary[key]._fields:
                    if x in {"values", "variables"} and not isinstance(
                            getattr(dictionary[key], x), str) and getattr(
                                dictionary[key],
                                x) != self.__emptyvalue and not isinstance(
                                    getattr(dictionary[key], x), Chunk):
                        raise TypeError(
                            "Values and variables must be strings, chunks or empty (None)"
                        )

                    elif x in {
                            "negvariables", "negvalues"
                    } and (not isinstance(getattr(dictionary[key], x),
                                          collections.abc.Sequence)
                           or isinstance(getattr(dictionary[key], x),
                                         collections.abc.MutableSequence)):
                        raise TypeError(
                            "Negvalues and negvariables must be tuples")

            elif (isinstance(dictionary[key], collections.abc.Iterable)
                  and not isinstance(dictionary[key], str)) or not isinstance(
                      dictionary[key], collections.abc.Hashable):
                raise ValueError(
                    "The value of a chunk slot must be hashable and not iterable; you are using an illegal type for the value of the chunk slot %s, namely %s"
                    % (key, type(dictionary[key])))

            else:
                #create namedtuple varval and split dictionary[key] into variables, values, negvariables, negvalues
                try:
                    temp_dict = utilities.stringsplitting(str(dictionary[key]))
                except utilities.ACTRError as e:
                    raise utilities.ACTRError(
                        "The chunk %s is not defined correctly; %s" %
                        (dictionary[key], e))
                loop_dict = temp_dict.copy()
                for x in loop_dict:
                    if x == "negvariables" or x == "negvalues":
                        val = tuple(temp_dict[x])
                    else:
                        try:
                            val = temp_dict[x].pop()
                        except KeyError:
                            val = None
                    temp_dict[x] = val
                dictionary[key] = utilities.VarvalClass(**temp_dict)

            #adding _ to minimize/avoid name clashes
            kwargs[key + "_"] = dictionary[key]
        try:
            for elem in self._chunktypes[typename]._fields:

                if elem not in kwargs:

                    kwargs[
                        elem] = self.__emptyvalue  #emptyvalues are explicitly added to attributes that were left out
                    dictionary[
                        elem[:
                             -1]] = self.__emptyvalue  #emptyvalues are also added to attributes in the original dictionary (since this might be used for chunktype creation later)

            if set(self._chunktypes[typename]._fields) != set(kwargs.keys()):

                chunktype(
                    typename, dictionary.keys()
                )  #If there are more args than in the original chunktype, chunktype has to be created again, with slots for new attributes
                warnings.warn("Chunk type %s is extended with new attributes" %
                              typename)

        except KeyError:

            chunktype(typename, dictionary.keys()
                      )  #If chunktype completely missing, it is created first
            warnings.warn(
                "Chunk type %s was not defined; added automatically" %
                typename)

        finally:
            self.actrchunk = self._chunktypes[typename](**kwargs)

        self.__empty = None  #this will store what the chunk looks like without empty values (the values will be stored on the first call of the relevant function)
        self.__unused = None  #this will store what the chunk looks like without unused values
        self.__hash = None, self.boundvars.copy(
        )  #this will store the hash along with variables (hash changes if some variables are resolved)
def createchunkdict(chunk):
    """
    Create typename and chunkdict from pyparsed list.
    """
    sp_dict = {
        utilities.ACTRVARIABLE: "variables",
        utilities.ACTRNEG: "negvalues",
        utilities.ACTRNEG + utilities.ACTRVARIABLE: "negvariables",
        utilities.ACTRVALUE: "values",
        utilities.ACTRNEG + utilities.ACTRVALUE: "negvalues"
    }
    chunk_dict = {}
    for elem in chunk:
        temp_dict = chunk_dict.get(
            elem[0],
            utilities.VarvalClass(variables=set(),
                                  values=set(),
                                  negvariables=set(),
                                  negvalues=set())._asdict())

        for idx in range(1, len(elem)):
            try:
                if elem[idx][0][0] == utilities.VISIONGREATER or elem[idx][0][
                        0] == utilities.VISIONSMALLER:  #this checks special visual conditions on greater/smaller than
                    if elem[idx][0][-1] == utilities.ACTRVARIABLE:
                        temp_dict['variables'].add(elem[idx][1])
                        update_val = elem[idx][0][0]
                    else:
                        update_val = elem[idx][0] + elem[idx][1]
                        #here fix
                    updating = 'values'
                elif elem[idx][1][0] == "'" or elem[idx][1][0] == '"':
                    updating = sp_dict[elem[idx][0]]
                    update_val = elem[idx][1][1:-1]
                else:
                    updating = sp_dict[elem[idx][0]]
                    update_val = elem[idx][1]

            except (
                    KeyError, IndexError
            ) as err:  #indexerror --> only a string is present; keyerror: the first element in elem[idx] is not a special symbol (in sp)
                if elem[idx][0] == "'" or elem[idx][0] == '"':
                    update_val = elem[idx][1:-1]
                else:
                    #check if the string is an existing chunk in the database of chunks
                    try:
                        update_val = Chunk._chunks[elem[idx]]
                    #if not, save it as a string
                    except KeyError:
                        update_val = elem[idx]
                updating = 'values'
            finally:
                temp_dict[updating].add(update_val)

        chunk_dict[elem[0]] = temp_dict

    for key in chunk_dict:
        chunk_dict[key]["negvalues"] = tuple(chunk_dict[key]["negvalues"])
        chunk_dict[key]["negvariables"] = tuple(
            chunk_dict[key]["negvariables"])
        for x in ["values", "variables"]:
            if len(chunk_dict[key][x]) > 1:
                raise utilities.ACTRError(
                    "Any slot must have fewer than two %s, there is more than one in this slot"
                    % x)
            elif len(chunk_dict[key][x]) == 1:
                chunk_dict[key][x] = chunk_dict[key][x].pop()
            else:
                chunk_dict[key][x] = None
        chunk_dict[key] = utilities.VarvalClass(**chunk_dict[key])
    type_chunk = ""
    try:
        type_chunk = chunk_dict.pop(
            "isa"
        ).values  #change this - any combination of capital/small letters
        type_chunk = chunk_dict.pop("ISA").values
        type_chunk = chunk_dict.pop("Isa").values
    except KeyError:
        pass
    return type_chunk, chunk_dict