Compare commits

..

No commits in common. "master" and "SCG-1.0.1" have entirely different histories.

31 changed files with 167 additions and 928 deletions

1
.gitignore vendored
View File

@ -1,6 +1,5 @@
# ---> Gradle
.gradle
gradle.properties
**/build/
!src/**/build/

View File

@ -1,13 +1,2 @@
arguments=
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=
jvm.arguments=
offline.mode=false
override.workspace.settings=false
show.console.view=false
show.executions.view=false

View File

@ -1,2 +0,0 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -6,18 +6,6 @@ It has a cache that keeps track of the input (if it was changed), and only cares
It is as bare bones as it can get but that also makes it flexible.
# How to install
Using Gradle:
```gradle
repositories {
maven {
url = "https://maven.speiger.com/repository/main"
}
}
dependencies {
compile 'de.speiger:Simple-Code-Generator:1.1.4'
}
```
# How to create a Template Processor

View File

@ -1,55 +1,24 @@
apply plugin: 'java-library'
repositories {
jcenter()
}
archivesBaseName = 'Simple Code Generator'
version = '1.3.0'
apply plugin: 'maven'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
dependencies {
}
task srcJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
artifacts {
archives srcJar
}
uploadArchives {
repositories.mavenDeployer {
repository(url: 'https://maven.speiger.com/repository/main') {
authentication(userName: project.properties.mavenUser, password: project.properties.mavenPassword)
}
snapshotRepository(url: 'https://maven.speiger.com/repository/main') {
authentication(userName: project.properties.mavenUser, password: project.properties.mavenPassword)
}
pom {
version = project.version
artifactId = project.archivesBaseName.replace(" ", "-")
groupId = 'de.speiger'
project {
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'speiger'
name = 'Speiger'
}
}
}
}
}
apply plugin: 'java-library'
repositories {
jcenter()
}
archivesBaseName = 'Simple Code Generator'
version = '1.0.1'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
dependencies {
}
task srcJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
artifacts {
archives srcJar
}

View File

@ -1 +0,0 @@
test=ddb9367ebd61888ab31a658dd6f6df86

View File

@ -1,53 +0,0 @@
Hello this is my test
#ignore
TESTING should not be overriden
#endignore
TESTING should be overriden
#if TEST0
#ignore
TESTING should not be overriden too
#endignore
TESTING should be overriden too
#endif
#if TEST1
#ignore
TESTING should not be overriden
#endignore
TESTING should not be overriden
#endif
#iterate
#argument NUMBER 1 2 3 4 5 6 7 8 9
Lets test number NUMBER
#enditerate
#if TEST0
Lets test a true condition.
#iterate
#argument NUMBER 1 2 3 4 5 6 7 8 9
Lets test number NUMBER
#enditerate
#endif
#if TEST1
Lets test a false condition.
#iterate
#argument NUMBER 1 2 3 4 5 6 7 8 9
Lets test number NUMBER
#enditerate
#endif
Lets test stacked iterators
#iterate
#argument NUMBER1 1 2 3
#iterate
#argument NUMBER2 4 5 6
Lets test numbers NUMBER1 NUMBER2
#enditerate
#enditerate

View File

@ -1,41 +0,0 @@
Hello this is my test
TESTING should not be overriden
Test2 should be overriden
TESTING should not be overriden too
Test2 should be overriden too
Lets test number 1
Lets test number 2
Lets test number 3
Lets test number 4
Lets test number 5
Lets test number 6
Lets test number 7
Lets test number 8
Lets test number 9
Lets test a true condition.
Lets test number 1
Lets test number 2
Lets test number 3
Lets test number 4
Lets test number 5
Lets test number 6
Lets test number 7
Lets test number 8
Lets test number 9
Lets test stacked iterators
Lets test numbers 1 4
Lets test numbers 1 5
Lets test numbers 1 6
Lets test numbers 2 4
Lets test numbers 2 5
Lets test numbers 2 6
Lets test numbers 3 4
Lets test numbers 3 5
Lets test numbers 3 6

View File

@ -2,12 +2,11 @@ package speiger.src.builder.base;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
import java.util.regex.Pattern;
import speiger.src.builder.conditions.ICondition;
import speiger.src.builder.misc.IdGenerator;
import speiger.src.builder.processor.CompiledArguments;
public class ConditionedSegment
{
@ -27,28 +26,23 @@ public class ConditionedSegment
segments.add(segment);
}
public int build(CompiledArguments process, StringBuilder builder, int baseIndex)
public int build(Set<String> parsePool, StringBuilder builder, int baseIndex)
{
baseIndex += index;
int length = builder.length();
for(int i = 0,m=segments.size();i<m;i++)
{
if(segments.get(i).build(process, builder, baseIndex)) break;
if(segments.get(i).build(parsePool, builder, baseIndex)) break;
}
return builder.length() - length;
}
public static int parse(String fileName, String currentLine, List<String> lines, int currentIndex, int startIndex, IdGenerator ignoreCounter, List<ConditionedSegment> segments, List<PostSegment> postSegments) throws IllegalStateException
public static int parse(String fileName, String currentLine, List<String> lines, int currentIndex, int startIndex, List<ConditionedSegment> segments) throws IllegalStateException
{
String ignoreSegmentId = ignoreCounter.getId();
ConditionedSegment segment = new ConditionedSegment(startIndex);
ICondition condition = currentLine == null ? null : ICondition.parse(currentLine);
ICondition condition = ICondition.parse(currentLine);
List<ConditionedSegment> childSegments = new ArrayList<>();
StringJoiner segmentText = new StringJoiner("\n", (currentIndex <= 0 || includeStartNewLine(lines.get(currentIndex-1).trim())) ? "\n" : "", "");
if(currentLine == null) {
lines.set(currentIndex, ignoreSegmentId);
}
StringJoiner segmentText = new StringJoiner("\n", "\n", "");
for(int i = currentIndex+1;i<lines.size();i++)
{
String s = lines.get(i);
@ -57,7 +51,6 @@ public class ConditionedSegment
{
if(trimmed.startsWith("#else if"))
{
if(currentLine == null) throw new IllegalStateException("#else if isn't working while in a ignore segment");
segment.addSegment(new Segment(segmentText.toString(), condition, childSegments));
condition = ICondition.parse(trimmed.substring(8).trim());
childSegments = new ArrayList<>();
@ -65,7 +58,6 @@ public class ConditionedSegment
}
else if(trimmed.startsWith("#else"))
{
if(currentLine == null) throw new IllegalStateException("#else isn't working while in a ignore segment");
segment.addSegment(new Segment(segmentText.toString(), condition, childSegments));
condition = ICondition.ALWAYS_TRUE;
childSegments = new ArrayList<>();
@ -73,33 +65,13 @@ public class ConditionedSegment
}
else if(trimmed.startsWith("#endif"))
{
if(currentLine == null) throw new IllegalStateException("#endif isn't working while in a ignore segment");
segment.addSegment(new Segment(segmentText.toString(), condition, childSegments));
segments.add(segment);
return i - currentIndex;
}
else if(trimmed.startsWith("#endignore"))
{
postSegments.add(new PostSegment(segmentText.toString(), ignoreSegmentId));
segments.add(segment);
return i - currentIndex;
}
else if(trimmed.startsWith("#if"))
{
if(currentLine == null) throw new IllegalStateException("#if isn't working while in a ignore segment");
i += parse(fileName, trimmed.substring(3).trim(), lines, i, segmentText.length(), ignoreCounter, childSegments, postSegments);
}
else if(trimmed.startsWith("#ignore"))
{
if(currentLine == null) throw new IllegalStateException("#ignore lines can't be applied Recursively");
ignoreCounter.appendId();
int prev = i;
i += parse(fileName, null, lines, i, segmentText.length(), ignoreCounter, childSegments, postSegments);
segmentText.add(lines.get(prev));
}
else if(trimmed.startsWith("#iterate")) {
SegmentIterator.iterateSegment(fileName, trimmed, lines, i, segmentText.length());
i--;
i += parse(fileName, trimmed.substring(3).trim(), lines, i, segmentText.length(), childSegments);
}
continue;
}
@ -108,8 +80,4 @@ public class ConditionedSegment
throw new IllegalStateException("Unclosed #If found in ["+fileName+"] at line ["+startIndex+"]");
}
static boolean includeStartNewLine(String s)
{
return !s.startsWith("#") || s.equalsIgnoreCase("#endif") || s.equalsIgnoreCase("#endignore");
}
}

View File

@ -1,18 +0,0 @@
package speiger.src.builder.base;
public class PostSegment
{
String text;
String identifier;
public PostSegment(String text, String identifier)
{
this.text = text;
this.identifier = identifier;
}
public String build(String input)
{
return input.replaceAll("\n"+identifier, text);
}
}

View File

@ -2,9 +2,9 @@ package speiger.src.builder.base;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import speiger.src.builder.conditions.ICondition;
import speiger.src.builder.processor.CompiledArguments;
public class Segment
{
@ -19,14 +19,14 @@ public class Segment
this.segments = segments;
}
public boolean build(CompiledArguments process, StringBuilder builder, int index)
public boolean build(Set<String> parsePool, StringBuilder builder, int index)
{
if(condition.isValid(process))
if(condition.isValid(parsePool))
{
builder.insert(index, text);
for(int i = 0,offset=0,m=segments.size();i<m;i++)
{
offset += segments.get(i).build(process, builder, index+offset);
offset += segments.get(i).build(parsePool, builder, index+offset);
}
return true;
}

View File

@ -1,61 +0,0 @@
package speiger.src.builder.base;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;
public class SegmentIterator {
public static void iterateSegment(String fileName, String currentLine, List<String> lines, int currentIndex, int startIndex) {
List<String[]> arguments = new ArrayList<>();
StringJoiner toIterate = new StringJoiner("\n");
int skip = 0;
int end = 1;
for(int i = currentIndex+1;i<lines.size();i++, end++)
{
String s = lines.get(i);
String trimmed = s.trim();
if(trimmed.startsWith("#"))
{
if(trimmed.startsWith("#enditerate"))
{
skip--;
if(skip < 0)
{
end++;
break;
}
}
if(trimmed.startsWith("#iterate")) skip++;
if(skip > 0)
{
toIterate.add(s);
continue;
}
if(trimmed.startsWith("#argument"))
{
arguments.add(trimmed.substring(9).trim().split(" "));
continue;
}
}
toIterate.add(s);
}
int size = arguments.get(0).length;
for(int i = 1,m=arguments.size();i<m;i++) {
if(arguments.get(i).length != size) throw new RuntimeException("Iteration arguments in file ["+fileName+"] are not equal size. Arugments="+arguments.stream().flatMap(Arrays::stream).collect(Collectors.toList()));
}
for(int i = 0;i<end;i++) {
lines.remove(currentIndex);
}
String toInsert = toIterate.toString();
for(int i = size-1;i>=1;i--) {
String temp = toInsert;
for(int j = 0;j<arguments.size();j++) {
String[] argument = arguments.get(j);
temp = temp.replace(argument[0], argument[i]);
}
lines.addAll(currentIndex, Arrays.asList(temp.split("\n", -1)));
}
}
}

View File

@ -10,22 +10,18 @@ import java.util.StringJoiner;
import speiger.src.builder.mappers.IMapper;
import speiger.src.builder.misc.FileUtils;
import speiger.src.builder.misc.IdGenerator;
import speiger.src.builder.processor.CompiledArguments;
public class Template
{
String fileName;
String textFile;
List<ConditionedSegment> segments;
List<PostSegment> postSegments;
public Template(String fileName, String textFile, List<ConditionedSegment> segments, List<PostSegment> postSegments)
public Template(String fileName, String textFile, List<ConditionedSegment> segments)
{
this.fileName = fileName;
this.textFile = textFile;
this.segments = segments;
this.postSegments = postSegments;
}
public String getFileName()
@ -33,14 +29,13 @@ public class Template
return fileName;
}
public String build(CompiledArguments process, boolean printNoWork, Set<IMapper> done)
public String build(Set<String> parsePool, List<IMapper> mappers, boolean printNoWork, Set<IMapper> done)
{
StringBuilder builder = new StringBuilder(textFile);
for(int i = 0,offset=0,m=segments.size();i<m;i++)
{
offset += segments.get(i).build(process, builder, offset);
offset += segments.get(i).build(parsePool, builder, offset);
}
List<IMapper> mappers = process.getMapper();
String result = builder.toString();
for(int i = 0,m=mappers.size();i<m;i++)
{
@ -58,19 +53,13 @@ public class Template
result = mappers.get(i).apply(result);
}
}
for(int i = 0,m=postSegments.size();i<m;i++)
{
result = postSegments.get(i).build(result);
}
return result;
}
public static Template parse(Path file) throws IOException
{
String fileName = FileUtils.getFileName(file.getFileName());
IdGenerator segmentIds = new IdGenerator();
List<ConditionedSegment> segments = new ArrayList<>();
List<PostSegment> postSegments = new ArrayList<>();
List<ConditionedSegment> segments = new ArrayList<ConditionedSegment>();
StringJoiner joiner = new StringJoiner("\n");
List<String> lines = Files.readAllLines(file);
for(int i = 0;i<lines.size();i++)
@ -81,20 +70,7 @@ public class Template
{
if(trimmed.startsWith("#if"))
{
i += ConditionedSegment.parse(fileName, s.trim().substring(3).trim(), lines, i, joiner.length(), segmentIds, segments, postSegments);
continue;
}
else if(trimmed.startsWith("#ignore"))
{
segmentIds.appendId();
int prev = i;
i += ConditionedSegment.parse(fileName, null, lines, i, joiner.length(), segmentIds, segments, postSegments);
joiner.add(lines.get(prev));
continue;
}
else if(trimmed.startsWith("#iterate")) {
SegmentIterator.iterateSegment(fileName, trimmed, lines, i, joiner.length());
i--;
i += ConditionedSegment.parse(fileName, s.trim().substring(3).trim(), lines, i, joiner.length(), segments);
continue;
}
else if(trimmed.startsWith("#symlink"))
@ -104,6 +80,6 @@ public class Template
}
joiner.add(s);
}
return new Template(fileName, joiner.toString(), segments, postSegments);
return new Template(fileName, joiner.toString(), segments);
}
}

View File

@ -2,32 +2,28 @@ package speiger.src.builder.conditions;
import java.util.ArrayList;
import java.util.List;
import speiger.src.builder.processor.CompiledArguments;
import java.util.Set;
public class AndCondition implements ICondition
{
List<ICondition> conditions = new ArrayList<>();
public AndCondition() {}
public AndCondition(ICondition base)
{
addCondition(base);
conditions.add(base);
}
public void addCondition(ICondition e)
{
if(e == null) return;
conditions.add(e);
}
@Override
public boolean isValid(CompiledArguments args)
public boolean isValid(Set<String> parsePool)
{
for(int i = 0,m=conditions.size();i<m;i++)
{
if(!conditions.get(i).isValid(args))
if(!conditions.get(i).isValid(parsePool))
{
return false;
}

View File

@ -1,6 +1,6 @@
package speiger.src.builder.conditions;
import speiger.src.builder.processor.CompiledArguments;
import java.util.Set;
public class FlagCondition implements ICondition
{
@ -14,8 +14,8 @@ public class FlagCondition implements ICondition
}
@Override
public boolean isValid(CompiledArguments args)
public boolean isValid(Set<String> parsePool)
{
return args.test(flag) != inverted;
return parsePool.contains(flag) != inverted;
}
}

View File

@ -1,74 +1,61 @@
package speiger.src.builder.conditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import speiger.src.builder.misc.RegexUtil;
import speiger.src.builder.processor.CompiledArguments;
public interface ICondition
{
public static final Set<Character> VALID_CHARACTERS = new HashSet<>(Arrays.asList('(', ')'));
public static final ICondition ALWAYS_TRUE = T -> true;
public boolean isValid(CompiledArguments args);
public static ICondition parse(List<String> elements) {
List<ICondition> conditions = new ArrayList<>();
AndCondition activeAnd = null;
for(int i = 0,m=elements.size();i<m;i++) {
String entry = elements.get(i);
if(entry.equalsIgnoreCase("(")) {
int endIndex = RegexUtil.lastIndexOf(elements, i, "(", ")");
if(endIndex == -1) throw new IllegalStateException("A Condition Closer [ ) ] is missing");
ICondition result = parse(elements.subList(i+1, endIndex));
if(activeAnd != null) activeAnd.addCondition(result);
else conditions.add(result);
i = endIndex+1;
}
else if(entry.equalsIgnoreCase("&&")) {
if(activeAnd != null) continue;
if(i != 0) {
ICondition prev = conditions.get(conditions.size()-1);
if(prev instanceof AndCondition) activeAnd = (AndCondition)prev;
else {
activeAnd = new AndCondition(prev);
conditions.set(conditions.size()-1, activeAnd);
public boolean isValid(Set<String> parsePool);
public static ICondition parse(String condition)
{
String[] elements = condition.split(" ");
List<ICondition> conditions = new ArrayList<ICondition>();
for(int i = 0;i<elements.length;i++)
{
if(elements[i].equalsIgnoreCase("&&"))
{
if(i==elements.length-1)
{
continue;
}
if(condition.isEmpty())
{
conditions.add(new AndCondition(parseSimpleCondition(elements[++i])));
}
else
{
ICondition con = conditions.get(conditions.size() - 1);
if(con instanceof AndCondition)
{
((AndCondition)con).addCondition(parseSimpleCondition(elements[++i]));
}
else
{
AndCondition replacement = new AndCondition(con);
replacement.addCondition(parseSimpleCondition(elements[++i]));
conditions.set(conditions.size()-1, replacement);
}
}
else {
activeAnd = new AndCondition();
conditions.add(activeAnd);
}
}
else if(entry.equalsIgnoreCase("||")) {
activeAnd = null;
}
else {
if(activeAnd != null) activeAnd.addCondition(parseCondition(entry));
else conditions.add(parseCondition(entry));
else if(!elements[i].equalsIgnoreCase("||"))
{
conditions.add(parseSimpleCondition(elements[i]));
}
}
switch(conditions.size())
{
case 0: throw new IllegalStateException("Empty Conditions are not allowed");
case 0: return ALWAYS_TRUE;
case 1: return conditions.get(0);
default: return new OrCondition(conditions);
}
}
public static ICondition parse(String condition)
static ICondition parseSimpleCondition(String s)
{
return parse(Arrays.asList(RegexUtil.ensureWhitespaces(condition, VALID_CHARACTERS).split(" ")));
}
static ICondition parseCondition(String s)
{
ICondition numbers = NumberCondition.tryBuild(s);
if(numbers != null) return numbers;
return s.startsWith("!") ? new FlagCondition(s.substring(1), true) : new FlagCondition(s, false);
}
}

View File

@ -1,115 +0,0 @@
package speiger.src.builder.conditions;
import java.util.Arrays;
import java.util.Map;
import java.util.StringJoiner;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import speiger.src.builder.processor.CompiledArguments;
public class NumberCondition implements ICondition
{
private static final Pattern SCANNER = Pattern.compile(Operation.buildReggex());
String flag;
Operation op;
int number;
boolean flipped;
public NumberCondition(String flag, Operation op, int number, boolean flipped)
{
this.flag = flag;
this.op = op;
this.number = number;
this.flipped = flipped;
}
@Override
public boolean isValid(CompiledArguments args)
{
return op.matches(flipped ? number : args.get(flag), flipped ? args.get(flag) : number);
}
public static NumberCondition tryBuild(String arg)
{
Matcher match = SCANNER.matcher(arg);
if(!match.find()) return null;
int start = match.start();
int end = match.end();
Operation op = Operation.byId(arg.substring(start, end));
if(op == null) throw new IllegalArgumentException("Operation ["+arg.substring(start, end)+"] is unknown");
String key = arg.substring(0, start);
String value = arg.substring(end);
int[] result = new int[1];
if(parse(key, result)) return new NumberCondition(value, op, result[0], true);
if(parse(value, result)) return new NumberCondition(key, op, result[0], false);
throw new IllegalStateException("Neither key or value are parsable");
}
private static boolean parse(String arg, int[] output) {
try { output[0] = Integer.parseInt(arg); }
catch(Exception e) { return false;}
return true;
}
public static enum Operation
{
EQUALS("=="),
GREATER_EQUALS(">="),
GREATER(">"),
SMALLER_EQUALS("<="),
SMALLER("<"),
NOT_EQUALS("!="),
BIT_EQUALS_ALL("&="),
BIT_EQUALS_ANY("|="),
BIT_EQUALS_NOT("~=");
static final Map<String, Operation> DATA = Arrays.stream(values()).collect(Collectors.toMap(Operation::getId, Function.identity()));
String key;
private Operation(String key)
{
this.key = key;
}
public static String buildReggex()
{
StringJoiner joiner = new StringJoiner("|\\", "\\", "");
for(Operation entry : values())
{
joiner.add(entry.getId());
}
return joiner.toString();
}
public String getId()
{
return key;
}
public boolean matches(int key, int value)
{
switch(this)
{
case EQUALS: return key == value;
case NOT_EQUALS: return key != value;
case GREATER: return key > value;
case GREATER_EQUALS: return key >= value;
case SMALLER: return key < value;
case SMALLER_EQUALS: return key <= value;
case BIT_EQUALS_ALL: return (key & value) == value;
case BIT_EQUALS_ANY: return (key & value) != 0;
case BIT_EQUALS_NOT: return (key & value) == 0;
default: return true;
}
}
public static Operation byId(String key)
{
return DATA.get(key);
}
}
}

View File

@ -1,8 +1,7 @@
package speiger.src.builder.conditions;
import java.util.List;
import speiger.src.builder.processor.CompiledArguments;
import java.util.Set;
public class OrCondition implements ICondition
{
@ -14,11 +13,11 @@ public class OrCondition implements ICondition
}
@Override
public boolean isValid(CompiledArguments args)
public boolean isValid(Set<String> parsePool)
{
for(int i = 0,m=conditions.size();i<m;i++)
{
if(conditions.get(i).isValid(args))
if(conditions.get(i).isValid(parsePool))
{
return true;
}

View File

@ -1,8 +1,8 @@
package speiger.src.builder.mappers;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import speiger.src.builder.misc.RegexMatcher;
import speiger.src.builder.misc.RegexUtil;
public class ArgumentMapper implements IMapper
@ -49,34 +49,22 @@ public class ArgumentMapper implements IMapper
@Override
public String apply(String t)
{
RegexMatcher matcher = new RegexMatcher(pattern, t);
try
Matcher matcher = pattern.matcher(t);
if(matcher.find())
{
if(matcher.find())
StringBuffer buffer = new StringBuffer();
do
{
StringBuffer buffer = new StringBuffer();
do
String text = RegexUtil.searchUntil(t, matcher.end()-1, braces.charAt(0), braces.charAt(1));
if(!text.isEmpty())
{
String text = RegexUtil.searchUntil(t, matcher.end()-1, braces.charAt(0), braces.charAt(1));
if(!text.isEmpty())
{
matcher.appendReplacement(buffer, "").skip(text.length());
buffer.append(String.format(replacement, (Object[])getString(text).split(argumentBreaker)));
}
RegexUtil.skip(matcher.appendReplacement(buffer, ""), text.length());
buffer.append(String.format(replacement, (Object[])getString(text).split(argumentBreaker)));
}
while(matcher.find());
matcher.appendTail(buffer);
return apply(buffer.toString());
}
}
catch(Exception e)
{
e.printStackTrace();
}
catch(Error error)
{
System.out.println("Error with ["+pattern.pattern()+"] pattern");
throw error;
while(matcher.find());
matcher.appendTail(buffer);
return buffer.toString();
}
return t;
}

View File

@ -1,8 +1,8 @@
package speiger.src.builder.mappers;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import speiger.src.builder.misc.RegexMatcher;
import speiger.src.builder.misc.RegexUtil;
public class InjectMapper implements IMapper
@ -47,33 +47,21 @@ public class InjectMapper implements IMapper
@Override
public String apply(String t)
{
RegexMatcher matcher = new RegexMatcher(pattern, t);
try
Matcher matcher = pattern.matcher(t);
if(matcher.find())
{
if(matcher.find())
StringBuffer buffer = new StringBuffer();
do
{
StringBuffer buffer = new StringBuffer();
do
String text = RegexUtil.searchUntil(t, matcher.end()-1, braces.charAt(0), braces.charAt(1));
if(!text.isEmpty())
{
String text = RegexUtil.searchUntil(t, matcher.end()-1, braces.charAt(0), braces.charAt(1));
if(!text.isEmpty())
{
matcher.appendReplacement(buffer, "").skip(text.length());
buffer.append(String.format(replacement, getString(text)));
}
} while (matcher.find());
matcher.appendTail(buffer);
return apply(buffer.toString());
}
}
catch(Exception e)
{
e.printStackTrace();
}
catch(Error error)
{
System.out.println("Error with ["+pattern.pattern()+"] pattern");
throw error;
RegexUtil.skip(matcher.appendReplacement(buffer, ""), text.length());
buffer.append(String.format(replacement, getString(text)));
}
} while (matcher.find());
matcher.appendTail(buffer);
return buffer.toString();
}
return t;
}

View File

@ -1,8 +1,8 @@
package speiger.src.builder.mappers;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import speiger.src.builder.misc.RegexMatcher;
import speiger.src.builder.misc.RegexUtil;
public class LineMapper implements IMapper
@ -30,35 +30,23 @@ public class LineMapper implements IMapper
@Override
public String apply(String t)
{
RegexMatcher matcher = new RegexMatcher(pattern, t);
try
Matcher matcher = pattern.matcher(t);
if(matcher.find())
{
if(matcher.find())
StringBuffer buffer = new StringBuffer();
do
{
StringBuffer buffer = new StringBuffer();
do
int start = matcher.end() - 1;
int[] result = RegexUtil.findFullLine(t, start);
if(result != null)
{
int start = matcher.end() - 1;
int[] result = RegexUtil.findFullLine(t, start);
if(result != null)
{
matcher.appendReplacement(buffer, pattern.pattern());
buffer.setLength(buffer.length() - (start - result[0]));
matcher.skip(result[1] - start);
}
} while (matcher.find());
matcher.appendTail(buffer);
return apply(buffer.toString());
}
}
catch(Exception e)
{
e.printStackTrace();
}
catch(Error error)
{
System.out.println("Error with ["+pattern.pattern()+"] pattern");
throw error;
matcher.appendReplacement(buffer, pattern.pattern());
buffer.setLength(buffer.length() - (start - result[0]));
RegexUtil.skip(matcher, result[1] - start);
}
} while (matcher.find());
matcher.appendTail(buffer);
return buffer.toString();
}
return t;
}

View File

@ -29,19 +29,6 @@ public class SimpleMapper implements IMapper
@Override
public String apply(String t)
{
try
{
return pattern.matcher(t).replaceAll(replacement);
}
catch(Exception e)
{
e.printStackTrace();
}
catch(Error error)
{
System.out.println("Error with ["+pattern.pattern()+"] pattern");
throw error;
}
return t;
return pattern.matcher(t).replaceAll(replacement);
}
}

View File

@ -6,10 +6,9 @@ import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class FileUtils
{
@ -41,11 +40,9 @@ public class FileUtils
{
try(BufferedWriter writer = Files.newBufferedWriter(dataFolder.resolve("cache.bin")))
{
List<String> keys = new ArrayList<String>(mappings.keySet());
keys.sort(String.CASE_INSENSITIVE_ORDER);
for(String s : keys)
for(Entry<String, String> entry : mappings.entrySet())
{
writer.write(s+"="+mappings.get(s));
writer.write(entry.getKey()+"="+entry.getValue());
writer.newLine();
}
writer.flush();

View File

@ -1,18 +0,0 @@
package speiger.src.builder.misc;
import java.util.concurrent.atomic.AtomicInteger;
public class IdGenerator
{
AtomicInteger integer = new AtomicInteger();
public void appendId()
{
integer.incrementAndGet();
}
public String getId()
{
return "#ignoreLine"+integer.get()+"suffix";
}
}

View File

@ -1,84 +0,0 @@
package speiger.src.builder.misc;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatcher
{
Matcher match;
StringWrapper text;
public RegexMatcher(Pattern pattern, String text)
{
this.text = new StringWrapper(text);
match = pattern.matcher(this.text);
}
public boolean find()
{
return match.find();
}
public int end()
{
return match.end()+text.getOffset();
}
public RegexMatcher appendReplacement(StringBuffer sb, String replacement)
{
match.appendReplacement(sb, replacement);
return this;
}
public RegexMatcher appendTail(StringBuffer sb)
{
match.appendTail(sb);
return this;
}
public RegexMatcher skip(int amount)
{
text.offset(amount+match.end());
match.reset();
return this;
}
public static class StringWrapper implements CharSequence
{
String s;
int offset;
public StringWrapper(String s)
{
this.s = s;
}
@Override
public int length()
{
return s.length() - offset;
}
@Override
public char charAt(int index)
{
return s.charAt(index+offset);
}
@Override
public CharSequence subSequence(int start, int end)
{
return s.subSequence(start+offset, end+offset);
}
public void offset(int offset)
{
this.offset += offset;
}
public int getOffset()
{
return offset;
}
}
}

View File

@ -1,10 +1,25 @@
package speiger.src.builder.misc;
import java.util.List;
import java.util.Set;
import java.lang.reflect.Field;
import java.util.regex.Matcher;
public class RegexUtil
{
static Field LAST_POS;
public static Matcher skip(Matcher matcher, int amount)
{
try
{
LAST_POS.setInt(matcher, LAST_POS.getInt(matcher) + amount);
}
catch(Exception e)
{
e.printStackTrace();
}
return matcher;
}
public static String searchUntil(String text, int startIndex, char increase, char decrease)
{
if(text.charAt(startIndex + 1) != increase)
@ -46,31 +61,17 @@ public class RegexUtil
return new int[]{start, offset};
}
public static int lastIndexOf(List<String> list, int startIndex, String increase, String decrease)
static
{
if(!list.get(startIndex).equalsIgnoreCase(increase)) return -1;
int inc = 0;
for(int i = startIndex;i<list.size();i++)
try
{
String entry = list.get(i);
if(entry.equalsIgnoreCase(increase)) inc++;
else if(entry.equalsIgnoreCase(decrease)) {
inc--;
if(inc <= 0) return i;
}
Field field = Matcher.class.getDeclaredField("lastAppendPosition");
field.setAccessible(true);
LAST_POS = field;
}
return -1;
}
public static String ensureWhitespaces(String s, Set<Character> set) {
StringBuilder builder = new StringBuilder(s);
for(int i = s.length()-1;i>=0;i--) {
char entry = builder.charAt(i);
if(entry != ' ' && set.contains(entry)) {
if(builder.charAt(i+1) != ' ') builder.insert(i+1, ' ');
if(builder.charAt(i-1) != ' ') builder.insert(i, ' ');
}
catch(Exception e)
{
e.printStackTrace();
}
return builder.toString();
}
}
}

View File

@ -14,21 +14,19 @@ public class BuildTask implements Runnable
Template template;
TemplateProcess process;
Set<IMapper>[] mappers;
boolean silencedSuccess;
public BuildTask(Path basePath, Template template, TemplateProcess process, boolean silencedSuccess, Set<IMapper>[] mappers)
public BuildTask(Path basePath, Template template, TemplateProcess process, Set<IMapper>[] mappers)
{
this.basePath = basePath;
this.template = template;
this.process = process;
this.silencedSuccess = silencedSuccess;
this.mappers = mappers;
}
@Override
public void run()
{
String s = template.build(new CompiledArguments(process), mappers != null, mappers != null ? mappers[1] : null);
String s = template.build(process.parsePool, process.mappers, mappers != null, mappers != null ? mappers[1] : null);
if(mappers != null)
{
mappers[0].addAll(process.mappers);
@ -46,7 +44,7 @@ public class BuildTask implements Runnable
{
writer.write(s);
writer.flush();
if(!silencedSuccess) System.out.println("Created: "+process.fileName);
System.out.println("Created: "+process.fileName);
}
catch(Exception e)
{

View File

@ -1,36 +0,0 @@
package speiger.src.builder.processor;
import java.util.List;
import java.util.Map;
import java.util.Set;
import speiger.src.builder.mappers.IMapper;
public class CompiledArguments
{
List<IMapper> mapper;
Set<String> flags;
Map<String, Integer> flaggedValues;
public CompiledArguments(TemplateProcess process)
{
mapper = process.mappers;
flags = process.parsePool;
flaggedValues = process.parseValues;
}
public List<IMapper> getMapper()
{
return mapper;
}
public boolean test(String key)
{
return flags.contains(key);
}
public int get(String key)
{
return flaggedValues.getOrDefault(key, 0);
}
}

View File

@ -4,10 +4,8 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.UnaryOperator;
@ -18,7 +16,6 @@ public class TemplateProcess
UnaryOperator<Path> pathBuilder;
String fileName;
Set<String> parsePool = new HashSet<>();
Map<String, Integer> parseValues = new HashMap<>();
List<IMapper> mappers = new ArrayList<>();
public TemplateProcess(String fileName)
@ -26,45 +23,28 @@ public class TemplateProcess
this.fileName = fileName;
}
public TemplateProcess setPathBuilder(UnaryOperator<Path> pathBuilder)
public void setPathBuilder(UnaryOperator<Path> pathBuilder)
{
this.pathBuilder = pathBuilder;
return this;
}
public TemplateProcess addFlags(String...flags)
public void addFlags(String...flags)
{
parsePool.addAll(Arrays.asList(flags));
return this;
}
public TemplateProcess addFlags(Collection<String> flags)
public void addFlags(Collection<String> flags)
{
parsePool.addAll(flags);
return this;
}
public TemplateProcess addValue(String key, int value)
{
parseValues.put(key, value);
return this;
}
public TemplateProcess addValues(Map<String, Integer> values)
{
parseValues.putAll(values);
return this;
}
public TemplateProcess addMapper(IMapper mapper)
public void addMapper(IMapper mapper)
{
mappers.add(mapper);
return this;
}
public TemplateProcess addMappers(Collection<IMapper> mappers)
public void addMappers(Collection<IMapper> mappers)
{
this.mappers.addAll(mappers);
return this;
}
}

View File

@ -11,7 +11,6 @@ import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@ -24,79 +23,25 @@ public abstract class TemplateProcessor
Path sourceFolder;
Path outputFolder;
Path dataFolder;
boolean silencedSuccess;
boolean init = false;
public TemplateProcessor(Path sourceFolder, Path outputFolder, Path dataFolder)
{
this(false, sourceFolder, outputFolder, dataFolder);
}
public TemplateProcessor(boolean silencedSuccess, Path sourceFolder, Path outputFolder, Path dataFolder)
{
this.silencedSuccess = silencedSuccess;
this.sourceFolder = sourceFolder;
this.outputFolder = outputFolder;
this.dataFolder = dataFolder;
}
/**
* Function that is called before the initial run of the template processor.
* It is only called once to basically initialize the program and then run as needed.
*/
protected abstract void init();
/**
* Function that decides which file is going to be used and which not. Basically black/white list as needed
* @param fileName FileName without folder structure. Since this is designed to have 0 duplicated file names.
* @return true if it is valid to be processed or false if it isn't
*/
protected abstract boolean isFileValid(Path fileName);
/**
* Main function that processes a filename to its target
* @param fileName name of the file that should be processed without the type of file. (.template or .json etc etc)
* @param process all modifications to the file that should be executed
*/
public abstract void createProcesses(String fileName, Consumer<TemplateProcess> process);
/**
* Function that asks if the folder structure on the source folder should be kept or not
* @return true if the source-structure should be kept or flattened.
*/
protected abstract boolean relativePackages();
/**
* Function that tests if a Mapper was used or not. Useful for small scale projects that barely have any mappers
* but sadly more like to cause not needed warnings for large scale projects.
* @return true if it should be enabled
*/
protected abstract boolean debugUnusedMappers();
/**
* Function called before the Template Processor runs.
* But after init is called and All files are loaded in and the task queue is already ready.
*/
protected void beforeStart() {}
/**
* Function that is called while the template generation is running and all after the File hashes for the memory are being generated.
* If you have anything to do while the processor is running this would be the ideal time to do it.
*/
protected void whileProcessing() {}
/**
* Function that is being called after the template processor is called and after the file cache has been updated
* Basically just before "Saved Changes" is called.
*/
protected void afterFinish() {}
protected Path getSourceFolder() { return sourceFolder; }
protected Path getOutputFolder() { return outputFolder; }
protected Path getDataFolder() { return dataFolder; }
protected boolean isSilencedSuccess() { return silencedSuccess; }
@SuppressWarnings("unchecked")
public final boolean process(boolean force) throws IOException, InterruptedException
{
if(!init)
@ -111,24 +56,19 @@ public abstract class TemplateProcessor
System.out.println("Nothing has changed");
return false;
}
AtomicLong[] counters = new AtomicLong[]{new AtomicLong(), new AtomicLong(), new AtomicLong()};
final boolean relative = relativePackages();
Set<IMapper>[] mappers = debugUnusedMappers() ? new Set[]{Collections.synchronizedSet(new HashSet<>()), Collections.synchronizedSet(new HashSet<>())} : null;
Set<IMapper>[] mappers = debugUnusedMappers() ? new Set[]{Collections.synchronizedSet(new HashSet<IMapper>()), Collections.synchronizedSet(new HashSet<IMapper>())} : null;
ThreadPoolExecutor service = (ThreadPoolExecutor)Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
service.setKeepAliveTime(10, TimeUnit.MILLISECONDS);
service.allowCoreThreadTimeOut(true);
beforeStart();
service.submit(() -> {
for(int i = 0,m=pathsLeft.size();i<m;i++)
{
Path path = pathsLeft.get(i);
try
{
long startTime = System.currentTimeMillis();
Template template = Template.parse(path);
counters[2].addAndGet(System.currentTimeMillis() - startTime);
counters[1].addAndGet(1);
createProcesses(FileUtils.getFileName(path), T -> {service.execute(new BuildTask(relative ? outputFolder.resolve(sourceFolder.relativize(path).getParent()) : outputFolder, template, T, silencedSuccess, mappers));counters[0].addAndGet(1);});
createProcesses(FileUtils.getFileName(path), T -> service.execute(new BuildTask(relative ? outputFolder.resolve(sourceFolder.relativize(path).getParent()) : outputFolder, template, T, mappers)));
}
catch(Exception e)
{
@ -143,7 +83,6 @@ public abstract class TemplateProcessor
Path path = pathsLeft.get(i);
existing.put(FileUtils.getFileName(path), FileUtils.getMD5String(path));
}
whileProcessing();
while(service.getActiveCount() > 0)
{
Thread.sleep(10);
@ -156,10 +95,9 @@ public abstract class TemplateProcessor
System.out.println("Mapper ["+mapper.getSearchValue()+"] is not used in the Entire Build Process");
}
}
System.out.println("Finished Building ["+counters[0].get()+"] Files from ["+counters[1].get()+"] in "+(System.currentTimeMillis() - start)+"ms (Template Parsing: "+counters[2].get()+"ms (avg: "+((counters[2].get() / Math.max(1D, counters[1].get())))+"ms)");
System.out.println("Finished Tasks: "+(System.currentTimeMillis() - start)+"ms");
FileUtils.saveMappings(existing, dataFolder);
afterFinish();
System.out.println("Saved Changes");
System.out.print("Saved Changes");
return true;
}
}

View File

@ -1,68 +0,0 @@
package example;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Consumer;
import speiger.src.builder.mappers.SimpleMapper;
import speiger.src.builder.processor.TemplateProcess;
import speiger.src.builder.processor.TemplateProcessor;
public class ExampleBuilder extends TemplateProcessor
{
public static void main(String...args)
{
try
{
new ExampleBuilder().process(true);
}
catch(IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch(InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public ExampleBuilder()
{
super(Paths.get("example/input"), Paths.get("example/output"), Paths.get("example"));
}
@Override
protected void init()
{
}
@Override
protected boolean isFileValid(Path fileName)
{
return true;
}
@Override
public void createProcesses(String fileName, Consumer<TemplateProcess> process)
{
process.accept(new TemplateProcess(fileName+".txt").addFlags("TEST0").addMapper(new SimpleMapper("TESTING", "Test2")));
}
@Override
protected boolean relativePackages()
{
return false;
}
@Override
protected boolean debugUnusedMappers()
{
return false;
}
}