xref: /Universal-ctags/parsers/ansibleplaybook.c (revision 9b034e2a470a28f764b92f4a51033fba645df9a0)
1bddf5c8aSMasatake YAMATO /*
2bddf5c8aSMasatake YAMATO *
3bddf5c8aSMasatake YAMATO *   Copyright (c) 2016, Masatake YAMATO
4bddf5c8aSMasatake YAMATO *   Copyright (c) 2016, Red Hat, K.K.
5bddf5c8aSMasatake YAMATO *
6bddf5c8aSMasatake YAMATO *   This source code is released for free distribution under the terms of the
7bddf5c8aSMasatake YAMATO *   GNU General Public License version 2 or (at your option) any later version.
8bddf5c8aSMasatake YAMATO *
9bddf5c8aSMasatake YAMATO */
10bddf5c8aSMasatake YAMATO 
11bddf5c8aSMasatake YAMATO #include "general.h"	/* must always come first */
12e24c0d0eSMasatake YAMATO #include "debug.h"
13bddf5c8aSMasatake YAMATO #include "entry.h"
14bddf5c8aSMasatake YAMATO #include "kind.h"
1587214e15SMasatake YAMATO #include "yaml.h"
16bddf5c8aSMasatake YAMATO #include "parse.h"
170051d650SMasatake YAMATO #include "subparser.h"
18bddf5c8aSMasatake YAMATO 
19bddf5c8aSMasatake YAMATO #include <stdio.h>
20bddf5c8aSMasatake YAMATO 
21bddf5c8aSMasatake YAMATO typedef enum {
22bddf5c8aSMasatake YAMATO 	K_PLAY
23bddf5c8aSMasatake YAMATO } ansiblePlaybookKind;
24bddf5c8aSMasatake YAMATO 
25e112e8abSMasatake YAMATO static kindDefinition AnsiblePlaybookKinds [] = {
26bddf5c8aSMasatake YAMATO 	{ true,  'p', "play", "plays" },
27bddf5c8aSMasatake YAMATO };
28bddf5c8aSMasatake YAMATO 
29bddf5c8aSMasatake YAMATO struct yamlBlockTypeStack {
30bddf5c8aSMasatake YAMATO 	yaml_token_type_t type;
31e24c0d0eSMasatake YAMATO 	int associatedCorkIndex;
32bddf5c8aSMasatake YAMATO 	struct yamlBlockTypeStack *next;
33bddf5c8aSMasatake YAMATO };
34bddf5c8aSMasatake YAMATO 
35bddf5c8aSMasatake YAMATO /* - name: "THE NAME" */
36bddf5c8aSMasatake YAMATO enum ansiblePlaybookPlayDetectingState {
37bddf5c8aSMasatake YAMATO 	DSTAT_PLAY_NAME_INITIAL,
38bddf5c8aSMasatake YAMATO 	DSTAT_PLAY_NAME_KEY,
39bddf5c8aSMasatake YAMATO 	DSTAT_PLAY_NAME_KEY_SCALAR,
40bddf5c8aSMasatake YAMATO 	DSTAT_PLAY_NAME_VALUE,
41bddf5c8aSMasatake YAMATO };
42bddf5c8aSMasatake YAMATO 
43bddf5c8aSMasatake YAMATO 
440051d650SMasatake YAMATO struct sAnsiblePlaybookSubparser {
450051d650SMasatake YAMATO 	yamlSubparser yaml;
46bddf5c8aSMasatake YAMATO 	struct yamlBlockTypeStack *type_stack;
47bddf5c8aSMasatake YAMATO 	enum ansiblePlaybookPlayDetectingState play_detection_state;
48bddf5c8aSMasatake YAMATO };
49bddf5c8aSMasatake YAMATO 
pushBlockType(struct sAnsiblePlaybookSubparser * ansible,yaml_token_type_t t)500051d650SMasatake YAMATO static void pushBlockType (struct sAnsiblePlaybookSubparser *ansible, yaml_token_type_t t)
51bddf5c8aSMasatake YAMATO {
52bddf5c8aSMasatake YAMATO 	struct yamlBlockTypeStack *s;
53bddf5c8aSMasatake YAMATO 
54bddf5c8aSMasatake YAMATO 	s = xMalloc (1, struct yamlBlockTypeStack);
55bddf5c8aSMasatake YAMATO 
560051d650SMasatake YAMATO 	s->next = ansible->type_stack;
570051d650SMasatake YAMATO 	ansible->type_stack = s;
58bddf5c8aSMasatake YAMATO 
59bddf5c8aSMasatake YAMATO 	s->type = t;
60e24c0d0eSMasatake YAMATO 	s->associatedCorkIndex = CORK_NIL;
61bddf5c8aSMasatake YAMATO }
62bddf5c8aSMasatake YAMATO 
popBlockType(struct sAnsiblePlaybookSubparser * ansible,yaml_token_t * token)630051d650SMasatake YAMATO static void popBlockType (struct sAnsiblePlaybookSubparser *ansible,
64e24c0d0eSMasatake YAMATO 						  yaml_token_t *token)
65bddf5c8aSMasatake YAMATO {
66bddf5c8aSMasatake YAMATO 	struct yamlBlockTypeStack *s;
67bddf5c8aSMasatake YAMATO 
680051d650SMasatake YAMATO 	s = ansible->type_stack;
690051d650SMasatake YAMATO 	ansible->type_stack = s->next;
70bddf5c8aSMasatake YAMATO 
71bddf5c8aSMasatake YAMATO 	s->next = NULL;
723671ad72SMasatake YAMATO 	tagEntryInfo *tag = getEntryInCorkQueue (s->associatedCorkIndex);
73*9b034e2aSMasatake YAMATO 	if (tag && token)
74e24c0d0eSMasatake YAMATO 		attachYamlPosition (tag, token, true);
75e24c0d0eSMasatake YAMATO 
76bddf5c8aSMasatake YAMATO 	eFree (s);
77bddf5c8aSMasatake YAMATO }
78bddf5c8aSMasatake YAMATO 
popAllBlockType(struct sAnsiblePlaybookSubparser * ansible,yaml_token_t * token)790051d650SMasatake YAMATO static void popAllBlockType (struct sAnsiblePlaybookSubparser *ansible,
80e24c0d0eSMasatake YAMATO 							 yaml_token_t *token)
81bddf5c8aSMasatake YAMATO {
820051d650SMasatake YAMATO 	while (ansible->type_stack)
830051d650SMasatake YAMATO 		popBlockType (ansible, token);
84bddf5c8aSMasatake YAMATO }
85bddf5c8aSMasatake YAMATO 
stateStackMatch(struct yamlBlockTypeStack * stack,yaml_token_type_t * expectation,unsigned int length,bool partial)86bddf5c8aSMasatake YAMATO static bool stateStackMatch (struct yamlBlockTypeStack *stack,
87bddf5c8aSMasatake YAMATO 							 yaml_token_type_t *expectation,
88bddf5c8aSMasatake YAMATO 							 unsigned int length,
89bddf5c8aSMasatake YAMATO 							 bool partial)
90bddf5c8aSMasatake YAMATO {
91bddf5c8aSMasatake YAMATO 	if (length == 0)
92bddf5c8aSMasatake YAMATO 	{
93bddf5c8aSMasatake YAMATO 		if (stack == NULL)
94bddf5c8aSMasatake YAMATO 			return true;
95bddf5c8aSMasatake YAMATO 		else if (partial)
96bddf5c8aSMasatake YAMATO 			return true;
97bddf5c8aSMasatake YAMATO 		else
98bddf5c8aSMasatake YAMATO 			return false;
99bddf5c8aSMasatake YAMATO 	}
100bddf5c8aSMasatake YAMATO 
101bddf5c8aSMasatake YAMATO 	if (stack == NULL)
102bddf5c8aSMasatake YAMATO 		return false;
103bddf5c8aSMasatake YAMATO 
104bddf5c8aSMasatake YAMATO 	if (stack->type == expectation[0])
105bddf5c8aSMasatake YAMATO 		return stateStackMatch (stack->next, expectation + 1, length - 1, partial);
106bddf5c8aSMasatake YAMATO 	else
107bddf5c8aSMasatake YAMATO 		return false;
108bddf5c8aSMasatake YAMATO }
109bddf5c8aSMasatake YAMATO 
scalarNeq(yaml_token_t * token,unsigned int len,const char * val)110bddf5c8aSMasatake YAMATO static bool scalarNeq (yaml_token_t *token, unsigned int len, const char* val)
111bddf5c8aSMasatake YAMATO {
112bddf5c8aSMasatake YAMATO 	if ((token->data.scalar.length == len)
113bddf5c8aSMasatake YAMATO 		&& (strncmp (val, (char *)token->data.scalar.value, len) == 0))
114bddf5c8aSMasatake YAMATO 		return true;
115bddf5c8aSMasatake YAMATO 	else
116bddf5c8aSMasatake YAMATO 		return false;
117bddf5c8aSMasatake YAMATO }
118bddf5c8aSMasatake YAMATO 
ansiblePlaybookPlayStateMachine(struct sAnsiblePlaybookSubparser * ansible,yaml_token_t * token)1190051d650SMasatake YAMATO static void	ansiblePlaybookPlayStateMachine (struct sAnsiblePlaybookSubparser *ansible,
120bddf5c8aSMasatake YAMATO 											 yaml_token_t *token)
121bddf5c8aSMasatake YAMATO {
122bddf5c8aSMasatake YAMATO 	yaml_token_type_t play_expect[] = {
123bddf5c8aSMasatake YAMATO 		YAML_BLOCK_MAPPING_START_TOKEN,
124bddf5c8aSMasatake YAMATO 		YAML_BLOCK_SEQUENCE_START_TOKEN,
125bddf5c8aSMasatake YAMATO 	};
126bddf5c8aSMasatake YAMATO 
127bddf5c8aSMasatake YAMATO 	switch (token->type)
128bddf5c8aSMasatake YAMATO 	{
129bddf5c8aSMasatake YAMATO 	case YAML_KEY_TOKEN:
1300051d650SMasatake YAMATO 		if (stateStackMatch (ansible->type_stack,
131bddf5c8aSMasatake YAMATO 							 play_expect, ARRAY_SIZE (play_expect),
132bddf5c8aSMasatake YAMATO 							 false))
1330051d650SMasatake YAMATO 			ansible->play_detection_state = DSTAT_PLAY_NAME_KEY;
134bddf5c8aSMasatake YAMATO 		else
1350051d650SMasatake YAMATO 			ansible->play_detection_state = DSTAT_PLAY_NAME_INITIAL;
136bddf5c8aSMasatake YAMATO 		break;
137bddf5c8aSMasatake YAMATO 	case YAML_SCALAR_TOKEN:
1380051d650SMasatake YAMATO 		if ((ansible->play_detection_state == DSTAT_PLAY_NAME_KEY)
139bddf5c8aSMasatake YAMATO 			&& scalarNeq (token, 4, "name"))
1400051d650SMasatake YAMATO 			ansible->play_detection_state = DSTAT_PLAY_NAME_KEY_SCALAR;
1410051d650SMasatake YAMATO 		else if (ansible->play_detection_state == DSTAT_PLAY_NAME_VALUE)
142bddf5c8aSMasatake YAMATO 		{
143bddf5c8aSMasatake YAMATO 			tagEntryInfo tag;
144bddf5c8aSMasatake YAMATO 			initTagEntry (&tag, (char *)token->data.scalar.value,
14516a2541cSMasatake YAMATO 						  K_PLAY);
146f3fffd78SMasatake YAMATO 			attachYamlPosition (&tag, token, false);
147e24c0d0eSMasatake YAMATO 
1480051d650SMasatake YAMATO 			Assert (ansible->type_stack->associatedCorkIndex == CORK_NIL);
1490051d650SMasatake YAMATO 			ansible->type_stack->associatedCorkIndex = makeTagEntry (&tag);
1500051d650SMasatake YAMATO 			ansible->play_detection_state = DSTAT_PLAY_NAME_INITIAL;
151bddf5c8aSMasatake YAMATO 		}
152bddf5c8aSMasatake YAMATO 		else
1530051d650SMasatake YAMATO 			ansible->play_detection_state = DSTAT_PLAY_NAME_INITIAL;
154bddf5c8aSMasatake YAMATO 		break;
155bddf5c8aSMasatake YAMATO 	case YAML_VALUE_TOKEN:
1560051d650SMasatake YAMATO 		if (ansible->play_detection_state == DSTAT_PLAY_NAME_KEY_SCALAR)
1570051d650SMasatake YAMATO 			ansible->play_detection_state = DSTAT_PLAY_NAME_VALUE;
158bddf5c8aSMasatake YAMATO 		else
1590051d650SMasatake YAMATO 			ansible->play_detection_state = DSTAT_PLAY_NAME_INITIAL;
160bddf5c8aSMasatake YAMATO 		break;
161bddf5c8aSMasatake YAMATO 	default:
1620051d650SMasatake YAMATO 		ansible->play_detection_state = DSTAT_PLAY_NAME_INITIAL;
163bddf5c8aSMasatake YAMATO 		break;
164bddf5c8aSMasatake YAMATO 	}
165bddf5c8aSMasatake YAMATO }
166bddf5c8aSMasatake YAMATO 
newTokenCallback(yamlSubparser * s,yaml_token_t * token)1670051d650SMasatake YAMATO static void newTokenCallback (yamlSubparser *s, yaml_token_t *token)
168bddf5c8aSMasatake YAMATO {
169bddf5c8aSMasatake YAMATO 	if (token->type == YAML_BLOCK_SEQUENCE_START_TOKEN
170bddf5c8aSMasatake YAMATO 		|| token->type == YAML_BLOCK_MAPPING_START_TOKEN)
1710051d650SMasatake YAMATO 		pushBlockType ((struct sAnsiblePlaybookSubparser *)s, token->type);
172bddf5c8aSMasatake YAMATO 
1730051d650SMasatake YAMATO 	ansiblePlaybookPlayStateMachine ((struct sAnsiblePlaybookSubparser *)s, token);
174bddf5c8aSMasatake YAMATO 
175bddf5c8aSMasatake YAMATO 	if (token->type == YAML_BLOCK_END_TOKEN)
1760051d650SMasatake YAMATO 		popBlockType ((struct sAnsiblePlaybookSubparser *)s, token);
177e24c0d0eSMasatake YAMATO 	else if (token->type == YAML_STREAM_END_TOKEN)
1780051d650SMasatake YAMATO 		popAllBlockType ((struct sAnsiblePlaybookSubparser *)s, token);
179bddf5c8aSMasatake YAMATO }
180bddf5c8aSMasatake YAMATO 
inputStart(subparser * s)1810051d650SMasatake YAMATO static void inputStart(subparser *s)
182bddf5c8aSMasatake YAMATO {
1830051d650SMasatake YAMATO 	((struct sAnsiblePlaybookSubparser*)s)->play_detection_state = DSTAT_PLAY_NAME_INITIAL;
1840051d650SMasatake YAMATO 	((struct sAnsiblePlaybookSubparser*)s)->type_stack = NULL;
185bddf5c8aSMasatake YAMATO }
186bddf5c8aSMasatake YAMATO 
inputEnd(subparser * s)1870051d650SMasatake YAMATO static void inputEnd(subparser *s)
18889070b4aSMasatake YAMATO {
189*9b034e2aSMasatake YAMATO 	popAllBlockType ((struct sAnsiblePlaybookSubparser *)s, NULL);
1900051d650SMasatake YAMATO 	Assert (((struct sAnsiblePlaybookSubparser*)s)->type_stack == NULL);
19189070b4aSMasatake YAMATO }
19289070b4aSMasatake YAMATO 
193bddf5c8aSMasatake YAMATO static void
findAnsiblePlaybookTags(void)194bddf5c8aSMasatake YAMATO findAnsiblePlaybookTags (void)
195bddf5c8aSMasatake YAMATO {
1960051d650SMasatake YAMATO 	scheduleRunningBaseparser (0);
197bddf5c8aSMasatake YAMATO }
198bddf5c8aSMasatake YAMATO 
AnsiblePlaybookParser(void)199bddf5c8aSMasatake YAMATO extern parserDefinition* AnsiblePlaybookParser (void)
200bddf5c8aSMasatake YAMATO {
2010051d650SMasatake YAMATO 	static struct sAnsiblePlaybookSubparser ansiblePlaybookSubparser = {
2020051d650SMasatake YAMATO 		.yaml = {
2030051d650SMasatake YAMATO 			.subparser = {
2040051d650SMasatake YAMATO 				.direction = SUBPARSER_BI_DIRECTION,
2050051d650SMasatake YAMATO 				.inputStart = inputStart,
2060051d650SMasatake YAMATO 				.inputEnd = inputEnd,
2070051d650SMasatake YAMATO 			},
2080051d650SMasatake YAMATO 			.newTokenNotfify = newTokenCallback
2090051d650SMasatake YAMATO 		},
2100051d650SMasatake YAMATO 	};
2110051d650SMasatake YAMATO 	static parserDependency dependencies [] = {
2120051d650SMasatake YAMATO 		{ DEPTYPE_SUBPARSER, "Yaml", &ansiblePlaybookSubparser },
2130051d650SMasatake YAMATO 	};
2140051d650SMasatake YAMATO 
215bddf5c8aSMasatake YAMATO 	parserDefinition* const def = parserNew ("AnsiblePlaybook");
216bddf5c8aSMasatake YAMATO 
217bddf5c8aSMasatake YAMATO 
218bddf5c8aSMasatake YAMATO 	def->dependencies = dependencies;
219bddf5c8aSMasatake YAMATO 	def->dependencyCount = ARRAY_SIZE (dependencies);
220bddf5c8aSMasatake YAMATO 
22109ae690fSMasatake YAMATO 	def->kindTable         = AnsiblePlaybookKinds;
222bddf5c8aSMasatake YAMATO 	def->kindCount     = ARRAY_SIZE (AnsiblePlaybookKinds);
223bddf5c8aSMasatake YAMATO 	def->parser        = findAnsiblePlaybookTags;
2246b1a862eSMasatake YAMATO 	def->useCork       = CORK_QUEUE;
225bddf5c8aSMasatake YAMATO 	return def;
226bddf5c8aSMasatake YAMATO }
227bddf5c8aSMasatake YAMATO 
228bddf5c8aSMasatake YAMATO /* vi:set tabstop=4 shiftwidth=4: */
229