xref: /Universal-ctags/parsers/yamlfrontmatter.c (revision 532866040b26c111e1e2a75f9383272afb02abfe)
1 /*
2 *
3 *   Copyright (c) 2022, Masatake YAMATO
4 *   Copyright (c) 2022, Red Hat, K.K.
5 *
6 *   This source code is released for free distribution under the terms of the
7 *   GNU General Public License version 2 or (at your option) any later version.
8 *
9 * This module contains functions for extracting language objects in FrontMatter
10 * using Yaml.
11 *
12 * https://gohugo.io/content-management/front-matter
13 */
14 
15 /*
16 *   INCLUDE FILES
17 */
18 #include "general.h"	/* must always come first */
19 
20 #include "frontmatter.h"
21 #include "yaml.h"
22 
23 #include "entry.h"
24 #include "gcc-attr.h"
25 #include "parse.h"
26 #include "read.h"
27 #include "subparser.h"
28 #include "trace.h"
29 
30 
31 /*
32 *   DATA DECLARATIONS
33 */
34 enum yamlfrontmatterDetectingState {
35 	DSTAT_LAST_KEY,
36 	DSTAT_LAST_VALUE,
37 	DSTAT_INITIAL,
38 };
39 
40 struct sYamlFrontMatterSubparser {
41 	yamlSubparser yaml;
42 	enum yamlfrontmatterDetectingState detection_state;
43 };
44 
45 
46 /*
47 *   FUNCTION PROTOTYPES
48 */
49 static bool yamlFrontmattterInitTagEntry (tagEntryInfo *e, char *name, void *data);
50 
51 
52 /*
53 *   DATA DEFINITIONS
54 */
55 
56 static langType frontMatterLang;
57 
58 static tagYpathTable ypathTables [] = {
59 	{
60 		"title",
61 		DSTAT_LAST_VALUE,
62 		.initTagEntry = yamlFrontmattterInitTagEntry,
63 	},
64 };
65 
66 
67 /*
68 *   FUNCTION DEFINITIONS
69 */
70 
yamlfrontmatterStateMachine(struct sYamlFrontMatterSubparser * yamlfrontmatter,yaml_token_t * token)71 static void	yamlfrontmatterStateMachine (struct sYamlFrontMatterSubparser *yamlfrontmatter,
72 								 yaml_token_t *token)
73 {
74 #ifdef DO_TRACING
75 	ypathPrintTypeStack (YAML(yamlfrontmatter));
76 #endif
77 
78 	switch (token->type)
79 	{
80 	case YAML_KEY_TOKEN:
81 		yamlfrontmatter->detection_state = DSTAT_LAST_KEY;
82 		break;
83 	case YAML_SCALAR_TOKEN:
84 		switch (yamlfrontmatter->detection_state)
85 		{
86 		case DSTAT_LAST_KEY:
87 			ypathFillKeywordOfTokenMaybe (YAML(yamlfrontmatter), token, getInputLanguage ());
88 			/* FALL THROUGH */
89 		case DSTAT_LAST_VALUE:
90 			TRACE_PRINT("token-callback: %s: %s",
91 						(yamlfrontmatter->detection_state == DSTAT_LAST_KEY)? "key": "value",
92 						(char*)token->data.scalar.value);
93 			ypathHandleToken (YAML(yamlfrontmatter), token, yamlfrontmatter->detection_state,
94 							  ypathTables, ARRAY_SIZE (ypathTables));
95 			break;
96 		default:
97 			break;
98 		}
99 
100 		yamlfrontmatter->detection_state = DSTAT_INITIAL;
101 
102 		break;
103 	case YAML_VALUE_TOKEN:
104 		yamlfrontmatter->detection_state = DSTAT_LAST_VALUE;
105 		break;
106 
107 	default:
108 		yamlfrontmatter->detection_state = DSTAT_INITIAL;
109 		break;
110 	}
111 }
112 
newTokenCallback(yamlSubparser * s,yaml_token_t * token)113 static void newTokenCallback (yamlSubparser *s, yaml_token_t *token)
114 {
115 	if (token->type == YAML_BLOCK_SEQUENCE_START_TOKEN
116 		|| token->type == YAML_BLOCK_MAPPING_START_TOKEN)
117 		ypathPushType (s, token);
118 
119 	yamlfrontmatterStateMachine ((struct sYamlFrontMatterSubparser *)s, token);
120 
121 	if (token->type == YAML_BLOCK_END_TOKEN)
122 		ypathPopType (s);
123 	else if (token->type == YAML_STREAM_END_TOKEN)
124 		ypathPopAllTypes (s);
125 }
126 
yamlFrontmattterInitTagEntry(tagEntryInfo * e,char * name,void * data CTAGS_ATTR_UNUSED)127 static bool yamlFrontmattterInitTagEntry (tagEntryInfo *e, char *name, void * data CTAGS_ATTR_UNUSED)
128 {
129 	initForeignTagEntry (e, name, frontMatterLang, FRONTMATTER_TITLE_KIND);
130 	return true;
131 }
132 
yamlFrontMatterInputStart(subparser * s)133 static void yamlFrontMatterInputStart(subparser *s)
134 {
135 	((struct sYamlFrontMatterSubparser*)s)->detection_state = DSTAT_INITIAL;
136 	((yamlSubparser*)s)->ypathTypeStack = NULL;
137 }
138 
yamlFrontMatterInputEnd(subparser * s)139 static void yamlFrontMatterInputEnd(subparser *s)
140 {
141 	Assert (((yamlSubparser*)s)->ypathTypeStack == NULL);
142 }
143 
findYamlFrontMatterTags(void)144 static void findYamlFrontMatterTags (void)
145 {
146 	scheduleRunningBaseparser (0);
147 }
148 
yamlFrontMatterInitialize(langType language)149 static void yamlFrontMatterInitialize (langType language)
150 {
151 	ypathCompileTables (language, ypathTables, ARRAY_SIZE (ypathTables), 0);
152 	frontMatterLang = getNamedLanguage ("FrontMatter", 0);
153 }
154 
yamlFrontMatterFinalize(langType language,bool initialized)155 static void yamlFrontMatterFinalize (langType language, bool initialized)
156 {
157 	if (initialized)
158 		ypathCompiledCodeDelete (ypathTables, ARRAY_SIZE (ypathTables));
159 }
160 
YamlFrontMatter(void)161 extern parserDefinition* YamlFrontMatter (void)
162 {
163 	static struct sYamlFrontMatterSubparser yamlfrontmatterSubparser = {
164 		.yaml = {
165 			.subparser = {
166 				.direction = SUBPARSER_SUB_RUNS_BASE,
167 				.inputStart = yamlFrontMatterInputStart,
168 				.inputEnd = yamlFrontMatterInputEnd,
169 			},
170 			.newTokenNotfify = newTokenCallback
171 		},
172 	};
173 	static parserDependency dependencies [] = {
174 		{ DEPTYPE_SUBPARSER, "Yaml", &yamlfrontmatterSubparser },
175 		{ DEPTYPE_FOREIGNER, "FrontMatter", NULL },
176 	};
177 
178 	parserDefinition* const def = parserNew ("YamlFrontMatter");
179 
180 	def->dependencies = dependencies;
181 	def->dependencyCount = ARRAY_SIZE (dependencies);
182 
183 	def->kindTable	= NULL;
184 	def->kindCount = 0;
185 	def->parser	= findYamlFrontMatterTags;
186 	def->initialize = yamlFrontMatterInitialize;
187 	def->finalize = yamlFrontMatterFinalize;
188 
189 	/* This parser runs ONLY as a part of FrontMatter parser.
190 	 * User may not want to enable/disable this parser directly. */
191 	def->invisible = true;
192 
193 	return def;
194 }
195