Skip to content

Commit 112d7c7

Browse files
authored
Merge pull request #51 from metafacture/35-record
Basic if statements and record mode draft
2 parents 3093168 + 547c4b1 commit 112d7c7

File tree

8 files changed

+782
-25
lines changed

8 files changed

+782
-25
lines changed

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ subprojects {
3232
'mockito': '2.27.0',
3333
'requirejs': '2.3.6',
3434
'slf4j': '1.7.21',
35-
'xtext': '2.17.0'
35+
'xtext': '2.17.0',
36+
'guava': '29.0-jre'
3637
]
3738
}
3839

config/checkstyle/checkstyle.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<property name="checks" value=".*"/>
88
<property name="files" value="xtext-gen"/>
99
</module>
10+
<module name="SuppressWarningsFilter" />
1011
<module name="TreeWalker">
1112
<module name="AbstractClassName"/>
1213
<module name="AnnotationUseStyle"/>
@@ -145,6 +146,7 @@
145146
<property name="checkFormat" value="$1"/>
146147
<property name="commentFormat" value="checkstyle-disable-line (\w+(?:\|\w+)?)"/>
147148
</module>
149+
<module name="SuppressWarningsHolder" />
148150
<module name="ThrowsCount">
149151
<property name="max" value="2"/>
150152
</module>

org.metafacture.fix/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ plugins {
66
dependencies {
77
compile "org.eclipse.xtext:org.eclipse.xtext:${versions.xtext}"
88
compile "org.eclipse.xtext:org.eclipse.xtext.xbase:${versions.xtext}"
9+
compile "com.google.guava:guava:${versions.guava}"
910

1011
testCompile "org.junit.jupiter:junit-jupiter-api:${versions.junit_jupiter}"
1112
testCompile "org.junit.platform:junit-platform-launcher:${versions.junit_platform}"

org.metafacture.fix/src/main/java/org/metafacture/metamorph/FixBuilder.java

Lines changed: 96 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
import org.metafacture.fix.fix.Do;
2121
import org.metafacture.fix.fix.Expression;
2222
import org.metafacture.fix.fix.Fix;
23+
import org.metafacture.fix.fix.If;
2324
import org.metafacture.fix.fix.MethodCall;
2425
import org.metafacture.fix.fix.Options;
2526
import org.metafacture.metamorph.api.Collect;
27+
import org.metafacture.metamorph.api.ConditionAware;
2628
import org.metafacture.metamorph.api.FlushListener;
2729
import org.metafacture.metamorph.api.Function;
2830
import org.metafacture.metamorph.api.InterceptorFactory;
@@ -31,6 +33,7 @@
3133
import org.metafacture.metamorph.functions.NotEquals;
3234
import org.metafacture.metamorph.functions.Replace;
3335

36+
import com.google.common.collect.Multimap;
3437
import org.eclipse.emf.common.util.EList;
3538
import org.eclipse.xtext.xbase.lib.Pair;
3639

@@ -54,6 +57,7 @@ public class FixBuilder { // checkstyle-disable-line ClassDataAbstractionCouplin
5457
static final String ARRAY_MARKER = "[]";
5558
private static final String FLUSH_WITH = "flushWith";
5659
private static final String RECORD = "record";
60+
5761
private final Deque<StackFrame> stack = new LinkedList<>();
5862
private final InterceptorFactory interceptorFactory;
5963
private final Metafix metafix;
@@ -177,10 +181,12 @@ protected void exitCollectorAndFlushWith(final String flushWith) {
177181
if (parent.isInEntity()) {
178182
((Entity) parent.getPipe()).setNameSource(delegate);
179183
}
180-
// TODO: condition handling, see MorphBuilder
181-
182-
parent.getPipe().addNamedValueSource(delegate);
183-
184+
else if (parent.isInCondition()) {
185+
((ConditionAware) parent.getPipe()).setConditionSource(delegate);
186+
}
187+
else {
188+
parent.getPipe().addNamedValueSource(delegate);
189+
}
184190
final Collect collector = (Collect) tailPipe;
185191
if (null != flushWith) {
186192
collector.setWaitForFlush(true);
@@ -218,19 +224,72 @@ private void processSubexpressions(final List<Expression> expressions, final Str
218224
if (sub instanceof Do) {
219225
processBind(sub, p);
220226
}
227+
else if (sub instanceof If) {
228+
processConditional(sub, p);
229+
}
221230
else {
222231
processFunction(sub, p, source);
223232
}
224233
}
225234
}
226235

236+
private void processConditional(final Expression expression, final EList<String> p) {
237+
final boolean isTopLevelIf = stack.peek().pipe instanceof Metafix;
238+
// If we're at the top level, we wrap the If into a collector:
239+
if (isTopLevelIf) {
240+
final Collect collect = collectFactory.newInstance("choose");
241+
stack.push(new StackFrame(collect));
242+
}
243+
enterIf();
244+
final If theIf = (If) expression;
245+
enterDataMap(p, false);
246+
final Map<String, String> attributes = resolvedAttributeMap(p, null);
247+
attributes.put("string", resolvedAttribute(p, 2)); // for contains & equals morph functions
248+
// TODO: support morph functions: regexp -> match, morph quantors as prefixes: none_, all_, any_
249+
runMetamorphFunction(expression.getName(), attributes);
250+
exitData();
251+
// The Metamorph IF acts like a guard, executing not nested statements, but following statements:
252+
exitIf();
253+
processSubexpressions(theIf.getElements(), resolvedAttribute(p, 1));
254+
// As a draft for a record mode, we might do something like this instead:
255+
if (metafix.isRecordMode() && testConditional(theIf.getName(), p)) {
256+
processSubexpressions(theIf.getElements(), resolvedAttribute(p, 1));
257+
}
258+
// If we're at the top level, we close the wrapping collector:
259+
if (isTopLevelIf) {
260+
exitCollectorAndFlushWith(RECORD);
261+
}
262+
}
263+
264+
private boolean testConditional(final String conditional, final EList<String> p) {
265+
System.out.printf("<IF>: %s p: %s\n", conditional, p);
266+
boolean result = false;
267+
final String field = resolvedAttribute(p, 1);
268+
final String value = resolvedAttribute(p, 2);
269+
final Multimap<String, String> map = metafix.getCurrentRecord();
270+
System.out.printf("<%s>: field: %s value: %s in: %s\n", conditional, field, value, map);
271+
switch (conditional) {
272+
case "any_match":
273+
result = map.containsKey(field) && map.get(field).stream().anyMatch(v -> v.matches(value));
274+
break;
275+
case "all_match":
276+
result = map.containsKey(field) && map.get(field).stream().allMatch(v -> v.matches(value));
277+
break;
278+
default:
279+
}
280+
return result;
281+
}
282+
227283
private void processFunction(final Expression expression, final List<String> params, final String source) {
228284
final FixFunction functionToRun = findFixFunction(expression);
229285
if (functionToRun != null) {
286+
System.out.printf("Running Fix function %s, params %s, source %s\n", expression.getName(), params, source);
230287
functionToRun.apply(this, expression, params, source);
231288
}
232289
else {
233-
runMetamorphFunction(expression, params);
290+
final Options options = ((MethodCall) expression).getOptions();
291+
final Map<String, String> attributes = resolvedAttributeMap(params, options);
292+
runMetamorphFunction(expression.getName(), attributes);
234293
}
235294
}
236295

@@ -243,15 +302,15 @@ private FixFunction findFixFunction(final Expression expression) {
243302
return null;
244303
}
245304

246-
private void runMetamorphFunction(final Expression expression, final List<String> params) {
247-
final Map<String, String> attributes = resolvedAttributeMap(params, ((MethodCall) expression).getOptions());
248-
if (functionFactory.containsKey(expression.getName())) {
305+
private void runMetamorphFunction(final String name, final Map<String, String> attributes) {
306+
if (functionFactory.containsKey(name)) {
249307
final String flushWith = attributes.remove(FLUSH_WITH);
250-
final Function function = functionFactory.newInstance(expression.getName(), attributes);
308+
final Function function = functionFactory.newInstance(name, attributes);
251309
if (null != flushWith) {
252310
registerFlush(flushWith, function);
253311
}
254312
function.setMaps(metafix);
313+
255314
final StackFrame head = stack.peek();
256315
final NamedValuePipe interceptor = interceptorFactory.createNamedValueInterceptor();
257316
final NamedValuePipe delegate;
@@ -266,7 +325,7 @@ private void runMetamorphFunction(final Expression expression, final List<String
266325
head.setPipe(function);
267326
}
268327
else {
269-
throw new IllegalArgumentException(expression.getName() + " not found");
328+
throw new IllegalArgumentException(name + " not found");
270329
}
271330
}
272331

@@ -288,10 +347,12 @@ void exitData() {
288347
if (parent.isInEntity()) {
289348
((Entity) parent.getPipe()).setNameSource(delegate);
290349
}
291-
292-
// TODO: condition handling, see MorphBuilder
293-
294-
parent.getPipe().addNamedValueSource(delegate);
350+
else if (parent.isInCondition()) {
351+
((ConditionAware) parent.getPipe()).setConditionSource(delegate);
352+
}
353+
else {
354+
parent.getPipe().addNamedValueSource(delegate);
355+
}
295356
}
296357

297358
NamedValuePipe enterDataMap(final List<String> params, final boolean standalone) {
@@ -356,6 +417,17 @@ void enterDataFunction(final String fieldName, final NamedValuePipe function, fi
356417
head.setPipe(function);
357418
}
358419

420+
void enterIf() {
421+
assert stack.peek().getPipe() instanceof ConditionAware :
422+
"statement `if` is not allowed in the current element";
423+
424+
stack.peek().setInCondition(true);
425+
}
426+
427+
void exitIf() {
428+
stack.peek().setInCondition(false);
429+
}
430+
359431
private void addNestedField(final List<String> params, final String resolvedAttribute) {
360432
final String[] keyElements = resolvedAttribute.split("\\.");
361433
final Pair<Entity, Entity> firstAndLast = createEntities(keyElements);
@@ -418,10 +490,20 @@ private static class StackFrame {
418490

419491
private boolean inEntity;
420492

493+
private boolean inCondition;
494+
421495
private StackFrame(final NamedValuePipe pipe) {
422496
this.pipe = pipe;
423497
}
424498

499+
public void setInCondition(final boolean inCondition) {
500+
this.inCondition = inCondition;
501+
}
502+
503+
public boolean isInCondition() {
504+
return inCondition;
505+
}
506+
425507
public NamedValuePipe getPipe() {
426508
return pipe;
427509
}

0 commit comments

Comments
 (0)