xref: /Universal-ctags/parsers/erlang.c (revision 0d502ef01a06f2d53250c160a71a28508c360d68)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO *   Copyright (c) 2003, Brent Fulgham <bfulgham@debian.org>
33ae02089SMasatake YAMATO *
43ae02089SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
63ae02089SMasatake YAMATO *
73ae02089SMasatake YAMATO *   This module contains functions for generating tags for Erlang language
83ae02089SMasatake YAMATO *   files.  Some of the parsing constructs are based on the Emacs 'etags'
93ae02089SMasatake YAMATO *   program by Francesco Potori <pot@gnu.org>
103ae02089SMasatake YAMATO */
113ae02089SMasatake YAMATO /*
123ae02089SMasatake YAMATO *   INCLUDE FILES
133ae02089SMasatake YAMATO */
143ae02089SMasatake YAMATO #include "general.h"  /* must always come first */
153ae02089SMasatake YAMATO 
163ae02089SMasatake YAMATO #include <string.h>
173ae02089SMasatake YAMATO 
183ae02089SMasatake YAMATO #include "entry.h"
193ae02089SMasatake YAMATO #include "read.h"
20*0d502ef0SMasatake YAMATO #include "parse.h"
213ae02089SMasatake YAMATO #include "routines.h"
223ae02089SMasatake YAMATO #include "vstring.h"
233ae02089SMasatake YAMATO 
243ae02089SMasatake YAMATO /*
253ae02089SMasatake YAMATO *   DATA DEFINITIONS
263ae02089SMasatake YAMATO */
273ae02089SMasatake YAMATO typedef enum {
283ae02089SMasatake YAMATO 	K_MACRO, K_FUNCTION, K_MODULE, K_RECORD, K_TYPE
293ae02089SMasatake YAMATO } erlangKind;
303ae02089SMasatake YAMATO 
31e112e8abSMasatake YAMATO static kindDefinition ErlangKinds[] = {
32ce990805SThomas Braun 	{true, 'd', "macro",    "macro definitions"},
33ce990805SThomas Braun 	{true, 'f', "function", "functions"},
34ce990805SThomas Braun 	{true, 'm', "module",   "modules"},
35ce990805SThomas Braun 	{true, 'r', "record",   "record definitions"},
36ce990805SThomas Braun 	{true, 't', "type",     "type definitions"},
373ae02089SMasatake YAMATO };
383ae02089SMasatake YAMATO 
393ae02089SMasatake YAMATO /*
403ae02089SMasatake YAMATO *   FUNCTION DEFINITIONS
413ae02089SMasatake YAMATO */
423ae02089SMasatake YAMATO /* tagEntryInfo and vString should be preinitialized/preallocated but not
433ae02089SMasatake YAMATO  * necessary. If successful you will find class name in vString
443ae02089SMasatake YAMATO  */
453ae02089SMasatake YAMATO 
isIdentifierFirstCharacter(int c)46ce990805SThomas Braun static bool isIdentifierFirstCharacter (int c)
473ae02089SMasatake YAMATO {
48ce990805SThomas Braun 	return (bool) (isalpha (c));
493ae02089SMasatake YAMATO }
503ae02089SMasatake YAMATO 
isIdentifierCharacter(int c)51ce990805SThomas Braun static bool isIdentifierCharacter (int c)
523ae02089SMasatake YAMATO {
53ce990805SThomas Braun 	return (bool) (isalnum (c) || c == '_' || c == ':');
543ae02089SMasatake YAMATO }
553ae02089SMasatake YAMATO 
skipSpace(const unsigned char * cp)563ae02089SMasatake YAMATO static const unsigned char *skipSpace (const unsigned char *cp)
573ae02089SMasatake YAMATO {
583ae02089SMasatake YAMATO 	while (isspace ((int) *cp))
593ae02089SMasatake YAMATO 		++cp;
603ae02089SMasatake YAMATO 	return cp;
613ae02089SMasatake YAMATO }
623ae02089SMasatake YAMATO 
parseIdentifier(const unsigned char * cp,vString * const identifier)633ae02089SMasatake YAMATO static const unsigned char *parseIdentifier (
643ae02089SMasatake YAMATO 		const unsigned char *cp, vString *const identifier)
653ae02089SMasatake YAMATO {
663ae02089SMasatake YAMATO 	vStringClear (identifier);
673ae02089SMasatake YAMATO 	while (isIdentifierCharacter ((int) *cp))
683ae02089SMasatake YAMATO 	{
693ae02089SMasatake YAMATO 		vStringPut (identifier, (int) *cp);
703ae02089SMasatake YAMATO 		++cp;
713ae02089SMasatake YAMATO 	}
723ae02089SMasatake YAMATO 	return cp;
733ae02089SMasatake YAMATO }
743ae02089SMasatake YAMATO 
makeMemberTag(vString * const identifier,erlangKind kind,vString * const module)753ae02089SMasatake YAMATO static void makeMemberTag (
763ae02089SMasatake YAMATO 		vString *const identifier, erlangKind kind, vString *const module)
773ae02089SMasatake YAMATO {
783ae02089SMasatake YAMATO 	if (ErlangKinds [kind].enabled  &&  vStringLength (identifier) > 0)
793ae02089SMasatake YAMATO 	{
803ae02089SMasatake YAMATO 		tagEntryInfo tag;
8116a2541cSMasatake YAMATO 		initTagEntry (&tag, vStringValue (identifier), kind);
823ae02089SMasatake YAMATO 
833ae02089SMasatake YAMATO 		if (module != NULL  &&  vStringLength (module) > 0)
843ae02089SMasatake YAMATO 		{
85f92e6bf2SMasatake YAMATO 			tag.extensionFields.scopeKindIndex = K_MODULE;
86015ab54cSMasatake YAMATO 			tag.extensionFields.scopeName = vStringValue (module);
873ae02089SMasatake YAMATO 		}
883ae02089SMasatake YAMATO 		makeTagEntry (&tag);
893ae02089SMasatake YAMATO 	}
903ae02089SMasatake YAMATO }
913ae02089SMasatake YAMATO 
parseModuleTag(const unsigned char * cp,vString * const module)923ae02089SMasatake YAMATO static void parseModuleTag (const unsigned char *cp, vString *const module)
933ae02089SMasatake YAMATO {
943ae02089SMasatake YAMATO 	vString *const identifier = vStringNew ();
953ae02089SMasatake YAMATO 	parseIdentifier (cp, identifier);
9616a2541cSMasatake YAMATO 	makeSimpleTag (identifier, K_MODULE);
973ae02089SMasatake YAMATO 
983ae02089SMasatake YAMATO 	/* All further entries go in the new module */
993ae02089SMasatake YAMATO 	vStringCopy (module, identifier);
1003ae02089SMasatake YAMATO 	vStringDelete (identifier);
1013ae02089SMasatake YAMATO }
1023ae02089SMasatake YAMATO 
parseSimpleTag(const unsigned char * cp,erlangKind kind)1033ae02089SMasatake YAMATO static void parseSimpleTag (const unsigned char *cp, erlangKind kind)
1043ae02089SMasatake YAMATO {
1053ae02089SMasatake YAMATO 	vString *const identifier = vStringNew ();
1063ae02089SMasatake YAMATO 	parseIdentifier (cp, identifier);
10716a2541cSMasatake YAMATO 	makeSimpleTag (identifier, kind);
1083ae02089SMasatake YAMATO 	vStringDelete (identifier);
1093ae02089SMasatake YAMATO }
1103ae02089SMasatake YAMATO 
parseFunctionTag(const unsigned char * cp,vString * const module)1113ae02089SMasatake YAMATO static void parseFunctionTag (const unsigned char *cp, vString *const module)
1123ae02089SMasatake YAMATO {
1133ae02089SMasatake YAMATO 	vString *const identifier = vStringNew ();
1143ae02089SMasatake YAMATO 	parseIdentifier (cp, identifier);
1153ae02089SMasatake YAMATO 	makeMemberTag (identifier, K_FUNCTION, module);
1163ae02089SMasatake YAMATO 	vStringDelete (identifier);
1173ae02089SMasatake YAMATO }
1183ae02089SMasatake YAMATO 
1193ae02089SMasatake YAMATO /*
1203ae02089SMasatake YAMATO  * Directives are of the form:
1213ae02089SMasatake YAMATO  * -module(foo)
1223ae02089SMasatake YAMATO  * -define(foo, bar)
1233ae02089SMasatake YAMATO  * -record(graph, {vtab = notable, cyclic = true}).
1243ae02089SMasatake YAMATO  * -type some_type() :: any().
1253ae02089SMasatake YAMATO  * -opaque some_opaque_type() :: any().
1263ae02089SMasatake YAMATO  */
parseDirective(const unsigned char * cp,vString * const module)1273ae02089SMasatake YAMATO static void parseDirective (const unsigned char *cp, vString *const module)
1283ae02089SMasatake YAMATO {
1293ae02089SMasatake YAMATO 	/*
1303ae02089SMasatake YAMATO 	 * A directive will be either a record definition or a directive.
1313ae02089SMasatake YAMATO 	 * Record definitions are handled separately
1323ae02089SMasatake YAMATO 	 */
1333ae02089SMasatake YAMATO 	vString *const directive = vStringNew ();
1343ae02089SMasatake YAMATO 	const char *const drtv = vStringValue (directive);
1353ae02089SMasatake YAMATO 	cp = parseIdentifier (cp, directive);
1363ae02089SMasatake YAMATO 	cp = skipSpace (cp);
1373ae02089SMasatake YAMATO 	if (*cp == '(')
1383ae02089SMasatake YAMATO 		++cp;
1393ae02089SMasatake YAMATO 
1403ae02089SMasatake YAMATO 	if (strcmp (drtv, "record") == 0)
1413ae02089SMasatake YAMATO 		parseSimpleTag (cp, K_RECORD);
1423ae02089SMasatake YAMATO 	else if (strcmp (drtv, "define") == 0)
1433ae02089SMasatake YAMATO 		parseSimpleTag (cp, K_MACRO);
1443ae02089SMasatake YAMATO 	else if (strcmp (drtv, "type") == 0)
1453ae02089SMasatake YAMATO 		parseSimpleTag (cp, K_TYPE);
1463ae02089SMasatake YAMATO 	else if (strcmp (drtv, "opaque") == 0)
1473ae02089SMasatake YAMATO 		parseSimpleTag (cp, K_TYPE);
1483ae02089SMasatake YAMATO 	else if (strcmp (drtv, "module") == 0)
1493ae02089SMasatake YAMATO 		parseModuleTag (cp, module);
1503ae02089SMasatake YAMATO 	/* Otherwise, it was an import, export, etc. */
1513ae02089SMasatake YAMATO 
1523ae02089SMasatake YAMATO 	vStringDelete (directive);
1533ae02089SMasatake YAMATO }
1543ae02089SMasatake YAMATO 
findErlangTags(void)1553ae02089SMasatake YAMATO static void findErlangTags (void)
1563ae02089SMasatake YAMATO {
1573ae02089SMasatake YAMATO 	vString *const module = vStringNew ();
1583ae02089SMasatake YAMATO 	const unsigned char *line;
1593ae02089SMasatake YAMATO 
1601b312fe7SMasatake YAMATO 	while ((line = readLineFromInputFile ()) != NULL)
1613ae02089SMasatake YAMATO 	{
1623ae02089SMasatake YAMATO 		const unsigned char *cp = line;
1633ae02089SMasatake YAMATO 
1643ae02089SMasatake YAMATO 		if (*cp == '%')  /* skip initial comment */
1653ae02089SMasatake YAMATO 			continue;
1663ae02089SMasatake YAMATO 		if (*cp == '"')  /* strings sometimes start in column one */
1673ae02089SMasatake YAMATO 			continue;
1683ae02089SMasatake YAMATO 
1693ae02089SMasatake YAMATO 		if ( *cp == '-')
1703ae02089SMasatake YAMATO 		{
1713ae02089SMasatake YAMATO 			++cp;  /* Move off of the '-' */
1723ae02089SMasatake YAMATO 			parseDirective(cp, module);
1733ae02089SMasatake YAMATO 		}
1743ae02089SMasatake YAMATO 		else if (isIdentifierFirstCharacter ((int) *cp))
1753ae02089SMasatake YAMATO 			parseFunctionTag (cp, module);
1763ae02089SMasatake YAMATO 	}
1773ae02089SMasatake YAMATO 	vStringDelete (module);
1783ae02089SMasatake YAMATO }
1793ae02089SMasatake YAMATO 
ErlangParser(void)1803ae02089SMasatake YAMATO extern parserDefinition *ErlangParser (void)
1813ae02089SMasatake YAMATO {
1823ae02089SMasatake YAMATO 	static const char *const extensions[] = { "erl", "ERL", "hrl", "HRL", NULL };
1833ae02089SMasatake YAMATO 	parserDefinition *def = parserNew ("Erlang");
18409ae690fSMasatake YAMATO 	def->kindTable = ErlangKinds;
1853db72c21SMasatake YAMATO 	def->kindCount = ARRAY_SIZE (ErlangKinds);
1863ae02089SMasatake YAMATO 	def->extensions = extensions;
1873ae02089SMasatake YAMATO 	def->parser = findErlangTags;
1883ae02089SMasatake YAMATO 	return def;
1893ae02089SMasatake YAMATO }
190