public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List <IExpression> args)
        {
            // Multiply multiplies a list of values - we thus have to handle _each_ arg
            // Note: we get a single argument which is an expression resulting in a list of values
            var listToMultiply = args[0];
            var mappings       = new List <Mapping>();
            var arg            = new List <IExpression>();

            if (UnApply(UnApply(
                            IsFunc(Funcs.StringStringToTags),
                            IsMapping(mappings)),
                        Assign(arg)
                        ).Invoke(listToMultiply))
            {
                var mapping = mappings.First();

                var result     = assignTo + " = " + _neutralValue + "\n";
                var mappingArg = arg.First();
                if (!Equals(mappingArg.Types.First(), Typs.Tags))
                {
                    return(null);
                }

                string tags;
                if (mappingArg is LuaLiteral literal)
                {
                    tags = literal.Lua;
                }
                else
                {
                    tags    = lua.FreeVar("tags");
                    result += "local " + tags + " = nil\n";
                    result += Snippets.Convert(lua, tags, mappingArg);
                }

                var m = lua.FreeVar("m");
                result += "    local " + m + " = nil\n";

                foreach (var(key, func) in mapping.StringToResultFunctions)
                {
                    result += "if (" + tags + "[\"" + key + "\"] ~= nil) then\n";
                    result += m + " = nil\n";
                    result += "    " +
                              Snippets.Convert(lua, m,
                                               func.Apply(new LuaLiteral(Typs.String, tags + "[\"" + key + "\"]"))).Indent() + "\n";
                    result += "\n\n    if (" + m + " ~= nil) then\n        " +
                              Combine(assignTo, m) +
                              "\n    end\n";
                    result += "end\n";
                }

                return(result);
            }


            var listDotArgs = new List <IExpression>();

            if (UnApply(
                    UnApply(IsFunc(Funcs.ListDot),
                            Assign(listDotArgs)),
                    Assign(arg)
                    ).Invoke(listToMultiply))
            {
                var listDotArg = arg.First();
                if (!(listDotArgs.First().Evaluate(lua.Context) is List <IExpression> functionsToApply))
                {
                    return(null);
                }

                var    result = "    " + assignTo + " = " + _neutralValue + "\n";
                string tags;
                if (listDotArg is LuaLiteral literal)
                {
                    tags = literal.Lua;
                }
                else
                {
                    tags    = lua.FreeVar("tags");
                    result += "    local " + tags + "\n";
                    result += Snippets.Convert(lua, tags, listDotArg);
                }

                var m = lua.FreeVar("m");
                result += "    local " + m + "\n";
                foreach (var func in functionsToApply)
                {
                    result += "    " + m + " = nil\n";
                    var subMapping = ExtractSubMapping(func);
                    if (subMapping != null)
                    {
                        var(key, f) = subMapping.Value;
                        var e = f.Apply(new LuaLiteral(Typs.String, tags + "[\"" + key + "\"]"));
                        e       = e.Optimize();
                        result += Snippets.Convert(lua, m, e).Indent();
                    }
                    else
                    {
                        result += Snippets.Convert(lua, m, func.Apply(new LuaLiteral(Typs.Tags, "tags")));
                    }


                    result += "\n\n    if (" + m + " ~= nil) then\n        " + Combine(assignTo, m) + "\n    end\n";
                }


                return(result);
            }


            throw new NotImplementedException();
        }
        public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List <IExpression> args)
        {
            var c = lua.Context;

            if (!(args[0].Evaluate(c) is List <IExpression> order))
            {
                return(null);
            }

            List <Mapping> mappings = new List <Mapping>();

            if (!UnApply(
                    IsFunc(Funcs.StringStringToTags),
                    IsMapping(mappings)
                    ).Invoke(args[1]))
            {
                return(null);
            }

            if (mappings.Count != 1)
            {
                throw new Exception("Multiple possible implementations at this point - should not happen");
            }

            if (mappings.Count == 0)
            {
            }
            var mapping = mappings.First();
            var tags    = args[2];

            var varName = "tags";

            var result = "";

            if (tags is LuaLiteral literal)
            {
                varName = literal.Lua;
            }
            else
            {
                result += Snippets.Convert(lua, "tags", tags);
            }

            // We _reverse_ the order, so that the _most_ important one is at the _bottom_
            // The most important one will then _overwrite_ the result value
            order.Reverse();
            foreach (var t in order)
            {
                if (!(t.Evaluate(c) is string key))
                {
                    return(null);
                }

                var func = mapping.StringToResultFunctions[key];

                result += "if (" + varName + "[\"" + key + "\"] ~= nil) then\n";
                result += "    " + Snippets.Convert(lua, assignTo, func.Apply(new LuaLiteral(Typs.String, "tags[\"" + key + "\"]"))).Indent();
                result += "\n";
                result += "end\n";
                // note: we do not do an 'elseif' as we have to fallthrough
                if (result.Contains("tags[\"nil\"]"))
                {
                    Console.WriteLine("EUHM");
                }
            }

            return(result);
        }