// clang-format off
/*
*   $Id: lua.c 443 2006-05-30 04:37:13Z darren $
*
*   Copyright (c) 2000-2001, Max Ischenko <mfi@ukr.net>.
*
*   This source code is released for free distribution under the terms of the
*   GNU General Public License.
*
*   This module contains functions for generating tags for Lua language.
*/

/*
*   INCLUDE FILES
*/
#include "third_party/ctags/general.h"  /* must always come first */

#include "libc/mem/alg.h"
#include "libc/str/str.h"

#include "third_party/ctags/options.h"
#include "third_party/ctags/parse.h"
#include "third_party/ctags/read.h"
#include "third_party/ctags/vstring.h"

/*
*   DATA DEFINITIONS
*/
typedef enum {
	K_FUNCTION
} luaKind;

static kindOption LuaKinds [] = {
	{ TRUE, 'f', "function", "functions" }
};

/*
*   FUNCTION DEFINITIONS
*/

/* for debugging purposes */
static void __unused print_string (char *p, char *q)
{
	for ( ; p != q; p++)
		fprintf (errout, "%c", *p);
	fprintf (errout, "\n");
}

/*
 * Helper function.
 * Returns 1 if line looks like a line of Lua code.
 *
 * TODO: Recognize UNIX bang notation.
 * (Lua treat first line as a comment if it starts with #!)
 *
 */
static boolean is_a_code_line (const unsigned char *line)
{
	boolean result;
	const unsigned char *p = line;
	while (isspace ((int) *p))
		p++;
	if (p [0] == '\0')
		result = FALSE;
	else if (p [0] == '-' && p [1] == '-')
		result = FALSE;
	else
		result = TRUE;
	return result;
}

static void extract_name (const char *begin, const char *end, vString *name)
{
	if (begin != NULL  &&  end != NULL  &&  begin < end)
	{
		const char *cp;

		while (isspace ((int) *begin))
			begin++;
		while (isspace ((int) *end))
			end--;
		if (begin < end)
		{
			for (cp = begin ; cp != end; cp++)
				vStringPut (name, (int) *cp);
			vStringTerminate (name);

			makeSimpleTag (name, LuaKinds, K_FUNCTION);
			vStringClear (name);
		}
	}
}

static void findLuaTags (void)
{
	vString *name = vStringNew ();
	const unsigned char *line;

	while ((line = fileReadLine ()) != NULL)
	{
		const char *p, *q;

		if (! is_a_code_line (line))
			continue;

		p = (const char*) strstr ((const char*) line, "function");
		if (p == NULL)
			continue;

		q = strchr ((const char*) line, '=');
		
		if (q == NULL) {
			p = p + 9;  /* skip the `function' word */
			q = strchr ((const char*) p, '(');
			extract_name (p, q, name);
		} else {
			p = (const char*) &line[0];
			extract_name (p, q, name);
		}
	}
	vStringDelete (name);
}

extern parserDefinition* LuaParser (void)
{
	static const char* const extensions [] = { "lua", NULL };
	parserDefinition* def = parserNew ("Lua");
	def->kinds      = LuaKinds;
	def->kindCount  = KIND_COUNT (LuaKinds);
	def->extensions = extensions;
	def->parser     = findLuaTags;
	return def;
}

/* vi:set tabstop=4 shiftwidth=4: */
