package com.javadude.annotation.processors.template;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Stack;
///*
//* Code generation notes
//* variable references take the form
//* $<modifiers_>name<_suffix>$
//* where modifiers can be any of:
//* parent
//* lower
//* upper
//* stripPackage
//* and suffix can be any text that is ignored (suffix allows creation
//* of unique names for the java compilation below to work)
//*
//* All lines ending in //#DUMMY are stripped
//*
//* All multi-line comments have the delimiters removed and then the
//* text is processed as normal. This allows expressions in places
//* that aren't possible in java (like specifying the method access
//* modifiers)
//*
//* FOREACH blocks push the elements on the stack one at a time
//* making their child attributes available in scope.
//*
//* //? conditions have special variables FIRST and LAST to
//* indicate looping
//*
//* conditions can use booleans for true/false and pointers
//* (null = false, non-null = true)
//*/
public class TemplateReader {
private ConditionParser conditionParser = new ConditionParser();
public Processor readTemplate(Reader reader) {
BufferedReader bufferedReader = null;
try {
try {
Template template = new Template(-1);
bufferedReader = new BufferedReader(reader);
String lineText;
int lineNumber = 0;
Stack<CompositeProcessor> currentComposite = new Stack<CompositeProcessor>();
currentComposite.push(template);
while ((lineText = bufferedReader.readLine()) != null) {
lineNumber++;
// check for directives
int i = lineText.indexOf("//#");
if (i != -1) {
// it's a directive (DUMMY, FOREACH, IF, END)
if (lineText.regionMatches(i+3, "DUMMY", 0, 5))
continue; // skip the line
// check if anything before "//" is non-whitespace
for (int n = 0; n < i; n++)
if (!Character.isWhitespace(lineText.charAt(n)))
throw new ExpressionException("Non-whitespace before //#FOREACH, //#IF or //#END is not allowed");
if (lineText.regionMatches(i+3, "END", 0, 3)) {
// can have comment text after the end
currentComposite.pop();
if (currentComposite.isEmpty()) {
throw new ExpressionException("Too many //#END directives in template detected on line " + lineText);
}
} else if (lineText.regionMatches(i+3, "FOREACH", 0, 7)) {
String expression = lineText.substring(i+10).trim();
ForEach forEach = new ForEach(lineNumber, expression);
currentComposite.peek().add(forEach);
currentComposite.push(forEach);
} else if (lineText.regionMatches(i+3, "IF", 0, 2)) {
String expression = lineText.substring(i+5).trim();
If if1 = new If(lineNumber, conditionParser.parse(expression, lineNumber));
currentComposite.peek().add(if1);
currentComposite.push(if1);
}
continue; // done with directives
}
// check for conditional inclusion of the line
Condition condition = null;
i = lineText.indexOf("//?");
if (i != -1) {
condition = conditionParser.parse(lineText.substring(i + 3), lineNumber);
lineText = lineText.substring(0, i);
}
Line line = new Line(lineNumber, condition);
currentComposite.peek().add(line);
// chop of rest of line into text and variable refs
boolean inVariable = false;
int start = 0;
// System.out.println("line:" + lineText);
lineText = lineText.replace("/**", "[##").replace("**/", "##]");
lineText = lineText.replace("/*", "").replace("*/", "");
lineText = lineText.replace("[##", "/**").replace("##]", "**/");
// trim trailing spaces
i = lineText.length() - 1;
while (i > -1 && Character.isWhitespace(lineText.charAt(i)))
i--;
lineText = lineText.substring(0, i + 1);
i = 0;
while (true) {
if (i >= lineText.length())
break;
char c = lineText.charAt(i++);
if (!inVariable) {
if (c == '$') {
inVariable = true;
line.add(new Text(lineText.substring(start, i-1)));
// System.out.println(" text:" + lineText.substring(start, i-1) + ':');
start = i;
}
} else {
if (c == '$') {
inVariable = false;
line.add(new VariableReference(lineText.substring(start, i-1)));
// System.out.println(" variable ref:" + lineText.substring(start, i-1) + ':');
start = i;
}
}
}
if (inVariable)
throw new ExpressionException("Mismatched '$' on line " + lineNumber + " position " + (start-1));
if (start < lineText.length()) {
line.add(new Text(lineText.substring(start)));
// System.out.println(" text:" + lineText.substring(start) + ':');
}
}
if (currentComposite.size() != 1) {
throw new ExpressionException("Not enough //#END directives in template detected at end of file");
}
return template;
} finally {
if (bufferedReader != null) {
bufferedReader.close();
reader = null;
}
if (reader != null) {
reader.close();
}
}
} catch (IOException e) {
throw new ExpressionException("IO Error reading template", e);
}
}
public static void main(String[] args) throws Exception {
FileReader fileReader = new FileReader("/eclipse34/javadude-workspace/com.javadude.annotation/src/$packageName$/$className$Gen.java");
new TemplateReader().readTemplate(fileReader);
}
}