summaryrefslogtreecommitdiff
path: root/src/main/java/bjc/rgens/parser/templates/GrammarTemplate.java
blob: ef0bf3a7b97d96a477e5ae51467005d408918592 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package bjc.rgens.parser.templates;

import bjc.rgens.parser.ConfigSet;
import bjc.rgens.parser.GenerationState;
import bjc.rgens.parser.LoadOptions;

import bjc.utils.data.ITree;
import bjc.utils.data.Tree;

import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import bjc.rgens.parser.ConfigSet;
import bjc.rgens.parser.GenerationState;

/**
 * Represents a grammar template.
 *
 * @author Ben Culkin
 */
public class GrammarTemplate {
	/**
	 * The config set the template belongs to.
	 */
	public ConfigSet belongsTo;

	/**
	 * The name of the template.
	 */
	public String name;

	/**
	 * The elements in the template.
	 */
	public final List<TemplateElement> elements;

	/**
	 * Whether or not to do spacing of elements.
	 */
	public boolean doSpacing = true;

	/**
	 * Create a new grammar template.
	 *
	 * @param elements
	 * 		The elements that belong to the template.
	 */
	public GrammarTemplate(List<TemplateElement> elements) {
		this.elements = elements;
	}

	/**
	 * Generate the template.
	 *
	 * @param state
	 * 		The state for generating a template.
	 */
	public void generate(GenerationState state) {
		for(TemplateElement element : elements) {
			element.generate(state);

			if(doSpacing && element.spacing)
				state.appendContents("\n");
		}
	}

	/**
	 * Read a template from an input source.
	 *
	 * @param rdr
	 * 		The reader to get input from.
	 *
	 * @param errs
	 * 		The errors/information to generate during loading.
	 *
	 * @return The generated template.
	 */
	public static GrammarTemplate readTemplate(Reader rdr, ITree<String> errs) {
		List<TemplateElement> elements = new ArrayList<>();
		GrammarTemplate template = new GrammarTemplate(elements);

		Scanner scn = new Scanner(rdr);
		scn.useDelimiter("\\R");

		int lno = 0;
		while(scn.hasNextLine()) {
			String ln = scn.nextLine();
			lno += 1;

			ITree<String> kid = new Tree<>(String.format("INFO: Line %d", lno));
			switch(ln.charAt(0)) {
			case '#':
				// Ignore comments
				break;
			case '/':
				handlePragma(elements, template, ln.substring(1), kid);
				break;
			default:
				handleLine(elements, template, ln, kid);
			}

			if (kid.size() > 0) {
				errs.addChild(kid);
			}
		}

		scn.close();
		
		return template;
	}

	private static void handleLine(List<TemplateElement> elements, GrammarTemplate template, String ln, ITree<String> errs) {
		if(ln.matches("^.*?\\$@.+?@\\$.*$")) {
			/*
			 * Handle live templates
			 */
			elements.add(new LiveTemplateElement(ln, errs));
		} else {
			elements.add(new LiteralTemplateElement(ln, errs));
		}
	}

	private static void handlePragma(List<TemplateElement> elements, GrammarTemplate template, String ln, ITree<String> errs) {
		/*
		 * @TODO 2/8/2019 Ben Culkin :TemplatePragmas
		 * Implement template pragmas.
		 *
		 * Implement template pragmas. Mainly, this means that the 'choose'
		 * based ones need to be implemented based off of the provided sample
		 * template.
		 */
		errs.addChild("ERROR: Template pragmas are not yet implemented");
	}
}