From cfc62dea7a0a1bfbc8a79725973064653115b04f Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Sat, 25 Feb 2017 20:42:50 +0100 Subject: [PATCH 1/5] [tracing] Added support for tracing in code generation (#287) Signed-off-by: Sven Efftinge --- .../trace/node/GeneratorNodeTest.xtend | 107 +++++++++ .../trace/node/TemplateNodeTest.xtend | 66 ++++++ .../trace/node/GeneratorNodeTest.java | 210 +++++++++++++++++ .../trace/node/TemplateNodeTest.java | 117 ++++++++++ org.eclipse.xtext/META-INF/MANIFEST.MF | 1 + .../generator/trace/node/CompositeNode.xtend | 20 ++ .../trace/node/GeneratorNodeExtensions.xtend | 58 +++++ .../trace/node/GeneratorNodeProcessor.xtend | 122 ++++++++++ .../generator/trace/node/IGeneratorNode.xtend | 18 ++ .../generator/trace/node/IndentNode.xtend | 17 ++ .../generator/trace/node/NewLineNode.xtend | 15 ++ .../generator/trace/node/TemplateNode.xtend | 109 +++++++++ .../xtext/generator/trace/node/TextNode.xtend | 17 ++ .../generator/trace/node/TraceNode.xtend | 22 ++ .../generator/trace/node/CompositeNode.java | 28 +++ .../trace/node/GeneratorNodeExtensions.java | 123 ++++++++++ .../trace/node/GeneratorNodeProcessor.java | 221 ++++++++++++++++++ .../generator/trace/node/IGeneratorNode.java | 17 ++ .../generator/trace/node/IndentNode.java | 48 ++++ .../generator/trace/node/NewLineNode.java | 17 ++ .../generator/trace/node/TemplateNode.java | 145 ++++++++++++ .../xtext/generator/trace/node/TextNode.java | 67 ++++++ .../xtext/generator/trace/node/TraceNode.java | 85 +++++++ 23 files changed, 1650 insertions(+) create mode 100644 org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend create mode 100644 org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.xtend create mode 100644 org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java create mode 100644 org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeNode.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IGeneratorNode.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/NewLineNode.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TextNode.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeNode.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IGeneratorNode.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/NewLineNode.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TextNode.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend new file mode 100644 index 000000000..65726539c --- /dev/null +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import org.eclipse.xtend2.lib.StringConcatenationClient +import org.eclipse.xtext.generator.trace.LocationData +import org.eclipse.xtext.generator.trace.SourceRelativeURI +import org.junit.Assert +import org.junit.Test + +/** + * @author Sven Efftinge - Initial contribution and API + */ +class GeneratorNodeTest { + + extension GeneratorNodeExtensions exts = new GeneratorNodeExtensions(" ") + + @Test def void testBasicCreationAndProcessing() { + val root = loc(0) + var node = root.startTrace + .append('notindented').appendNewLine + node.indent.trace(loc(1)) + .append("indented1").appendNewLine + .append("indented2") + node.appendNewLine.append("dedented") + val processor = new GeneratorNodeProcessor(new StringBuilder, " ", "\n") + processor.process(node) + Assert.assertEquals(''' + notindented + indented1 + indented2 + dedented'''.toString, processor.contents.toString) + Assert.assertEquals(''' + CompletableTraceRegion [myOffset=0, myLength=44] associations={ + LocationData [TextRegionWithLineInformation [0:100][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } nestedRegions={ + CompletableTraceRegion [myOffset=14, myLength=21] associations={ + LocationData [TextRegionWithLineInformation [1:99][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } + }'''.toString, processor.currentRegion.toString) + } + + + @Test def void testTemplateProcessing() { + val root = loc(0) + var node = root.startTrace + .appendTemplate(''' + «someCodeGen(2)» + ''') + val processor = new GeneratorNodeProcessor(new StringBuilder, " ", "\n") + processor.process(node) + Assert.assertEquals(''' + before Hello after + before Hello after + + before Hello after + + + before Hello after + before Hello after + + before Hello after + + + + '''.toString, processor.contents.toString) + Assert.assertEquals(''' + CompletableTraceRegion [myOffset=0, myLength=153] associations={ + LocationData [TextRegionWithLineInformation [0:100][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } nestedRegions={ + CompletableTraceRegion [myOffset=7, myLength=5] associations={ + LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } + CompletableTraceRegion [myOffset=30, myLength=5] associations={ + LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } + CompletableTraceRegion [myOffset=58, myLength=5] associations={ + LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } + CompletableTraceRegion [myOffset=83, myLength=5] associations={ + LocationData [TextRegionWithLineInformation [11:89][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } + CompletableTraceRegion [myOffset=106, myLength=5] associations={ + LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } + CompletableTraceRegion [myOffset=134, myLength=5] associations={ + LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] + } + }'''.toString, processor.currentRegion.toString) + } + + def StringConcatenationClient someCodeGen(int n) ''' + «FOR i : 0.. 1» + «FOR i : 1..4» + «other» «i» + «multiLineString» «multiLineString» + «ENDFOR» + «ENDIF» + ''') + } + + private def other() ''' + foo «"dfdf" + 23» bar + ''' + + private def String multiLineString() ''' + test + bar + «other()» + ''' + + def void assertEquals(StringConcatenationClient c) { + val ext = new GeneratorNodeExtensions(" ") + val processor = new GeneratorNodeProcessor(new StringBuilder, " ", "\n") + + val root = new CompositeNode() + ext.appendTemplate(root, c); + processor.process(root) + + val expected = new StringConcatenation() + expected.append(c) + Assert.assertEquals(expected.toString, processor.contents.toString) + } +} \ No newline at end of file diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java new file mode 100644 index 000000000..2cb2de740 --- /dev/null +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java @@ -0,0 +1,210 @@ +/** + * Copyright (c) 2017 TypeFox (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.generator.trace.LocationData; +import org.eclipse.xtext.generator.trace.SourceRelativeURI; +import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; +import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.xbase.lib.ExclusiveRange; +import org.eclipse.xtext.xbase.lib.Extension; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@SuppressWarnings("all") +public class GeneratorNodeTest { + @Extension + private GeneratorNodeExtensions exts = new GeneratorNodeExtensions(" "); + + @Test + public void testBasicCreationAndProcessing() { + final LocationData root = this.loc(0); + CompositeNode node = this.exts.appendNewLine(this.exts.append(this.exts.startTrace(root), "notindented")); + this.exts.append(this.exts.appendNewLine(this.exts.append(this.exts.trace(this.exts.indent(node), this.loc(1)), "indented1")), "indented2"); + this.exts.append(this.exts.appendNewLine(node), "dedented"); + StringBuilder _stringBuilder = new StringBuilder(); + final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); + processor.process(node); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("notindented"); + _builder.newLine(); + _builder.append(" "); + _builder.append("indented1"); + _builder.newLine(); + _builder.append(" "); + _builder.append("indented2"); + _builder.newLine(); + _builder.append("dedented"); + Assert.assertEquals(_builder.toString(), processor.getContents().toString()); + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("CompletableTraceRegion [myOffset=0, myLength=44] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [0:100][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append("} nestedRegions={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("CompletableTraceRegion [myOffset=14, myLength=21] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [1:99][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append("}"); + Assert.assertEquals(_builder_1.toString(), processor.getCurrentRegion().toString()); + } + + @Test + public void testTemplateProcessing() { + final LocationData root = this.loc(0); + CompositeNode _startTrace = this.exts.startTrace(root); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + StringConcatenationClient _someCodeGen = GeneratorNodeTest.this.someCodeGen(2); + _builder.append(_someCodeGen); + _builder.newLineIfNotEmpty(); + } + }; + IGeneratorNode node = this.exts.appendTemplate(_startTrace, _client); + StringBuilder _stringBuilder = new StringBuilder(); + final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); + processor.process(node); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("before Hello after"); + _builder.newLine(); + _builder.append(" "); + _builder.append("before Hello after"); + _builder.newLine(); + _builder.append(" "); + _builder.newLine(); + _builder.append(" "); + _builder.append("before Hello after"); + _builder.newLine(); + _builder.append(" "); + _builder.newLine(); + _builder.newLine(); + _builder.append("before Hello after"); + _builder.newLine(); + _builder.append(" "); + _builder.append("before Hello after"); + _builder.newLine(); + _builder.append(" "); + _builder.newLine(); + _builder.append(" "); + _builder.append("before Hello after"); + _builder.newLine(); + _builder.append(" "); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + Assert.assertEquals(_builder.toString(), processor.getContents().toString()); + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("CompletableTraceRegion [myOffset=0, myLength=153] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [0:100][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append("} nestedRegions={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("CompletableTraceRegion [myOffset=7, myLength=5] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("CompletableTraceRegion [myOffset=30, myLength=5] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("CompletableTraceRegion [myOffset=58, myLength=5] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("CompletableTraceRegion [myOffset=83, myLength=5] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [11:89][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("CompletableTraceRegion [myOffset=106, myLength=5] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("CompletableTraceRegion [myOffset=134, myLength=5] associations={"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append("}"); + Assert.assertEquals(_builder_1.toString(), processor.getCurrentRegion().toString()); + } + + public StringConcatenationClient someCodeGen(final int n) { + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + { + ExclusiveRange _doubleDotLessThan = new ExclusiveRange(0, n, true); + for(final Integer i : _doubleDotLessThan) { + _builder.append("before "); + CompositeNode _append = GeneratorNodeTest.this.exts.append(GeneratorNodeTest.this.exts.startTrace(GeneratorNodeTest.this.loc((10 + (i).intValue()))), "Hello"); + _builder.append(_append); + _builder.append(" after"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + StringConcatenationClient _someCodeGen = GeneratorNodeTest.this.someCodeGen((n - 1)); + _builder.append(_someCodeGen, " "); + _builder.newLineIfNotEmpty(); + } + } + } + }; + return _client; + } + + public LocationData loc(final int idx) { + SourceRelativeURI _sourceRelativeURI = new SourceRelativeURI("foo/mymodel.dsl"); + return new LocationData(idx, (100 - idx), 0, 0, _sourceRelativeURI); + } +} diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java new file mode 100644 index 000000000..0d00ed5eb --- /dev/null +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2017 itemis AG (http://www.itemis.eu) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; +import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor; +import org.eclipse.xtext.xbase.lib.IntegerRange; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@SuppressWarnings("all") +public class TemplateNodeTest { + @Test + public void testSimpleString() { + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("fooo bar"); + _builder.newLine(); + } + }; + this.assertEquals(_client); + } + + @Test + public void testSimpleTemplate_01() { + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + String _multiLineString = TemplateNodeTest.this.multiLineString(); + _builder.append(_multiLineString); + _builder.append(" "); + String _multiLineString_1 = TemplateNodeTest.this.multiLineString(); + _builder.append(_multiLineString_1); + _builder.newLineIfNotEmpty(); + } + }; + this.assertEquals(_client); + } + + @Test + public void testString() { + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("fooo bar"); + _builder.newLine(); + { + if ((2 > 1)) { + { + IntegerRange _upTo = new IntegerRange(1, 4); + for(final Integer i : _upTo) { + CharSequence _other = TemplateNodeTest.this.other(); + _builder.append(_other); + _builder.append(" "); + _builder.append(i); + _builder.newLineIfNotEmpty(); + String _multiLineString = TemplateNodeTest.this.multiLineString(); + _builder.append(_multiLineString); + _builder.append(" "); + String _multiLineString_1 = TemplateNodeTest.this.multiLineString(); + _builder.append(_multiLineString_1); + _builder.newLineIfNotEmpty(); + } + } + } + } + } + }; + this.assertEquals(_client); + } + + private CharSequence other() { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("foo "); + _builder.append(("dfdf" + Integer.valueOf(23))); + _builder.append(" bar"); + _builder.newLineIfNotEmpty(); + return _builder; + } + + private String multiLineString() { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("test "); + _builder.newLine(); + _builder.append("bar"); + _builder.newLine(); + _builder.append("\t"); + CharSequence _other = this.other(); + _builder.append(_other, "\t"); + _builder.newLineIfNotEmpty(); + return _builder.toString(); + } + + public void assertEquals(final StringConcatenationClient c) { + final GeneratorNodeExtensions ext = new GeneratorNodeExtensions(" "); + StringBuilder _stringBuilder = new StringBuilder(); + final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); + final CompositeNode root = new CompositeNode(); + ext.appendTemplate(root, c); + processor.process(root); + final StringConcatenation expected = new StringConcatenation(); + expected.append(c); + Assert.assertEquals(expected.toString(), processor.getContents().toString()); + } +} diff --git a/org.eclipse.xtext/META-INF/MANIFEST.MF b/org.eclipse.xtext/META-INF/MANIFEST.MF index 5599b849d..484f7a4b7 100644 --- a/org.eclipse.xtext/META-INF/MANIFEST.MF +++ b/org.eclipse.xtext/META-INF/MANIFEST.MF @@ -34,6 +34,7 @@ Export-Package: org.eclipse.xtext, org.eclipse.xtext.generator, org.eclipse.xtext.generator.trace;x-friends:="org.eclipse.xtext.xbase.ui,org.eclipse.xtend.ide", org.eclipse.xtext.generator.trace.internal;x-friends:="org.eclipse.xtext.ui,org.eclipse.xtext.xbase.ui", + org.eclipse.xtext.generator.trace.node, org.eclipse.xtext.grammaranalysis;x-internal:=true, org.eclipse.xtext.grammaranalysis.impl;x-friends:="org.eclipse.xtext.junit4,org.eclipse.xtext.xtext.generator", org.eclipse.xtext.impl, diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeNode.xtend new file mode 100644 index 000000000..553972636 --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeNode.xtend @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import java.util.List +import org.eclipse.xtend.lib.annotations.Accessors + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Accessors class CompositeNode implements IGeneratorNode { + + val List children = newArrayList + +} \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend new file mode 100644 index 000000000..dfcd4326d --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import org.eclipse.xtend.lib.annotations.Data +import org.eclipse.xtend2.lib.StringConcatenationClient +import org.eclipse.xtext.generator.trace.ILocationData + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Data class GeneratorNodeExtensions { + + def CompositeNode startTrace(ILocationData data) { + val result = new TraceNode(data) + return result + } + + def CompositeNode trace(CompositeNode parent, ILocationData data) { + val result = new TraceNode(data) + parent.children += result + return result + } + + def CompositeNode indent(CompositeNode parent) { + val result = new IndentNode + parent.children += result + return result + } + + def CompositeNode appendNewLine(CompositeNode parent) { + parent.children += new NewLineNode + return parent + } + + def CompositeNode append(CompositeNode parent, String text) { + parent.children += new TextNode(text) + return parent + } + + def CompositeNode append(CompositeNode parent, CharSequence text) { + parent.children += new TextNode(text) + return parent + } + + String indentationString + + def IGeneratorNode appendTemplate(CompositeNode parent, StringConcatenationClient contents) { + val proc = new TemplateNode(indentationString, contents, this) + parent.children += proc + return parent + } +} \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend new file mode 100644 index 000000000..50e977d06 --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtend.lib.annotations.Delegate +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor +import org.eclipse.xtext.generator.trace.AbstractStatefulTraceRegion +import org.eclipse.xtext.generator.trace.AbstractTraceRegion +import org.eclipse.xtext.generator.trace.ILocationData +import org.eclipse.xtext.util.ITextRegionWithLineInformation +import org.eclipse.xtext.util.TextRegionWithLineInformation + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@FinalFieldsConstructor class GeneratorNodeProcessor { + + @Accessors(PUBLIC_GETTER) val StringBuilder contents + val String indentationString + val String newLineString + + int currentIndentLevel = 0 + int currentLine = 0 + @Accessors(PUBLIC_GETTER) AbstractTraceRegion currentRegion = null + + def dispatch void process(IGeneratorNode node) { + throw new IllegalArgumentException("No processing for " + node) + } + + def dispatch void process(IndentNode node) { + try { + this.currentIndentLevel++ + this.contents.append(indentationString) + processChildren(node); + } finally { + this.currentIndentLevel-- + } + } + + def dispatch void process(NewLineNode node) { + currentLine++ + contents.append(newLineString) + for (i : 0 ..< currentIndentLevel) { + contents.append(indentationString) + } + } + + def dispatch void process(TextNode node) { + contents.append(node.text) + } + + def dispatch void process(CompositeNode node) { + processChildren(node) + } + + def dispatch void process(TraceNode node) { + val beforeRegion = currentRegion + val newRegion = new CompletableTraceRegion(false, node.sourceLocation, beforeRegion) + val offset = contents.length + val startLine = currentLine; + try { + currentRegion = newRegion + processChildren(node); + } finally { + if (beforeRegion !== null) + currentRegion = beforeRegion + newRegion.complete(offset, contents.length - offset, startLine, currentLine) + } + } + + protected def void processChildren(CompositeNode node) { + for (child : node.children) { + process(child) + } + } + + /** + * Used to avoid multi-pass processing, when constructing a trace region tree. + * + * @author Sven Efftinge - Initial contribution and API + */ + static class CompletableTraceRegion extends AbstractStatefulTraceRegion { + + static class CompletableTextRegion implements ITextRegionWithLineInformation { + ITextRegionWithLineInformation delegate + + @Delegate def ITextRegionWithLineInformation getDelegate() { + if (delegate === null) { + throw new IllegalStateException("region not completed") + } + return delegate + } + } + + CompletableTextRegion region + + new(boolean useForDebugging, ILocationData associatedLocation, AbstractTraceRegion parent) { + this(new CompletableTextRegion(), useForDebugging, associatedLocation, parent) + } + + protected new(CompletableTextRegion region, boolean useForDebugging, ILocationData associatedLocation, + AbstractTraceRegion parent) { + super(region, useForDebugging, associatedLocation, parent) + this.region = region + } + + def void complete(int offset, int length, int startLine, int endLine) { + this.region.delegate = new TextRegionWithLineInformation(offset, length, startLine, endLine) + } + + override protected isConsistentWithParent() { + return true + } + + } +} diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IGeneratorNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IGeneratorNode.xtend new file mode 100644 index 000000000..c6cbbb079 --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IGeneratorNode.xtend @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +/** + * + * A node in the code generator graph + * + * @author Sven Efftinge - Initial contribution and API + */ +interface IGeneratorNode { + +} \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend new file mode 100644 index 000000000..c3c5e15cd --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import org.eclipse.xtend.lib.annotations.Data + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Data class IndentNode extends CompositeNode { + +} \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/NewLineNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/NewLineNode.xtend new file mode 100644 index 000000000..f731f15bf --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/NewLineNode.xtend @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +/** + * @author Sven Efftinge - Initial contribution and API + */ +class NewLineNode implements IGeneratorNode { + +} \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend new file mode 100644 index 000000000..6525a5980 --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import org.eclipse.xtend2.lib.StringConcatenationClient +import org.eclipse.xtend2.lib.StringConcatenationClient.TargetStringConcatenation +import com.google.common.base.Splitter +import java.util.regex.Pattern + +/** + * @author Sven Efftinge - Initial contribution and API + */ +class TemplateNode extends CompositeNode implements TargetStringConcatenation { + + val String indentationString + val GeneratorNodeExtensions nodeFactory + + new(String indentationString, StringConcatenationClient contents, GeneratorNodeExtensions nodeFactory) { + this.indentationString = indentationString + this.nodeFactory = nodeFactory + StringConcatenationClient.appendTo(contents, this) + } + + CompositeNode currentParent = this + boolean isEmptyLine = true; + + override append(Object object, String indentation) { + val idx = indentation.indexOf(indentationString) + if (idx === 0) { + val before = currentParent + try { + currentParent = new IndentNode + before.children += currentParent + append(object, indentation.substring(indentationString.length)) + } finally { + currentParent = before + } + } + // TODO check indentation string + append(object) + } + + val splitter = Splitter.on(Pattern.compile("\\R")) + + override append(Object object) { + switch object { + StringConcatenationClient: + nodeFactory.appendTemplate(currentParent, object) + IGeneratorNode: { + isEmptyLine = false + currentParent.children += object + } + default: { + val str = object.toString + val iter = splitter.split(str).iterator + while (iter.hasNext) { + val segment = iter.next + if (!segment.isEmpty) + isEmptyLine = false + nodeFactory.append(currentParent, segment) + if (iter.hasNext) { + newLine + } + } + } + } + } + + override appendImmediate(Object object, String indentation) { + for (var i = currentParent.children.size; i >= 0; i--) { + val node = currentParent.children.get(i) + if (node instanceof TextNode) { + if (node.text.toString.trim.length === 0) { + currentParent.children.remove(i) + } + } + } + append(object, indentation) + } + + override newLine() { + currentParent.children += new NewLineNode + isEmptyLine = true + } + + override newLineIfNotEmpty() { + if (!isEmptyLine) + newLine + } + + // + override charAt(int index) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override length() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override subSequence(int start, int end) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + +} diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TextNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TextNode.xtend new file mode 100644 index 000000000..f15f04e27 --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TextNode.xtend @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import org.eclipse.xtend.lib.annotations.Data + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Data class TextNode implements IGeneratorNode { + CharSequence text +} \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend new file mode 100644 index 000000000..ca7d5750f --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import java.util.List +import org.eclipse.xtend.lib.annotations.Data +import org.eclipse.xtext.generator.trace.ILocationData + +/** + * @author Sven Efftinge - initial contribution and API + */ +@Data class TraceNode extends CompositeNode { + + final ILocationData sourceLocation + final List children = newArrayList + +} \ No newline at end of file diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeNode.java new file mode 100644 index 000000000..760e3d078 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeNode.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import java.util.List; +import org.eclipse.xtend.lib.annotations.Accessors; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.Pure; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Accessors +@SuppressWarnings("all") +public class CompositeNode implements IGeneratorNode { + private final List children = CollectionLiterals.newArrayList(); + + @Pure + public List getChildren() { + return this.children; + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java new file mode 100644 index 000000000..477a0be67 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import java.util.List; +import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.generator.trace.ILocationData; +import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.generator.trace.node.IndentNode; +import org.eclipse.xtext.generator.trace.node.NewLineNode; +import org.eclipse.xtext.generator.trace.node.TemplateNode; +import org.eclipse.xtext.generator.trace.node.TextNode; +import org.eclipse.xtext.generator.trace.node.TraceNode; +import org.eclipse.xtext.xbase.lib.Pure; +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Data +@SuppressWarnings("all") +public class GeneratorNodeExtensions { + public CompositeNode startTrace(final ILocationData data) { + final TraceNode result = new TraceNode(data); + return result; + } + + public CompositeNode trace(final CompositeNode parent, final ILocationData data) { + final TraceNode result = new TraceNode(data); + List _children = parent.getChildren(); + _children.add(result); + return result; + } + + public CompositeNode indent(final CompositeNode parent) { + final IndentNode result = new IndentNode(); + List _children = parent.getChildren(); + _children.add(result); + return result; + } + + public CompositeNode appendNewLine(final CompositeNode parent) { + List _children = parent.getChildren(); + NewLineNode _newLineNode = new NewLineNode(); + _children.add(_newLineNode); + return parent; + } + + public CompositeNode append(final CompositeNode parent, final String text) { + List _children = parent.getChildren(); + TextNode _textNode = new TextNode(text); + _children.add(_textNode); + return parent; + } + + public CompositeNode append(final CompositeNode parent, final CharSequence text) { + List _children = parent.getChildren(); + TextNode _textNode = new TextNode(text); + _children.add(_textNode); + return parent; + } + + private final String indentationString; + + public IGeneratorNode appendTemplate(final CompositeNode parent, final StringConcatenationClient contents) { + final TemplateNode proc = new TemplateNode(this.indentationString, contents, this); + List _children = parent.getChildren(); + _children.add(proc); + return parent; + } + + public GeneratorNodeExtensions(final String indentationString) { + super(); + this.indentationString = indentationString; + } + + @Override + @Pure + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.indentationString== null) ? 0 : this.indentationString.hashCode()); + return result; + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + GeneratorNodeExtensions other = (GeneratorNodeExtensions) obj; + if (this.indentationString == null) { + if (other.indentationString != null) + return false; + } else if (!this.indentationString.equals(other.indentationString)) + return false; + return true; + } + + @Override + @Pure + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("indentationString", this.indentationString); + return b.toString(); + } + + @Pure + public String getIndentationString() { + return this.indentationString; + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java new file mode 100644 index 000000000..d28ebf044 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import java.util.Arrays; +import java.util.List; +import org.eclipse.xtend.lib.annotations.AccessorType; +import org.eclipse.xtend.lib.annotations.Accessors; +import org.eclipse.xtend.lib.annotations.Delegate; +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor; +import org.eclipse.xtext.generator.trace.AbstractStatefulTraceRegion; +import org.eclipse.xtext.generator.trace.AbstractTraceRegion; +import org.eclipse.xtext.generator.trace.ILocationData; +import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.generator.trace.node.IndentNode; +import org.eclipse.xtext.generator.trace.node.NewLineNode; +import org.eclipse.xtext.generator.trace.node.TextNode; +import org.eclipse.xtext.generator.trace.node.TraceNode; +import org.eclipse.xtext.util.ITextRegion; +import org.eclipse.xtext.util.ITextRegionWithLineInformation; +import org.eclipse.xtext.util.TextRegionWithLineInformation; +import org.eclipse.xtext.xbase.lib.ExclusiveRange; +import org.eclipse.xtext.xbase.lib.Pure; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@FinalFieldsConstructor +@SuppressWarnings("all") +public class GeneratorNodeProcessor { + /** + * Used to avoid multi-pass processing, when constructing a trace region tree. + * + * @author Sven Efftinge - Initial contribution and API + */ + public static class CompletableTraceRegion extends AbstractStatefulTraceRegion { + public static class CompletableTextRegion implements ITextRegionWithLineInformation { + private ITextRegionWithLineInformation delegate; + + @Delegate + public ITextRegionWithLineInformation getDelegate() { + if ((this.delegate == null)) { + throw new IllegalStateException("region not completed"); + } + return this.delegate; + } + + public int getEndLineNumber() { + return this.getDelegate().getEndLineNumber(); + } + + public int getLineNumber() { + return this.getDelegate().getLineNumber(); + } + + public ITextRegionWithLineInformation merge(final ITextRegionWithLineInformation other) { + return this.getDelegate().merge(other); + } + + public boolean contains(final ITextRegion other) { + return this.getDelegate().contains(other); + } + + public boolean contains(final int offset) { + return this.getDelegate().contains(offset); + } + + public int getLength() { + return this.getDelegate().getLength(); + } + + public int getOffset() { + return this.getDelegate().getOffset(); + } + + public ITextRegion merge(final ITextRegion region) { + return this.getDelegate().merge(region); + } + } + + private GeneratorNodeProcessor.CompletableTraceRegion.CompletableTextRegion region; + + public CompletableTraceRegion(final boolean useForDebugging, final ILocationData associatedLocation, final AbstractTraceRegion parent) { + this(new GeneratorNodeProcessor.CompletableTraceRegion.CompletableTextRegion(), useForDebugging, associatedLocation, parent); + } + + protected CompletableTraceRegion(final GeneratorNodeProcessor.CompletableTraceRegion.CompletableTextRegion region, final boolean useForDebugging, final ILocationData associatedLocation, final AbstractTraceRegion parent) { + super(region, useForDebugging, associatedLocation, parent); + this.region = region; + } + + public void complete(final int offset, final int length, final int startLine, final int endLine) { + TextRegionWithLineInformation _textRegionWithLineInformation = new TextRegionWithLineInformation(offset, length, startLine, endLine); + this.region.delegate = _textRegionWithLineInformation; + } + + @Override + protected boolean isConsistentWithParent() { + return true; + } + } + + @Accessors(AccessorType.PUBLIC_GETTER) + private final StringBuilder contents; + + private final String indentationString; + + private final String newLineString; + + private int currentIndentLevel = 0; + + private int currentLine = 0; + + @Accessors(AccessorType.PUBLIC_GETTER) + private AbstractTraceRegion currentRegion = null; + + protected void _process(final IGeneratorNode node) { + throw new IllegalArgumentException(("No processing for " + node)); + } + + protected void _process(final IndentNode node) { + try { + this.currentIndentLevel++; + this.contents.append(this.indentationString); + this.processChildren(node); + } finally { + this.currentIndentLevel--; + } + } + + protected void _process(final NewLineNode node) { + this.currentLine++; + this.contents.append(this.newLineString); + ExclusiveRange _doubleDotLessThan = new ExclusiveRange(0, this.currentIndentLevel, true); + for (final Integer i : _doubleDotLessThan) { + this.contents.append(this.indentationString); + } + } + + protected void _process(final TextNode node) { + this.contents.append(node.getText()); + } + + protected void _process(final CompositeNode node) { + this.processChildren(node); + } + + protected void _process(final TraceNode node) { + final AbstractTraceRegion beforeRegion = this.currentRegion; + ILocationData _sourceLocation = node.getSourceLocation(); + final GeneratorNodeProcessor.CompletableTraceRegion newRegion = new GeneratorNodeProcessor.CompletableTraceRegion(false, _sourceLocation, beforeRegion); + final int offset = this.contents.length(); + final int startLine = this.currentLine; + try { + this.currentRegion = newRegion; + this.processChildren(node); + } finally { + if ((beforeRegion != null)) { + this.currentRegion = beforeRegion; + } + int _length = this.contents.length(); + int _minus = (_length - offset); + newRegion.complete(offset, _minus, startLine, this.currentLine); + } + } + + protected void processChildren(final CompositeNode node) { + List _children = node.getChildren(); + for (final IGeneratorNode child : _children) { + this.process(child); + } + } + + public void process(final IGeneratorNode node) { + if (node instanceof IndentNode) { + _process((IndentNode)node); + return; + } else if (node instanceof TraceNode) { + _process((TraceNode)node); + return; + } else if (node instanceof CompositeNode) { + _process((CompositeNode)node); + return; + } else if (node instanceof NewLineNode) { + _process((NewLineNode)node); + return; + } else if (node instanceof TextNode) { + _process((TextNode)node); + return; + } else if (node != null) { + _process(node); + return; + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(node).toString()); + } + } + + public GeneratorNodeProcessor(final StringBuilder contents, final String indentationString, final String newLineString) { + super(); + this.contents = contents; + this.indentationString = indentationString; + this.newLineString = newLineString; + } + + @Pure + public StringBuilder getContents() { + return this.contents; + } + + @Pure + public AbstractTraceRegion getCurrentRegion() { + return this.currentRegion; + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IGeneratorNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IGeneratorNode.java new file mode 100644 index 000000000..e256afc33 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IGeneratorNode.java @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +/** + * A node in the code generator graph + * + * @author Sven Efftinge - Initial contribution and API + */ +@SuppressWarnings("all") +public interface IGeneratorNode { +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java new file mode 100644 index 000000000..fed1c4e4b --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.xbase.lib.Pure; +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Data +@SuppressWarnings("all") +public class IndentNode extends CompositeNode { + @Override + @Pure + public int hashCode() { + int result = 1; + return result; + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + return true; + } + + @Override + @Pure + public String toString() { + String result = new ToStringBuilder(this) + .addAllFields() + .toString(); + return result; + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/NewLineNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/NewLineNode.java new file mode 100644 index 000000000..cd10ac188 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/NewLineNode.java @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@SuppressWarnings("all") +public class NewLineNode implements IGeneratorNode { +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java new file mode 100644 index 000000000..60fead73d --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java @@ -0,0 +1,145 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import com.google.common.base.Splitter; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Pattern; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.generator.trace.node.IndentNode; +import org.eclipse.xtext.generator.trace.node.NewLineNode; +import org.eclipse.xtext.generator.trace.node.TextNode; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@SuppressWarnings("all") +public class TemplateNode extends CompositeNode implements StringConcatenationClient.TargetStringConcatenation { + private final String indentationString; + + private final GeneratorNodeExtensions nodeFactory; + + public TemplateNode(final String indentationString, final StringConcatenationClient contents, final GeneratorNodeExtensions nodeFactory) { + this.indentationString = indentationString; + this.nodeFactory = nodeFactory; + StringConcatenationClient.appendTo(contents, this); + } + + private CompositeNode currentParent = this; + + private boolean isEmptyLine = true; + + @Override + public void append(final Object object, final String indentation) { + final int idx = indentation.indexOf(this.indentationString); + if ((idx == 0)) { + final CompositeNode before = this.currentParent; + try { + IndentNode _indentNode = new IndentNode(); + this.currentParent = _indentNode; + List _children = before.getChildren(); + _children.add(this.currentParent); + this.append(object, indentation.substring(this.indentationString.length())); + } finally { + this.currentParent = before; + } + } + this.append(object); + } + + private final Splitter splitter = Splitter.on(Pattern.compile("\\R")); + + @Override + public void append(final Object object) { + boolean _matched = false; + if (object instanceof StringConcatenationClient) { + _matched=true; + this.nodeFactory.appendTemplate(this.currentParent, ((StringConcatenationClient)object)); + } + if (!_matched) { + if (object instanceof IGeneratorNode) { + _matched=true; + this.isEmptyLine = false; + List _children = this.currentParent.getChildren(); + _children.add(((IGeneratorNode)object)); + } + } + if (!_matched) { + { + final String str = object.toString(); + final Iterator iter = this.splitter.split(str).iterator(); + while (iter.hasNext()) { + { + final String segment = iter.next(); + boolean _isEmpty = segment.isEmpty(); + boolean _not = (!_isEmpty); + if (_not) { + this.isEmptyLine = false; + } + this.nodeFactory.append(this.currentParent, segment); + boolean _hasNext = iter.hasNext(); + if (_hasNext) { + this.newLine(); + } + } + } + } + } + } + + @Override + public void appendImmediate(final Object object, final String indentation) { + for (int i = this.currentParent.getChildren().size(); (i >= 0); i--) { + { + final IGeneratorNode node = this.currentParent.getChildren().get(i); + if ((node instanceof TextNode)) { + int _length = ((TextNode)node).getText().toString().trim().length(); + boolean _tripleEquals = (_length == 0); + if (_tripleEquals) { + this.currentParent.getChildren().remove(i); + } + } + } + } + this.append(object, indentation); + } + + @Override + public void newLine() { + List _children = this.currentParent.getChildren(); + NewLineNode _newLineNode = new NewLineNode(); + _children.add(_newLineNode); + this.isEmptyLine = true; + } + + @Override + public void newLineIfNotEmpty() { + if ((!this.isEmptyLine)) { + this.newLine(); + } + } + + @Override + public char charAt(final int index) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public int length() { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public CharSequence subSequence(final int start, final int end) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TextNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TextNode.java new file mode 100644 index 000000000..322dc7643 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TextNode.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.xbase.lib.Pure; +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Data +@SuppressWarnings("all") +public class TextNode implements IGeneratorNode { + private final CharSequence text; + + public TextNode(final CharSequence text) { + super(); + this.text = text; + } + + @Override + @Pure + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.text== null) ? 0 : this.text.hashCode()); + return result; + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TextNode other = (TextNode) obj; + if (this.text == null) { + if (other.text != null) + return false; + } else if (!this.text.equals(other.text)) + return false; + return true; + } + + @Override + @Pure + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("text", this.text); + return b.toString(); + } + + @Pure + public CharSequence getText() { + return this.text; + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java new file mode 100644 index 000000000..ee9377788 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2017 TypeFox (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import java.util.List; +import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtext.generator.trace.ILocationData; +import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.Pure; +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +/** + * @author Sven Efftinge - initial contribution and API + */ +@Data +@SuppressWarnings("all") +public class TraceNode extends CompositeNode { + private final ILocationData sourceLocation; + + private final List children = CollectionLiterals.newArrayList(); + + public TraceNode(final ILocationData sourceLocation) { + super(); + this.sourceLocation = sourceLocation; + } + + @Override + @Pure + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.sourceLocation== null) ? 0 : this.sourceLocation.hashCode()); + result = prime * result + ((this.children== null) ? 0 : this.children.hashCode()); + return result; + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TraceNode other = (TraceNode) obj; + if (this.sourceLocation == null) { + if (other.sourceLocation != null) + return false; + } else if (!this.sourceLocation.equals(other.sourceLocation)) + return false; + if (this.children == null) { + if (other.children != null) + return false; + } else if (!this.children.equals(other.children)) + return false; + return true; + } + + @Override + @Pure + public String toString() { + String result = new ToStringBuilder(this) + .addAllFields() + .toString(); + return result; + } + + @Pure + public ILocationData getSourceLocation() { + return this.sourceLocation; + } + + @Pure + public List getChildren() { + return this.children; + } +} From 3e96aa39398ef1c5a714c954e83f10b1f77889d0 Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Sun, 26 Feb 2017 14:50:06 +0100 Subject: [PATCH 2/5] [tracing] Improved client API (#287) --- .../trace/node/GeneratorNodeTest.xtend | 4 +- .../trace/node/TemplateNodeTest.xtend | 6 +- .../trace/node/TracingSugarTest.xtend | 135 +++++++ .../trace/node/GeneratorNodeTest.java | 15 +- .../trace/node/TemplateNodeTest.java | 8 +- .../trace/node/TracingSugarTest.java | 337 ++++++++++++++++++ ...ode.xtend => CompositeGeneratorNode.xtend} | 2 +- .../trace/node/GeneratorNodeExtensions.xtend | 31 +- .../trace/node/GeneratorNodeProcessor.xtend | 8 +- .../generator/trace/node/IndentNode.xtend | 2 +- .../generator/trace/node/TemplateNode.xtend | 38 +- .../generator/trace/node/TraceNode.xtend | 4 +- .../xtext/generator/trace/node/Traced.xtend | 64 ++++ .../trace/node/TracingExtensionsForEMF.xtend | 96 +++++ .../generator/trace/node/TracingSugar.xtend | 78 ++++ .../trace/node/WhiteSpaceConfig.xtend | 22 ++ ...eNode.java => CompositeGeneratorNode.java} | 2 +- .../trace/node/GeneratorNodeExtensions.java | 89 ++--- .../trace/node/GeneratorNodeProcessor.java | 10 +- .../generator/trace/node/IndentNode.java | 4 +- .../generator/trace/node/TemplateNode.java | 55 ++- .../xtext/generator/trace/node/TraceNode.java | 20 +- .../xtext/generator/trace/node/Traced.java | 19 + .../generator/trace/node/TracedProcessor.java | 120 +++++++ .../trace/node/TracingExtensionsForEMF.java | 20 ++ .../TracingExtensionsForEMFProcessor.java | 190 ++++++++++ .../generator/trace/node/TracingSugar.java | 169 +++++++++ .../trace/node/WhiteSpaceConfig.java | 22 ++ 28 files changed, 1421 insertions(+), 149 deletions(-) create mode 100644 org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend create mode 100644 org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java rename org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/{CompositeNode.xtend => CompositeGeneratorNode.xtend} (91%) create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/Traced.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend create mode 100644 org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.xtend rename org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/{CompositeNode.java => CompositeGeneratorNode.java} (93%) create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/Traced.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedProcessor.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMFProcessor.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java create mode 100644 org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.java diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend index 65726539c..4c0cf9458 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 TypeFox (http://www.typefox.io) and others. + * Copyright (c) 2017 TypeFox (https://typefox.io) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -18,7 +18,7 @@ import org.junit.Test */ class GeneratorNodeTest { - extension GeneratorNodeExtensions exts = new GeneratorNodeExtensions(" ") + extension GeneratorNodeExtensions exts = new GeneratorNodeExtensions() @Test def void testBasicCreationAndProcessing() { val root = loc(0) diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.xtend index 9c3d3c769..8b544d6ce 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.xtend +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.xtend @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 itemis AG (http://www.itemis.eu) and others. + * Copyright (c) 2017 TypeFox (https://typefox.io) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -52,10 +52,10 @@ class TemplateNodeTest { ''' def void assertEquals(StringConcatenationClient c) { - val ext = new GeneratorNodeExtensions(" ") + val ext = new GeneratorNodeExtensions() val processor = new GeneratorNodeProcessor(new StringBuilder, " ", "\n") - val root = new CompositeNode() + val root = new CompositeGeneratorNode() ext.appendTemplate(root, c); processor.process(root) diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend new file mode 100644 index 000000000..e10a6ea53 --- /dev/null +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox (https://typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import com.google.inject.Inject +import org.eclipse.xtext.generator.InMemoryFileSystemAccess +import org.eclipse.xtext.linking.lazy.lazyLinking.LazyLinkingFactory +import org.eclipse.xtext.linking.lazy.lazyLinking.Model +import org.eclipse.xtext.linking.lazy.lazyLinking.Property +import org.eclipse.xtext.linking.lazy.lazyLinking.Type +import org.eclipse.xtext.linking.lazy.tests.LazyLinkingTestLanguageInjectorProvider +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.XtextRunner +import org.eclipse.xtext.testing.util.ParseHelper +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.Assert +import org.eclipse.xtext.generator.trace.ITraceRegionProvider + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@RunWith(XtextRunner) +@InjectWith(LazyLinkingTestLanguageInjectorProvider) +class TracingSugarTest { + + @TracingExtensionsForEMF(LazyLinkingFactory) + static class MyExtensions { + + /** + * manual implementation for unsupported multi cross reference + */ + def IGeneratorNode _type(Property it, (Type)=>String provider) { + val location = location(eClass.getEStructuralFeature("type"), 0) + val result = location.startTrace + result.append(provider.apply(type.head)) + return result + } + } + + @Inject extension MyExtensions + @Inject ParseHelper parseHelper + + CharSequence generated + + InMemoryFileSystemAccess fsa = new InMemoryFileSystemAccess() { + override generateFile(String fileName, CharSequence contents) { + generated = contents + super.generateFile(fileName, contents) + } + }; + + @Test def void testCodeGeneration() { + val root = parseHelper.parse(''' + type String {} + type Foo { + String name; + } + ''') + fsa.generateTracedFile('foo/bar.txt', root, ''' + «FOR t : root.types» + «t._generateType» + «ENDFOR» + ''') + + // check the generated string is as expected + Assert.assertEquals(''' + «FOR t : root.types» + «t.generateType» + «ENDFOR» + '''.toString, generated.toString) + + val trace = (generated as ITraceRegionProvider).traceRegion + Assert.assertEquals(''' + CompletableTraceRegion [myOffset=0, myLength=55] associations={ + LocationData [TextRegionWithLineInformation [0:41][lineNumber=0, endLineNumber=3]][path=__synthetic0.lazylinkingtestlanguage] + } nestedRegions={ + CompletableTraceRegion [myOffset=0, myLength=17] associations={ + LocationData [TextRegionWithLineInformation [0:14][lineNumber=0, endLineNumber=0]][path=__synthetic0.lazylinkingtestlanguage] + } nestedRegions={ + CompletableTraceRegion [myOffset=6, myLength=6] associations={ + LocationData [TextRegionWithLineInformation [5:6][lineNumber=0, endLineNumber=0]][path=__synthetic0.lazylinkingtestlanguage] + } + } + CompletableTraceRegion [myOffset=17, myLength=38] associations={ + LocationData [TextRegionWithLineInformation [15:26][lineNumber=1, endLineNumber=3]][path=__synthetic0.lazylinkingtestlanguage] + } nestedRegions={ + CompletableTraceRegion [myOffset=23, myLength=3] associations={ + LocationData [TextRegionWithLineInformation [20:3][lineNumber=1, endLineNumber=1]][path=__synthetic0.lazylinkingtestlanguage] + } + CompletableTraceRegion [myOffset=30, myLength=23] associations={ + LocationData [TextRegionWithLineInformation [27:12][lineNumber=2, endLineNumber=2]][path=__synthetic0.lazylinkingtestlanguage] + } nestedRegions={ + CompletableTraceRegion [myOffset=39, myLength=4] associations={ + LocationData [TextRegionWithLineInformation [34:4][lineNumber=2, endLineNumber=2]][path=__synthetic0.lazylinkingtestlanguage] + } + CompletableTraceRegion [myOffset=46, myLength=6] associations={ + LocationData [TextRegionWithLineInformation [27:6][lineNumber=2, endLineNumber=2]][path=__synthetic0.lazylinkingtestlanguage] + } + } + } + }'''.toString, trace.toString) + } + + @Traced def _generateType(Type it) ''' + Class «_name» { + «FOR p : properties» + «p._generateProperty» + «ENDFOR» + } + ''' + + @Traced def _generateProperty(Property it) ''' + Property «_name» : «_type[name]» + ''' + + def generateType(Type it) ''' + Class «name» { + «FOR p : properties» + «p.generateProperty» + «ENDFOR» + } + ''' + + def generateProperty(Property it) ''' + Property «name» : «type.head.name» + ''' + + +} \ No newline at end of file diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java index 2cb2de740..c35db37ae 100644 --- a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017 TypeFox (http://www.typefox.io) and others. + * Copyright (c) 2017 TypeFox (https://typefox.io) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,10 +11,9 @@ import org.eclipse.xtend2.lib.StringConcatenation; import org.eclipse.xtend2.lib.StringConcatenationClient; import org.eclipse.xtext.generator.trace.LocationData; import org.eclipse.xtext.generator.trace.SourceRelativeURI; -import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor; -import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.xbase.lib.ExclusiveRange; import org.eclipse.xtext.xbase.lib.Extension; import org.junit.Assert; @@ -26,12 +25,12 @@ import org.junit.Test; @SuppressWarnings("all") public class GeneratorNodeTest { @Extension - private GeneratorNodeExtensions exts = new GeneratorNodeExtensions(" "); + private GeneratorNodeExtensions exts = new GeneratorNodeExtensions(); @Test public void testBasicCreationAndProcessing() { final LocationData root = this.loc(0); - CompositeNode node = this.exts.appendNewLine(this.exts.append(this.exts.startTrace(root), "notindented")); + CompositeGeneratorNode node = this.exts.appendNewLine(this.exts.append(this.exts.startTrace(root), "notindented")); this.exts.append(this.exts.appendNewLine(this.exts.append(this.exts.trace(this.exts.indent(node), this.loc(1)), "indented1")), "indented2"); this.exts.append(this.exts.appendNewLine(node), "dedented"); StringBuilder _stringBuilder = new StringBuilder(); @@ -72,7 +71,7 @@ public class GeneratorNodeTest { @Test public void testTemplateProcessing() { final LocationData root = this.loc(0); - CompositeNode _startTrace = this.exts.startTrace(root); + CompositeGeneratorNode _startTrace = this.exts.startTrace(root); StringConcatenationClient _client = new StringConcatenationClient() { @Override protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { @@ -81,7 +80,7 @@ public class GeneratorNodeTest { _builder.newLineIfNotEmpty(); } }; - IGeneratorNode node = this.exts.appendTemplate(_startTrace, _client); + CompositeGeneratorNode node = this.exts.appendTemplate(_startTrace, _client); StringBuilder _stringBuilder = new StringBuilder(); final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); processor.process(node); @@ -188,7 +187,7 @@ public class GeneratorNodeTest { ExclusiveRange _doubleDotLessThan = new ExclusiveRange(0, n, true); for(final Integer i : _doubleDotLessThan) { _builder.append("before "); - CompositeNode _append = GeneratorNodeTest.this.exts.append(GeneratorNodeTest.this.exts.startTrace(GeneratorNodeTest.this.loc((10 + (i).intValue()))), "Hello"); + CompositeGeneratorNode _append = GeneratorNodeTest.this.exts.append(GeneratorNodeTest.this.exts.startTrace(GeneratorNodeTest.this.loc((10 + (i).intValue()))), "Hello"); _builder.append(_append); _builder.append(" after"); _builder.newLineIfNotEmpty(); diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java index 0d00ed5eb..c4ec4dd1d 100644 --- a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017 itemis AG (http://www.itemis.eu) and others. + * Copyright (c) 2017 TypeFox (https://typefox.io) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -9,7 +9,7 @@ package org.eclipse.xtext.generator.trace.node; import org.eclipse.xtend2.lib.StringConcatenation; import org.eclipse.xtend2.lib.StringConcatenationClient; -import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor; import org.eclipse.xtext.xbase.lib.IntegerRange; @@ -104,10 +104,10 @@ public class TemplateNodeTest { } public void assertEquals(final StringConcatenationClient c) { - final GeneratorNodeExtensions ext = new GeneratorNodeExtensions(" "); + final GeneratorNodeExtensions ext = new GeneratorNodeExtensions(); StringBuilder _stringBuilder = new StringBuilder(); final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); - final CompositeNode root = new CompositeNode(); + final CompositeGeneratorNode root = new CompositeGeneratorNode(); ext.appendTemplate(root, c); processor.process(root); final StringConcatenation expected = new StringConcatenation(); diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java new file mode 100644 index 000000000..586038155 --- /dev/null +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java @@ -0,0 +1,337 @@ +/** + * Copyright (c) 2017 TypeFox (https://typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import com.google.inject.Inject; +import java.util.function.Function; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.generator.InMemoryFileSystemAccess; +import org.eclipse.xtext.generator.trace.AbstractTraceRegion; +import org.eclipse.xtext.generator.trace.ILocationData; +import org.eclipse.xtext.generator.trace.ITraceRegionProvider; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.generator.trace.node.Traced; +import org.eclipse.xtext.generator.trace.node.TracingExtensionsForEMF; +import org.eclipse.xtext.generator.trace.node.TracingSugar; +import org.eclipse.xtext.linking.lazy.lazyLinking.LazyLinkingFactory; +import org.eclipse.xtext.linking.lazy.lazyLinking.Model; +import org.eclipse.xtext.linking.lazy.lazyLinking.Property; +import org.eclipse.xtext.linking.lazy.lazyLinking.Type; +import org.eclipse.xtext.linking.lazy.lazyLinking.UnresolvedProxyProperty; +import org.eclipse.xtext.linking.lazy.tests.LazyLinkingTestLanguageInjectorProvider; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.XtextRunner; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.xbase.lib.Exceptions; +import org.eclipse.xtext.xbase.lib.Extension; +import org.eclipse.xtext.xbase.lib.Functions.Function1; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@RunWith(XtextRunner.class) +@InjectWith(LazyLinkingTestLanguageInjectorProvider.class) +@SuppressWarnings("all") +public class TracingSugarTest { + @TracingExtensionsForEMF(LazyLinkingFactory.class) + public static class MyExtensions extends TracingSugar { + /** + * manual implementation for unsupported multi cross reference + */ + public IGeneratorNode _type(final Property it, final Function1 provider) { + final ILocationData location = this.location(it, it.eClass().getEStructuralFeature("type"), 0); + final CompositeGeneratorNode result = this.startTrace(location); + this.append(result, provider.apply(IterableExtensions.head(it.getType()))); + return result; + } + + public IGeneratorNode _name(final Property target) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.startTrace(location); + this.append(trace, target.getName()); + return trace; + } + + public IGeneratorNode _extends(final Type target, final Function stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("extends"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.startTrace(location); + this.append(trace, stringProvider.apply(target.getExtends())); + return trace; + } + + public IGeneratorNode _name(final Type target) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.startTrace(location); + this.append(trace, target.getName()); + return trace; + } + + public IGeneratorNode _parentId(final Type target, final Function stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("parentId"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.startTrace(location); + this.append(trace, stringProvider.apply(target.getParentId())); + return trace; + } + + public IGeneratorNode _name(final UnresolvedProxyProperty target) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.startTrace(location); + this.append(trace, target.getName()); + return trace; + } + } + + @Inject + @Extension + private TracingSugarTest.MyExtensions _myExtensions; + + @Inject + private ParseHelper parseHelper; + + private CharSequence generated; + + private InMemoryFileSystemAccess fsa = new InMemoryFileSystemAccess() { + @Override + public void generateFile(final String fileName, final CharSequence contents) { + TracingSugarTest.this.generated = contents; + super.generateFile(fileName, contents); + } + }; + + @Test + public void testCodeGeneration() { + try { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("type String {}"); + _builder.newLine(); + _builder.append("type Foo {"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("String name;"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + final Model root = this.parseHelper.parse(_builder); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + { + EList _types = root.getTypes(); + for(final Type t : _types) { + IGeneratorNode __generateType = TracingSugarTest.this._generateType(t); + _builder.append(__generateType); + _builder.newLineIfNotEmpty(); + } + } + } + }; + this._myExtensions.generateTracedFile(this.fsa, "foo/bar.txt", root, _client); + StringConcatenation _builder_1 = new StringConcatenation(); + { + EList _types = root.getTypes(); + for(final Type t : _types) { + CharSequence _generateType = this.generateType(t); + _builder_1.append(_generateType); + _builder_1.newLineIfNotEmpty(); + } + } + Assert.assertEquals(_builder_1.toString(), this.generated.toString()); + final AbstractTraceRegion trace = ((ITraceRegionProvider) this.generated).getTraceRegion(); + StringConcatenation _builder_2 = new StringConcatenation(); + _builder_2.append("CompletableTraceRegion [myOffset=0, myLength=55] associations={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("LocationData [TextRegionWithLineInformation [0:41][lineNumber=0, endLineNumber=3]][path=__synthetic0.lazylinkingtestlanguage]"); + _builder_2.newLine(); + _builder_2.append("} nestedRegions={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("CompletableTraceRegion [myOffset=0, myLength=17] associations={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("LocationData [TextRegionWithLineInformation [0:14][lineNumber=0, endLineNumber=0]][path=__synthetic0.lazylinkingtestlanguage]"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("} nestedRegions={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("CompletableTraceRegion [myOffset=6, myLength=6] associations={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("LocationData [TextRegionWithLineInformation [5:6][lineNumber=0, endLineNumber=0]][path=__synthetic0.lazylinkingtestlanguage]"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("}"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("}"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("CompletableTraceRegion [myOffset=17, myLength=38] associations={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("LocationData [TextRegionWithLineInformation [15:26][lineNumber=1, endLineNumber=3]][path=__synthetic0.lazylinkingtestlanguage]"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("} nestedRegions={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("CompletableTraceRegion [myOffset=23, myLength=3] associations={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("LocationData [TextRegionWithLineInformation [20:3][lineNumber=1, endLineNumber=1]][path=__synthetic0.lazylinkingtestlanguage]"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("}"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("CompletableTraceRegion [myOffset=30, myLength=23] associations={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("LocationData [TextRegionWithLineInformation [27:12][lineNumber=2, endLineNumber=2]][path=__synthetic0.lazylinkingtestlanguage]"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("} nestedRegions={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("CompletableTraceRegion [myOffset=39, myLength=4] associations={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("LocationData [TextRegionWithLineInformation [34:4][lineNumber=2, endLineNumber=2]][path=__synthetic0.lazylinkingtestlanguage]"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("}"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("CompletableTraceRegion [myOffset=46, myLength=6] associations={"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("LocationData [TextRegionWithLineInformation [27:6][lineNumber=2, endLineNumber=2]][path=__synthetic0.lazylinkingtestlanguage]"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("}"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("}"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append("}"); + _builder_2.newLine(); + _builder_2.append("}"); + Assert.assertEquals(_builder_2.toString(), trace.toString()); + } catch (Throwable _e) { + throw Exceptions.sneakyThrow(_e); + } + } + + @Traced + public IGeneratorNode _generateType(final Type it) { + ILocationData _location = this._myExtensions.location(it); + CompositeGeneratorNode _traceNode = this._myExtensions.startTrace(_location); + this._myExtensions.appendTemplate(_traceNode, __generateType(it)); + return _traceNode; + } + + @Traced + public IGeneratorNode _generateProperty(final Property it) { + ILocationData _location = this._myExtensions.location(it); + CompositeGeneratorNode _traceNode = this._myExtensions.startTrace(_location); + this._myExtensions.appendTemplate(_traceNode, __generateProperty(it)); + return _traceNode; + } + + public CharSequence generateType(final Type it) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("Class "); + String _name = it.getName(); + _builder.append(_name); + _builder.append(" {"); + _builder.newLineIfNotEmpty(); + { + EList _properties = it.getProperties(); + for(final Property p : _properties) { + _builder.append("\t"); + CharSequence _generateProperty = this.generateProperty(p); + _builder.append(_generateProperty, "\t"); + _builder.newLineIfNotEmpty(); + } + } + _builder.append("}"); + _builder.newLine(); + return _builder; + } + + public CharSequence generateProperty(final Property it) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("Property "); + String _name = it.getName(); + _builder.append(_name); + _builder.append(" : "); + String _name_1 = IterableExtensions.head(it.getType()).getName(); + _builder.append(_name_1); + _builder.newLineIfNotEmpty(); + return _builder; + } + + public StringConcatenationClient __generateType(final Type it) { + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("Class "); + IGeneratorNode __name = TracingSugarTest.this._myExtensions._name(it); + _builder.append(__name); + _builder.append(" {"); + _builder.newLineIfNotEmpty(); + { + EList _properties = it.getProperties(); + for(final Property p : _properties) { + _builder.append("\t"); + IGeneratorNode __generateProperty = TracingSugarTest.this._generateProperty(p); + _builder.append(__generateProperty, "\t"); + _builder.newLineIfNotEmpty(); + } + } + _builder.append("}"); + _builder.newLine(); + } + }; + return _client; + } + + public StringConcatenationClient __generateProperty(final Property it) { + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("Property "); + IGeneratorNode __name = TracingSugarTest.this._myExtensions._name(it); + _builder.append(__name); + _builder.append(" : "); + final Function1 _function = (Type it_1) -> { + return it_1.getName(); + }; + IGeneratorNode __type = TracingSugarTest.this._myExtensions._type(it, _function); + _builder.append(__type); + _builder.newLineIfNotEmpty(); + } + }; + return _client; + } +} diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.xtend similarity index 91% rename from org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeNode.xtend rename to org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.xtend index 553972636..40e990d94 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.xtend @@ -13,7 +13,7 @@ import org.eclipse.xtend.lib.annotations.Accessors /** * @author Sven Efftinge - Initial contribution and API */ -@Accessors class CompositeNode implements IGeneratorNode { +@Accessors class CompositeGeneratorNode implements IGeneratorNode { val List children = newArrayList diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend index dfcd4326d..378ff8c3f 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend @@ -7,51 +7,48 @@ *******************************************************************************/ package org.eclipse.xtext.generator.trace.node -import org.eclipse.xtend.lib.annotations.Data +import com.google.inject.Inject import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtext.generator.trace.ILocationData /** * @author Sven Efftinge - Initial contribution and API */ -@Data class GeneratorNodeExtensions { +class GeneratorNodeExtensions { - def CompositeNode startTrace(ILocationData data) { + @Inject WhiteSpaceConfig wsConfig = new WhiteSpaceConfig + + def CompositeGeneratorNode startTrace(ILocationData data) { val result = new TraceNode(data) return result } - def CompositeNode trace(CompositeNode parent, ILocationData data) { + def CompositeGeneratorNode trace(CompositeGeneratorNode parent, ILocationData data) { val result = new TraceNode(data) parent.children += result return result } - def CompositeNode indent(CompositeNode parent) { + def CompositeGeneratorNode indent(CompositeGeneratorNode parent) { val result = new IndentNode parent.children += result return result } - def CompositeNode appendNewLine(CompositeNode parent) { + def CompositeGeneratorNode appendNewLine(CompositeGeneratorNode parent) { parent.children += new NewLineNode return parent } - def CompositeNode append(CompositeNode parent, String text) { - parent.children += new TextNode(text) + def CompositeGeneratorNode append(CompositeGeneratorNode parent, Object object) { + if (object !== null) { + parent.children += new TextNode(object.toString) + } return parent } - def CompositeNode append(CompositeNode parent, CharSequence text) { - parent.children += new TextNode(text) - return parent - } - - String indentationString - - def IGeneratorNode appendTemplate(CompositeNode parent, StringConcatenationClient contents) { - val proc = new TemplateNode(indentationString, contents, this) + def CompositeGeneratorNode appendTemplate(CompositeGeneratorNode parent, StringConcatenationClient contents) { + val proc = new TemplateNode(wsConfig.indentationString, contents, this) parent.children += proc return parent } diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend index 50e977d06..d16080e3e 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend @@ -20,7 +20,7 @@ import org.eclipse.xtext.util.TextRegionWithLineInformation * @author Sven Efftinge - Initial contribution and API */ @FinalFieldsConstructor class GeneratorNodeProcessor { - + @Accessors(PUBLIC_GETTER) val StringBuilder contents val String indentationString val String newLineString @@ -28,7 +28,7 @@ import org.eclipse.xtext.util.TextRegionWithLineInformation int currentIndentLevel = 0 int currentLine = 0 @Accessors(PUBLIC_GETTER) AbstractTraceRegion currentRegion = null - + def dispatch void process(IGeneratorNode node) { throw new IllegalArgumentException("No processing for " + node) } @@ -55,7 +55,7 @@ import org.eclipse.xtext.util.TextRegionWithLineInformation contents.append(node.text) } - def dispatch void process(CompositeNode node) { + def dispatch void process(CompositeGeneratorNode node) { processChildren(node) } @@ -74,7 +74,7 @@ import org.eclipse.xtext.util.TextRegionWithLineInformation } } - protected def void processChildren(CompositeNode node) { + protected def void processChildren(CompositeGeneratorNode node) { for (child : node.children) { process(child) } diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend index c3c5e15cd..8657cbece 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend @@ -12,6 +12,6 @@ import org.eclipse.xtend.lib.annotations.Data /** * @author Sven Efftinge - Initial contribution and API */ -@Data class IndentNode extends CompositeNode { +@Data class IndentNode extends CompositeGeneratorNode { } \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend index 6525a5980..64fa0c6dc 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend @@ -7,15 +7,16 @@ *******************************************************************************/ package org.eclipse.xtext.generator.trace.node +import com.google.common.base.Splitter +import com.google.common.collect.Iterables +import java.util.regex.Pattern import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtend2.lib.StringConcatenationClient.TargetStringConcatenation -import com.google.common.base.Splitter -import java.util.regex.Pattern /** * @author Sven Efftinge - Initial contribution and API */ -class TemplateNode extends CompositeNode implements TargetStringConcatenation { +class TemplateNode extends CompositeGeneratorNode implements TargetStringConcatenation { val String indentationString val GeneratorNodeExtensions nodeFactory @@ -26,7 +27,7 @@ class TemplateNode extends CompositeNode implements TargetStringConcatenation { StringConcatenationClient.appendTo(contents, this) } - CompositeNode currentParent = this + CompositeGeneratorNode currentParent = this boolean isEmptyLine = true; override append(Object object, String indentation) { @@ -41,7 +42,7 @@ class TemplateNode extends CompositeNode implements TargetStringConcatenation { currentParent = before } } - // TODO check indentation string + // TODO check indentation string for consistency append(object) } @@ -52,7 +53,7 @@ class TemplateNode extends CompositeNode implements TargetStringConcatenation { StringConcatenationClient: nodeFactory.appendTemplate(currentParent, object) IGeneratorNode: { - isEmptyLine = false + isEmptyLine = isEmptyLine(object) currentParent.children += object } default: { @@ -70,6 +71,31 @@ class TemplateNode extends CompositeNode implements TargetStringConcatenation { } } } + + private def boolean isEmptyLine(IGeneratorNode n) { + for (leaf : n.leafsBackwards) { + if (leaf instanceof TextNode) { + if (!leaf.text.toString().trim().empty) { + return false + } + } + if (leaf instanceof NewLineNode) { + return true; + } + } + return false; + } + + private def Iterable leafsBackwards(IGeneratorNode it) { + switch it { + CompositeGeneratorNode : { + children.reverseView.map[leafsBackwards].reduce[p1, p2| Iterables.concat(p1, p2)] + } + default : { + #[it] + } + } + } override appendImmediate(Object object, String indentation) { for (var i = currentParent.children.size; i >= 0; i--) { diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend index ca7d5750f..ddde8254f 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend @@ -7,16 +7,14 @@ *******************************************************************************/ package org.eclipse.xtext.generator.trace.node -import java.util.List import org.eclipse.xtend.lib.annotations.Data import org.eclipse.xtext.generator.trace.ILocationData /** * @author Sven Efftinge - initial contribution and API */ -@Data class TraceNode extends CompositeNode { +@Data class TraceNode extends CompositeGeneratorNode { final ILocationData sourceLocation - final List children = newArrayList } \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/Traced.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/Traced.xtend new file mode 100644 index 000000000..d9fff2135 --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/Traced.xtend @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtend.lib.macro.AbstractMethodProcessor +import org.eclipse.xtend.lib.macro.Active +import org.eclipse.xtend.lib.macro.TransformationContext +import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration +import org.eclipse.xtend.lib.macro.declaration.MutableMethodDeclaration +import org.eclipse.xtend2.lib.StringConcatenationClient +import org.eclipse.xtext.generator.trace.ILocationData + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Active(TracedProcessor) +annotation Traced { + String tracingSugarFieldName = '_traceExtensions' +} + +class TracedProcessor extends AbstractMethodProcessor { + + override doTransform(MutableMethodDeclaration annotatedMethod, extension TransformationContext context) { + val traceSugar = TracingSugar.newTypeReference + val templateClient = StringConcatenationClient.newTypeReference + val nodeType = IGeneratorNode.newTypeReference + val eobjectType = EObject.newTypeReference + + val clazz = annotatedMethod.declaringType as MutableClassDeclaration + val field = clazz.declaredFields.findFirst[ + traceSugar.isAssignableFrom(type) + ] + if (field === null) { + annotatedMethod.addError('''@«Traced.simpleName» methods can only declared in a class with a field of type «TracingSugar»''') + return; + } + val traceParam = annotatedMethod.parameters.findFirst[eobjectType.isAssignableFrom(type)] + if (traceParam === null) { + annotatedMethod.addError('''@«Traced.simpleName» methods need at least one parameter of type «EObject».''') + return; + } + clazz.addMethod('_'+annotatedMethod.simpleName) [ + for (p : annotatedMethod.parameters) { + addParameter(p.simpleName, p.type) + } + returnType = templateClient + body = annotatedMethod.body + ] + annotatedMethod.returnType = nodeType + annotatedMethod.body = ''' + «ILocationData» _location = this.«field.simpleName».location(«traceParam.simpleName»); + «CompositeGeneratorNode» _traceNode = this.«field.simpleName».startTrace(_location); + this.«field.simpleName».appendTemplate(_traceNode, _«annotatedMethod.simpleName»(«annotatedMethod.parameters.join(',')[simpleName]»)); + return _traceNode; + ''' + } + +} \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.xtend new file mode 100644 index 000000000..e23f0686c --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.xtend @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +import java.util.function.Function +import org.eclipse.emf.ecore.EFactory +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EStructuralFeature +import org.eclipse.xtend.lib.macro.AbstractClassProcessor +import org.eclipse.xtend.lib.macro.Active +import org.eclipse.xtend.lib.macro.TransformationContext +import org.eclipse.xtend.lib.macro.declaration.InterfaceDeclaration +import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration +import org.eclipse.xtend.lib.macro.declaration.ResolvedMethod +import org.eclipse.xtext.generator.trace.ILocationData + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Active(TracingExtensionsForEMFProcessor) +annotation TracingExtensionsForEMF { + Class[] value +} + +class TracingExtensionsForEMFProcessor extends AbstractClassProcessor { + + override doTransform(MutableClassDeclaration annotatedClass, extension TransformationContext context) { + val eobjectType = EObject.newTypeReference() + annotatedClass.extendedClass = TracingSugar.newTypeReference() + val annotationType = findTypeGlobally(TracingExtensionsForEMF) + val factories = annotatedClass.findAnnotation(annotationType)?.getClassArrayValue("value") + if (factories === null) { + return; + } + for (f : factories.map[type].filter(InterfaceDeclaration)) { + for (t: f.declaredMethods.filter[simpleName.startsWith('create') && parameters.empty].map[returnType]) { + for (getter : t.allResolvedMethods.filter[ isGetter]) { + val rt = getter.resolvedReturnType + if (allowedLowerCaseTypeNames.contains(rt.type.simpleName.toLowerCase)) { + annotatedClass.addMethod(getter.tracerName) [ + returnType = IGeneratorNode.newTypeReference() + addParameter('target', t) + body = ''' + «EStructuralFeature» feature = target.eClass().getEStructuralFeature("«getter.featureName»"); + «ILocationData» location = this.location(target, feature, -1); + «CompositeGeneratorNode» trace = this.startTrace(location); + this.append(trace, target.«getter.declaration.simpleName»()); + return trace; + ''' + ] + } else if (eobjectType.isAssignableFrom(rt)) { + annotatedClass.addMethod(getter.tracerName) [ + returnType = IGeneratorNode.newTypeReference + addParameter('target', t) + val stringProvider = Function.newTypeReference(rt, string) + addParameter('stringProvider', stringProvider) + body = ''' + «EStructuralFeature» feature = target.eClass().getEStructuralFeature("«getter.featureName»"); + «ILocationData» location = this.location(target, feature, -1); + «CompositeGeneratorNode» trace = this.startTrace(location); + this.append(trace, stringProvider.apply(target.«getter.declaration.simpleName»())); + return trace; + ''' + ] + } + } + } + } + } + + def String tracerName(ResolvedMethod m) { + '_'+m.featureName + } + + def String featureName(ResolvedMethod m) { + val n = m.declaration.simpleName + val skip = if (n.startsWith('get')) 3 else 2 + m.declaration.simpleName.substring(skip).toFirstLower + } + + static val allowedLowerCaseTypeNames = #{'string','boolean','int','long','integer'} + + def boolean isGetter(ResolvedMethod it) { + if (!declaration.parameters.empty) + return false + if (declaration.static) + return false + val n = it.declaration.simpleName + return n.startsWith('get') || n.startsWith('is') + } +} \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend new file mode 100644 index 000000000..fbc2a6636 --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend @@ -0,0 +1,78 @@ +package org.eclipse.xtext.generator.trace.node + +import com.google.inject.Inject +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtend.lib.annotations.Data +import org.eclipse.xtend.lib.annotations.Delegate +import org.eclipse.xtend2.lib.StringConcatenationClient +import org.eclipse.xtext.generator.IFileSystemAccess2 +import org.eclipse.xtext.generator.trace.AbstractTraceRegion +import org.eclipse.xtext.generator.trace.ITraceRegionProvider +import org.eclipse.xtext.generator.trace.ITraceURIConverter +import org.eclipse.xtext.generator.trace.LocationData +import org.eclipse.xtext.generator.trace.TraceNotFoundException +import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions +import org.eclipse.xtext.generator.trace.node.IGeneratorNode +import org.eclipse.xtext.resource.ILocationInFileProvider +import org.eclipse.xtext.util.ITextRegionWithLineInformation +import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor +import org.eclipse.xtext.generator.trace.ILocationData +import org.eclipse.emf.ecore.EStructuralFeature + +class TracingSugar extends GeneratorNodeExtensions { + + @Inject protected ILocationInFileProvider locationProvider + @Inject protected ITraceURIConverter traceURIConverter + @Inject protected WhiteSpaceConfig whiteSpaceConfig + + def void generateTracedFile(IFileSystemAccess2 fsa, String path, EObject rootTrace, StringConcatenationClient code) { + val node = trace(rootTrace, code) + val proc = new GeneratorNodeProcessor(new StringBuilder(), whiteSpaceConfig.indentationString, whiteSpaceConfig.lineDelimiter) + proc.process(node); + fsa.generateFile(path, new Result(proc.contents, proc.currentRegion)) + } + + def void generateTracedFile(IFileSystemAccess2 fsa, String path, CompositeGeneratorNode rootNode) { + val proc = new GeneratorNodeProcessor(new StringBuilder(), " ", "\n") + proc.process(rootNode); + fsa.generateFile(path, new Result(proc.contents, proc.currentRegion)) + } + + def IGeneratorNode trace(EObject obj, StringConcatenationClient code) { + val region = locationProvider.getFullTextRegion(obj) + val uri = traceURIConverter.getURIForTrace(obj.eResource) + val location = new LocationData(region as ITextRegionWithLineInformation, uri); + return location.startTrace.appendTemplate(code) + } + + def IGeneratorNode trace(T obj, (T)=>String code) { + val string = code.apply(obj); + val location = location(obj); + return location.startTrace.append(string) + } + + def ILocationData location(EObject obj) { + val region = locationProvider.getFullTextRegion(obj) + val uri = traceURIConverter.getURIForTrace(obj.eResource) + return new LocationData(region as ITextRegionWithLineInformation, uri); + } + + def ILocationData location(EObject obj, EStructuralFeature feature, int idx) { + val region = locationProvider.getFullTextRegion(obj, feature, idx) + val uri = traceURIConverter.getURIForTrace(obj.eResource) + return new LocationData(region as ITextRegionWithLineInformation, uri); + } + + @Data static class Result implements CharSequence, ITraceRegionProvider { + @Delegate CharSequence contents + AbstractTraceRegion traceRegion + + override getTraceRegion() throws TraceNotFoundException { + return traceRegion + } + + override toString() { + contents.toString() + } + } +} diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.xtend new file mode 100644 index 000000000..827289e0e --- /dev/null +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.xtend @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.generator.trace.node + +/** + * @author Sven Efftinge - Initial contribution and API + */ +class WhiteSpaceConfig { + + def String getIndentationString() { + ' ' + } + + def String getLineDelimiter() { + '\n' + } +} \ No newline at end of file diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.java similarity index 93% rename from org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeNode.java rename to org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.java index 760e3d078..a8963f3d5 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.java @@ -18,7 +18,7 @@ import org.eclipse.xtext.xbase.lib.Pure; */ @Accessors @SuppressWarnings("all") -public class CompositeNode implements IGeneratorNode { +public class CompositeGeneratorNode implements IGeneratorNode { private final List children = CollectionLiterals.newArrayList(); @Pure diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java index 477a0be67..90e564a4b 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java @@ -7,117 +7,68 @@ */ package org.eclipse.xtext.generator.trace.node; +import com.google.inject.Inject; import java.util.List; -import org.eclipse.xtend.lib.annotations.Data; import org.eclipse.xtend2.lib.StringConcatenationClient; import org.eclipse.xtext.generator.trace.ILocationData; -import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.IndentNode; import org.eclipse.xtext.generator.trace.node.NewLineNode; import org.eclipse.xtext.generator.trace.node.TemplateNode; import org.eclipse.xtext.generator.trace.node.TextNode; import org.eclipse.xtext.generator.trace.node.TraceNode; -import org.eclipse.xtext.xbase.lib.Pure; -import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; +import org.eclipse.xtext.generator.trace.node.WhiteSpaceConfig; /** * @author Sven Efftinge - Initial contribution and API */ -@Data @SuppressWarnings("all") public class GeneratorNodeExtensions { - public CompositeNode startTrace(final ILocationData data) { + @Inject + private WhiteSpaceConfig wsConfig = new WhiteSpaceConfig(); + + public CompositeGeneratorNode startTrace(final ILocationData data) { final TraceNode result = new TraceNode(data); return result; } - public CompositeNode trace(final CompositeNode parent, final ILocationData data) { + public CompositeGeneratorNode trace(final CompositeGeneratorNode parent, final ILocationData data) { final TraceNode result = new TraceNode(data); List _children = parent.getChildren(); _children.add(result); return result; } - public CompositeNode indent(final CompositeNode parent) { + public CompositeGeneratorNode indent(final CompositeGeneratorNode parent) { final IndentNode result = new IndentNode(); List _children = parent.getChildren(); _children.add(result); return result; } - public CompositeNode appendNewLine(final CompositeNode parent) { + public CompositeGeneratorNode appendNewLine(final CompositeGeneratorNode parent) { List _children = parent.getChildren(); NewLineNode _newLineNode = new NewLineNode(); _children.add(_newLineNode); return parent; } - public CompositeNode append(final CompositeNode parent, final String text) { - List _children = parent.getChildren(); - TextNode _textNode = new TextNode(text); - _children.add(_textNode); + public CompositeGeneratorNode append(final CompositeGeneratorNode parent, final Object object) { + if ((object != null)) { + List _children = parent.getChildren(); + String _string = object.toString(); + TextNode _textNode = new TextNode(_string); + _children.add(_textNode); + } return parent; } - public CompositeNode append(final CompositeNode parent, final CharSequence text) { - List _children = parent.getChildren(); - TextNode _textNode = new TextNode(text); - _children.add(_textNode); - return parent; - } - - private final String indentationString; - - public IGeneratorNode appendTemplate(final CompositeNode parent, final StringConcatenationClient contents) { - final TemplateNode proc = new TemplateNode(this.indentationString, contents, this); + public CompositeGeneratorNode appendTemplate(final CompositeGeneratorNode parent, final StringConcatenationClient contents) { + String _indentationString = this.wsConfig.getIndentationString(); + final TemplateNode proc = new TemplateNode(_indentationString, contents, this); List _children = parent.getChildren(); _children.add(proc); return parent; } - - public GeneratorNodeExtensions(final String indentationString) { - super(); - this.indentationString = indentationString; - } - - @Override - @Pure - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((this.indentationString== null) ? 0 : this.indentationString.hashCode()); - return result; - } - - @Override - @Pure - public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - GeneratorNodeExtensions other = (GeneratorNodeExtensions) obj; - if (this.indentationString == null) { - if (other.indentationString != null) - return false; - } else if (!this.indentationString.equals(other.indentationString)) - return false; - return true; - } - - @Override - @Pure - public String toString() { - ToStringBuilder b = new ToStringBuilder(this); - b.add("indentationString", this.indentationString); - return b.toString(); - } - - @Pure - public String getIndentationString() { - return this.indentationString; - } } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java index d28ebf044..9fc62309c 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java @@ -16,7 +16,7 @@ import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor; import org.eclipse.xtext.generator.trace.AbstractStatefulTraceRegion; import org.eclipse.xtext.generator.trace.AbstractTraceRegion; import org.eclipse.xtext.generator.trace.ILocationData; -import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.IndentNode; import org.eclipse.xtext.generator.trace.node.NewLineNode; @@ -147,7 +147,7 @@ public class GeneratorNodeProcessor { this.contents.append(node.getText()); } - protected void _process(final CompositeNode node) { + protected void _process(final CompositeGeneratorNode node) { this.processChildren(node); } @@ -170,7 +170,7 @@ public class GeneratorNodeProcessor { } } - protected void processChildren(final CompositeNode node) { + protected void processChildren(final CompositeGeneratorNode node) { List _children = node.getChildren(); for (final IGeneratorNode child : _children) { this.process(child); @@ -184,8 +184,8 @@ public class GeneratorNodeProcessor { } else if (node instanceof TraceNode) { _process((TraceNode)node); return; - } else if (node instanceof CompositeNode) { - _process((CompositeNode)node); + } else if (node instanceof CompositeGeneratorNode) { + _process((CompositeGeneratorNode)node); return; } else if (node instanceof NewLineNode) { _process((NewLineNode)node); diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java index fed1c4e4b..932a75fdf 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java @@ -8,7 +8,7 @@ package org.eclipse.xtext.generator.trace.node; import org.eclipse.xtend.lib.annotations.Data; -import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.xbase.lib.Pure; import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; @@ -17,7 +17,7 @@ import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; */ @Data @SuppressWarnings("all") -public class IndentNode extends CompositeNode { +public class IndentNode extends CompositeGeneratorNode { @Override @Pure public int hashCode() { diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java index 60fead73d..6729f75c4 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java @@ -8,22 +8,29 @@ package org.eclipse.xtext.generator.trace.node; import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.eclipse.xtend2.lib.StringConcatenationClient; -import org.eclipse.xtext.generator.trace.node.CompositeNode; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.IndentNode; import org.eclipse.xtext.generator.trace.node.NewLineNode; import org.eclipse.xtext.generator.trace.node.TextNode; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.Functions.Function1; +import org.eclipse.xtext.xbase.lib.Functions.Function2; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.ListExtensions; /** * @author Sven Efftinge - Initial contribution and API */ @SuppressWarnings("all") -public class TemplateNode extends CompositeNode implements StringConcatenationClient.TargetStringConcatenation { +public class TemplateNode extends CompositeGeneratorNode implements StringConcatenationClient.TargetStringConcatenation { private final String indentationString; private final GeneratorNodeExtensions nodeFactory; @@ -34,7 +41,7 @@ public class TemplateNode extends CompositeNode implements StringConcatenationCl StringConcatenationClient.appendTo(contents, this); } - private CompositeNode currentParent = this; + private CompositeGeneratorNode currentParent = this; private boolean isEmptyLine = true; @@ -42,7 +49,7 @@ public class TemplateNode extends CompositeNode implements StringConcatenationCl public void append(final Object object, final String indentation) { final int idx = indentation.indexOf(this.indentationString); if ((idx == 0)) { - final CompositeNode before = this.currentParent; + final CompositeGeneratorNode before = this.currentParent; try { IndentNode _indentNode = new IndentNode(); this.currentParent = _indentNode; @@ -68,7 +75,7 @@ public class TemplateNode extends CompositeNode implements StringConcatenationCl if (!_matched) { if (object instanceof IGeneratorNode) { _matched=true; - this.isEmptyLine = false; + this.isEmptyLine = this.isEmptyLine(((IGeneratorNode)object)); List _children = this.currentParent.getChildren(); _children.add(((IGeneratorNode)object)); } @@ -96,6 +103,44 @@ public class TemplateNode extends CompositeNode implements StringConcatenationCl } } + private boolean isEmptyLine(final IGeneratorNode n) { + Iterable _leafsBackwards = this.leafsBackwards(n); + for (final IGeneratorNode leaf : _leafsBackwards) { + { + if ((leaf instanceof TextNode)) { + boolean _isEmpty = ((TextNode)leaf).getText().toString().trim().isEmpty(); + boolean _not = (!_isEmpty); + if (_not) { + return false; + } + } + if ((leaf instanceof NewLineNode)) { + return true; + } + } + } + return false; + } + + private Iterable leafsBackwards(final IGeneratorNode it) { + Iterable _switchResult = null; + boolean _matched = false; + if (it instanceof CompositeGeneratorNode) { + _matched=true; + final Function1> _function = (IGeneratorNode it_1) -> { + return this.leafsBackwards(it_1); + }; + final Function2, Iterable, Iterable> _function_1 = (Iterable p1, Iterable p2) -> { + return Iterables.concat(p1, p2); + }; + _switchResult = IterableExtensions.>reduce(ListExtensions.>map(ListExtensions.reverseView(((CompositeGeneratorNode)it).getChildren()), _function), _function_1); + } + if (!_matched) { + _switchResult = Collections.unmodifiableList(CollectionLiterals.newArrayList(it)); + } + return _switchResult; + } + @Override public void appendImmediate(final Object object, final String indentation) { for (int i = this.currentParent.getChildren().size(); (i >= 0); i--) { diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java index ee9377788..9a371e7b8 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java @@ -7,12 +7,9 @@ */ package org.eclipse.xtext.generator.trace.node; -import java.util.List; import org.eclipse.xtend.lib.annotations.Data; import org.eclipse.xtext.generator.trace.ILocationData; -import org.eclipse.xtext.generator.trace.node.CompositeNode; -import org.eclipse.xtext.generator.trace.node.IGeneratorNode; -import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.xbase.lib.Pure; import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; @@ -21,11 +18,9 @@ import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; */ @Data @SuppressWarnings("all") -public class TraceNode extends CompositeNode { +public class TraceNode extends CompositeGeneratorNode { private final ILocationData sourceLocation; - private final List children = CollectionLiterals.newArrayList(); - public TraceNode(final ILocationData sourceLocation) { super(); this.sourceLocation = sourceLocation; @@ -37,7 +32,6 @@ public class TraceNode extends CompositeNode { final int prime = 31; int result = 1; result = prime * result + ((this.sourceLocation== null) ? 0 : this.sourceLocation.hashCode()); - result = prime * result + ((this.children== null) ? 0 : this.children.hashCode()); return result; } @@ -56,11 +50,6 @@ public class TraceNode extends CompositeNode { return false; } else if (!this.sourceLocation.equals(other.sourceLocation)) return false; - if (this.children == null) { - if (other.children != null) - return false; - } else if (!this.children.equals(other.children)) - return false; return true; } @@ -77,9 +66,4 @@ public class TraceNode extends CompositeNode { public ILocationData getSourceLocation() { return this.sourceLocation; } - - @Pure - public List getChildren() { - return this.children; - } } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/Traced.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/Traced.java new file mode 100644 index 000000000..1aade423a --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/Traced.java @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import org.eclipse.xtend.lib.macro.Active; +import org.eclipse.xtext.generator.trace.node.TracedProcessor; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Active(TracedProcessor.class) +public @interface Traced { + public String tracingSugarFieldName() default "_traceExtensions"; +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedProcessor.java new file mode 100644 index 000000000..0fe34a026 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedProcessor.java @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtend.lib.macro.AbstractMethodProcessor; +import org.eclipse.xtend.lib.macro.TransformationContext; +import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration; +import org.eclipse.xtend.lib.macro.declaration.MutableFieldDeclaration; +import org.eclipse.xtend.lib.macro.declaration.MutableMethodDeclaration; +import org.eclipse.xtend.lib.macro.declaration.MutableParameterDeclaration; +import org.eclipse.xtend.lib.macro.declaration.MutableTypeDeclaration; +import org.eclipse.xtend.lib.macro.declaration.TypeReference; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.generator.trace.ILocationData; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.generator.trace.node.Traced; +import org.eclipse.xtext.generator.trace.node.TracingSugar; +import org.eclipse.xtext.xbase.lib.Extension; +import org.eclipse.xtext.xbase.lib.Functions.Function1; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; + +@SuppressWarnings("all") +public class TracedProcessor extends AbstractMethodProcessor { + @Override + public void doTransform(final MutableMethodDeclaration annotatedMethod, @Extension final TransformationContext context) { + final TypeReference traceSugar = context.newTypeReference(TracingSugar.class); + final TypeReference templateClient = context.newTypeReference(StringConcatenationClient.class); + final TypeReference nodeType = context.newTypeReference(IGeneratorNode.class); + final TypeReference eobjectType = context.newTypeReference(EObject.class); + MutableTypeDeclaration _declaringType = annotatedMethod.getDeclaringType(); + final MutableClassDeclaration clazz = ((MutableClassDeclaration) _declaringType); + final Function1 _function = (MutableFieldDeclaration it) -> { + return Boolean.valueOf(traceSugar.isAssignableFrom(it.getType())); + }; + final MutableFieldDeclaration field = IterableExtensions.findFirst(clazz.getDeclaredFields(), _function); + if ((field == null)) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("@"); + String _simpleName = Traced.class.getSimpleName(); + _builder.append(_simpleName); + _builder.append(" methods can only declared in a class with a field of type "); + _builder.append(TracingSugar.class); + context.addError(annotatedMethod, _builder.toString()); + return; + } + final Function1 _function_1 = (MutableParameterDeclaration it) -> { + return Boolean.valueOf(eobjectType.isAssignableFrom(it.getType())); + }; + final MutableParameterDeclaration traceParam = IterableExtensions.findFirst(annotatedMethod.getParameters(), _function_1); + if ((traceParam == null)) { + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("@"); + String _simpleName_1 = Traced.class.getSimpleName(); + _builder_1.append(_simpleName_1); + _builder_1.append(" methods need at least one parameter of type "); + _builder_1.append(EObject.class); + _builder_1.append("."); + context.addError(annotatedMethod, _builder_1.toString()); + return; + } + String _simpleName_2 = annotatedMethod.getSimpleName(); + String _plus = ("_" + _simpleName_2); + final Procedure1 _function_2 = (MutableMethodDeclaration it) -> { + Iterable _parameters = annotatedMethod.getParameters(); + for (final MutableParameterDeclaration p : _parameters) { + it.addParameter(p.getSimpleName(), p.getType()); + } + it.setReturnType(templateClient); + it.setBody(annotatedMethod.getBody()); + }; + clazz.addMethod(_plus, _function_2); + annotatedMethod.setReturnType(nodeType); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append(ILocationData.class); + _builder.append(" _location = this."); + String _simpleName = field.getSimpleName(); + _builder.append(_simpleName); + _builder.append(".location("); + String _simpleName_1 = traceParam.getSimpleName(); + _builder.append(_simpleName_1); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append(CompositeGeneratorNode.class); + _builder.append(" _traceNode = this."); + String _simpleName_2 = field.getSimpleName(); + _builder.append(_simpleName_2); + _builder.append(".startTrace(_location);"); + _builder.newLineIfNotEmpty(); + _builder.append("this."); + String _simpleName_3 = field.getSimpleName(); + _builder.append(_simpleName_3); + _builder.append(".appendTemplate(_traceNode, _"); + String _simpleName_4 = annotatedMethod.getSimpleName(); + _builder.append(_simpleName_4); + _builder.append("("); + final Function1 _function = (MutableParameterDeclaration it) -> { + return it.getSimpleName(); + }; + String _join = IterableExtensions.join(annotatedMethod.getParameters(), ",", _function); + _builder.append(_join); + _builder.append("));"); + _builder.newLineIfNotEmpty(); + _builder.append("return _traceNode;"); + _builder.newLine(); + } + }; + annotatedMethod.setBody(_client); + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.java new file mode 100644 index 000000000..7d6e64fbb --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import org.eclipse.emf.ecore.EFactory; +import org.eclipse.xtend.lib.macro.Active; +import org.eclipse.xtext.generator.trace.node.TracingExtensionsForEMFProcessor; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@Active(TracingExtensionsForEMFProcessor.class) +public @interface TracingExtensionsForEMF { + public Class[] value(); +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMFProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMFProcessor.java new file mode 100644 index 000000000..463f20d71 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMFProcessor.java @@ -0,0 +1,190 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +import com.google.common.collect.Iterables; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.xtend.lib.macro.AbstractClassProcessor; +import org.eclipse.xtend.lib.macro.TransformationContext; +import org.eclipse.xtend.lib.macro.declaration.AnnotationReference; +import org.eclipse.xtend.lib.macro.declaration.InterfaceDeclaration; +import org.eclipse.xtend.lib.macro.declaration.MethodDeclaration; +import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration; +import org.eclipse.xtend.lib.macro.declaration.MutableMethodDeclaration; +import org.eclipse.xtend.lib.macro.declaration.ResolvedMethod; +import org.eclipse.xtend.lib.macro.declaration.Type; +import org.eclipse.xtend.lib.macro.declaration.TypeReference; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.generator.trace.ILocationData; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.generator.trace.node.TracingExtensionsForEMF; +import org.eclipse.xtext.generator.trace.node.TracingSugar; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.Conversions; +import org.eclipse.xtext.xbase.lib.Extension; +import org.eclipse.xtext.xbase.lib.Functions.Function1; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.ListExtensions; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; +import org.eclipse.xtext.xbase.lib.StringExtensions; + +@SuppressWarnings("all") +public class TracingExtensionsForEMFProcessor extends AbstractClassProcessor { + @Override + public void doTransform(final MutableClassDeclaration annotatedClass, @Extension final TransformationContext context) { + final TypeReference eobjectType = context.newTypeReference(EObject.class); + annotatedClass.setExtendedClass(context.newTypeReference(TracingSugar.class)); + final Type annotationType = context.findTypeGlobally(TracingExtensionsForEMF.class); + AnnotationReference _findAnnotation = annotatedClass.findAnnotation(annotationType); + TypeReference[] _classArrayValue = null; + if (_findAnnotation!=null) { + _classArrayValue=_findAnnotation.getClassArrayValue("value"); + } + final TypeReference[] factories = _classArrayValue; + if ((factories == null)) { + return; + } + final Function1 _function = (TypeReference it) -> { + return it.getType(); + }; + Iterable _filter = Iterables.filter(ListExtensions.map(((List)Conversions.doWrapArray(factories)), _function), InterfaceDeclaration.class); + for (final InterfaceDeclaration f : _filter) { + final Function1 _function_1 = (MethodDeclaration it) -> { + return Boolean.valueOf((it.getSimpleName().startsWith("create") && IterableExtensions.isEmpty(it.getParameters()))); + }; + final Function1 _function_2 = (MethodDeclaration it) -> { + return it.getReturnType(); + }; + Iterable _map = IterableExtensions.map(IterableExtensions.filter(f.getDeclaredMethods(), _function_1), _function_2); + for (final TypeReference t : _map) { + final Function1 _function_3 = (ResolvedMethod it) -> { + return Boolean.valueOf(this.isGetter(it)); + }; + Iterable _filter_1 = IterableExtensions.filter(t.getAllResolvedMethods(), _function_3); + for (final ResolvedMethod getter : _filter_1) { + { + final TypeReference rt = getter.getResolvedReturnType(); + boolean _contains = TracingExtensionsForEMFProcessor.allowedLowerCaseTypeNames.contains(rt.getType().getSimpleName().toLowerCase()); + if (_contains) { + final Procedure1 _function_4 = (MutableMethodDeclaration it) -> { + it.setReturnType(context.newTypeReference(IGeneratorNode.class)); + it.addParameter("target", t); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append(EStructuralFeature.class); + _builder.append(" feature = target.eClass().getEStructuralFeature(\""); + String _featureName = TracingExtensionsForEMFProcessor.this.featureName(getter); + _builder.append(_featureName); + _builder.append("\");"); + _builder.newLineIfNotEmpty(); + _builder.append(ILocationData.class); + _builder.append(" location = this.location(target, feature, -1);"); + _builder.newLineIfNotEmpty(); + _builder.append(CompositeGeneratorNode.class); + _builder.append(" trace = this.startTrace(location);"); + _builder.newLineIfNotEmpty(); + _builder.append("this.append(trace, target."); + String _simpleName = getter.getDeclaration().getSimpleName(); + _builder.append(_simpleName); + _builder.append("());"); + _builder.newLineIfNotEmpty(); + _builder.append("return trace;"); + _builder.newLine(); + } + }; + it.setBody(_client); + }; + annotatedClass.addMethod(this.tracerName(getter), _function_4); + } else { + boolean _isAssignableFrom = eobjectType.isAssignableFrom(rt); + if (_isAssignableFrom) { + final Procedure1 _function_5 = (MutableMethodDeclaration it) -> { + it.setReturnType(context.newTypeReference(IGeneratorNode.class)); + it.addParameter("target", t); + final TypeReference stringProvider = context.newTypeReference(Function.class, rt, context.getString()); + it.addParameter("stringProvider", stringProvider); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append(EStructuralFeature.class); + _builder.append(" feature = target.eClass().getEStructuralFeature(\""); + String _featureName = TracingExtensionsForEMFProcessor.this.featureName(getter); + _builder.append(_featureName); + _builder.append("\");"); + _builder.newLineIfNotEmpty(); + _builder.append(ILocationData.class); + _builder.append(" location = this.location(target, feature, -1);"); + _builder.newLineIfNotEmpty(); + _builder.append(CompositeGeneratorNode.class); + _builder.append(" trace = this.startTrace(location);"); + _builder.newLineIfNotEmpty(); + _builder.append("this.append(trace, stringProvider.apply(target."); + String _simpleName = getter.getDeclaration().getSimpleName(); + _builder.append(_simpleName); + _builder.append("()));"); + _builder.newLineIfNotEmpty(); + _builder.append("return trace;"); + _builder.newLine(); + } + }; + it.setBody(_client); + }; + annotatedClass.addMethod(this.tracerName(getter), _function_5); + } + } + } + } + } + } + } + + public String tracerName(final ResolvedMethod m) { + String _featureName = this.featureName(m); + return ("_" + _featureName); + } + + public String featureName(final ResolvedMethod m) { + String _xblockexpression = null; + { + final String n = m.getDeclaration().getSimpleName(); + int _xifexpression = (int) 0; + boolean _startsWith = n.startsWith("get"); + if (_startsWith) { + _xifexpression = 3; + } else { + _xifexpression = 2; + } + final int skip = _xifexpression; + _xblockexpression = StringExtensions.toFirstLower(m.getDeclaration().getSimpleName().substring(skip)); + } + return _xblockexpression; + } + + private final static Set allowedLowerCaseTypeNames = Collections.unmodifiableSet(CollectionLiterals.newHashSet("string", "boolean", "int", "long", "integer")); + + public boolean isGetter(final ResolvedMethod it) { + boolean _isEmpty = IterableExtensions.isEmpty(it.getDeclaration().getParameters()); + boolean _not = (!_isEmpty); + if (_not) { + return false; + } + boolean _isStatic = it.getDeclaration().isStatic(); + if (_isStatic) { + return false; + } + final String n = it.getDeclaration().getSimpleName(); + return (n.startsWith("get") || n.startsWith("is")); + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java new file mode 100644 index 000000000..4e8fb589a --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java @@ -0,0 +1,169 @@ +package org.eclipse.xtext.generator.trace.node; + +import com.google.inject.Inject; +import java.util.stream.IntStream; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtend.lib.annotations.Delegate; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.eclipse.xtext.generator.trace.AbstractTraceRegion; +import org.eclipse.xtext.generator.trace.ILocationData; +import org.eclipse.xtext.generator.trace.ITraceRegionProvider; +import org.eclipse.xtext.generator.trace.ITraceURIConverter; +import org.eclipse.xtext.generator.trace.LocationData; +import org.eclipse.xtext.generator.trace.SourceRelativeURI; +import org.eclipse.xtext.generator.trace.TraceNotFoundException; +import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; +import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; +import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor; +import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.generator.trace.node.WhiteSpaceConfig; +import org.eclipse.xtext.resource.ILocationInFileProvider; +import org.eclipse.xtext.util.ITextRegion; +import org.eclipse.xtext.util.ITextRegionWithLineInformation; +import org.eclipse.xtext.xbase.lib.Functions.Function1; +import org.eclipse.xtext.xbase.lib.Pure; + +@SuppressWarnings("all") +public class TracingSugar extends GeneratorNodeExtensions { + @Data + public static class Result implements CharSequence, ITraceRegionProvider { + @Delegate + private final CharSequence contents; + + private final AbstractTraceRegion traceRegion; + + @Override + public AbstractTraceRegion getTraceRegion() throws TraceNotFoundException { + return this.traceRegion; + } + + @Override + public String toString() { + return this.contents.toString(); + } + + public Result(final CharSequence contents, final AbstractTraceRegion traceRegion) { + super(); + this.contents = contents; + this.traceRegion = traceRegion; + } + + @Override + @Pure + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.contents== null) ? 0 : this.contents.hashCode()); + result = prime * result + ((this.traceRegion== null) ? 0 : this.traceRegion.hashCode()); + return result; + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TracingSugar.Result other = (TracingSugar.Result) obj; + if (this.contents == null) { + if (other.contents != null) + return false; + } else if (!this.contents.equals(other.contents)) + return false; + if (this.traceRegion == null) { + if (other.traceRegion != null) + return false; + } else if (!this.traceRegion.equals(other.traceRegion)) + return false; + return true; + } + + @Pure + public CharSequence getContents() { + return this.contents; + } + + public char charAt(final int index) { + return this.contents.charAt(index); + } + + public IntStream chars() { + return this.contents.chars(); + } + + public IntStream codePoints() { + return this.contents.codePoints(); + } + + public int length() { + return this.contents.length(); + } + + public CharSequence subSequence(final int start, final int end) { + return this.contents.subSequence(start, end); + } + } + + @Inject + protected ILocationInFileProvider locationProvider; + + @Inject + protected ITraceURIConverter traceURIConverter; + + @Inject + protected WhiteSpaceConfig whiteSpaceConfig; + + public void generateTracedFile(final IFileSystemAccess2 fsa, final String path, final EObject rootTrace, final StringConcatenationClient code) { + final IGeneratorNode node = this.trace(rootTrace, code); + StringBuilder _stringBuilder = new StringBuilder(); + String _indentationString = this.whiteSpaceConfig.getIndentationString(); + String _lineDelimiter = this.whiteSpaceConfig.getLineDelimiter(); + final GeneratorNodeProcessor proc = new GeneratorNodeProcessor(_stringBuilder, _indentationString, _lineDelimiter); + proc.process(node); + StringBuilder _contents = proc.getContents(); + AbstractTraceRegion _currentRegion = proc.getCurrentRegion(); + TracingSugar.Result _result = new TracingSugar.Result(_contents, _currentRegion); + fsa.generateFile(path, _result); + } + + public void generateTracedFile(final IFileSystemAccess2 fsa, final String path, final CompositeGeneratorNode rootNode) { + StringBuilder _stringBuilder = new StringBuilder(); + final GeneratorNodeProcessor proc = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); + proc.process(rootNode); + StringBuilder _contents = proc.getContents(); + AbstractTraceRegion _currentRegion = proc.getCurrentRegion(); + TracingSugar.Result _result = new TracingSugar.Result(_contents, _currentRegion); + fsa.generateFile(path, _result); + } + + public IGeneratorNode trace(final EObject obj, final StringConcatenationClient code) { + final ITextRegion region = this.locationProvider.getFullTextRegion(obj); + final SourceRelativeURI uri = this.traceURIConverter.getURIForTrace(obj.eResource()); + final LocationData location = new LocationData(((ITextRegionWithLineInformation) region), uri); + return this.appendTemplate(this.startTrace(location), code); + } + + public IGeneratorNode trace(final T obj, final Function1 code) { + final String string = code.apply(obj); + final ILocationData location = this.location(obj); + return this.append(this.startTrace(location), string); + } + + public ILocationData location(final EObject obj) { + final ITextRegion region = this.locationProvider.getFullTextRegion(obj); + final SourceRelativeURI uri = this.traceURIConverter.getURIForTrace(obj.eResource()); + return new LocationData(((ITextRegionWithLineInformation) region), uri); + } + + public ILocationData location(final EObject obj, final EStructuralFeature feature, final int idx) { + final ITextRegion region = this.locationProvider.getFullTextRegion(obj, feature, idx); + final SourceRelativeURI uri = this.traceURIConverter.getURIForTrace(obj.eResource()); + return new LocationData(((ITextRegionWithLineInformation) region), uri); + } +} diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.java new file mode 100644 index 000000000..2b581fd98 --- /dev/null +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.generator.trace.node; + +/** + * @author Sven Efftinge - Initial contribution and API + */ +@SuppressWarnings("all") +public class WhiteSpaceConfig { + public String getIndentationString() { + return " "; + } + + public String getLineDelimiter() { + return "\n"; + } +} From ac2b856e6e71f595e943212f7619cc34c9698539 Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Sun, 26 Feb 2017 15:50:48 +0100 Subject: [PATCH 3/5] [tracing] rename (#287) --- .../generator/trace/node/TracingSugarTest.xtend | 2 +- .../xtext/generator/trace/node/TracingSugarTest.java | 4 ++-- ...xtensionsForEMF.xtend => TracingExtensions.xtend} | 8 ++++---- ...gExtensionsForEMF.java => TracingExtensions.java} | 6 +++--- ...rocessor.java => TracingExtensionsProcessor.java} | 12 ++++++------ 5 files changed, 16 insertions(+), 16 deletions(-) rename org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/{TracingExtensionsForEMF.xtend => TracingExtensions.xtend} (94%) rename org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/{TracingExtensionsForEMF.java => TracingExtensions.java} (76%) rename org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/{TracingExtensionsForEMFProcessor.java => TracingExtensionsProcessor.java} (94%) diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend index e10a6ea53..8a624395f 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend @@ -29,7 +29,7 @@ import org.eclipse.xtext.generator.trace.ITraceRegionProvider @InjectWith(LazyLinkingTestLanguageInjectorProvider) class TracingSugarTest { - @TracingExtensionsForEMF(LazyLinkingFactory) + @TracingExtensions(LazyLinkingFactory) static class MyExtensions { /** diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java index 586038155..5825bea81 100644 --- a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java @@ -20,7 +20,7 @@ import org.eclipse.xtext.generator.trace.ITraceRegionProvider; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.Traced; -import org.eclipse.xtext.generator.trace.node.TracingExtensionsForEMF; +import org.eclipse.xtext.generator.trace.node.TracingExtensions; import org.eclipse.xtext.generator.trace.node.TracingSugar; import org.eclipse.xtext.linking.lazy.lazyLinking.LazyLinkingFactory; import org.eclipse.xtext.linking.lazy.lazyLinking.Model; @@ -46,7 +46,7 @@ import org.junit.runner.RunWith; @InjectWith(LazyLinkingTestLanguageInjectorProvider.class) @SuppressWarnings("all") public class TracingSugarTest { - @TracingExtensionsForEMF(LazyLinkingFactory.class) + @TracingExtensions(LazyLinkingFactory.class) public static class MyExtensions extends TracingSugar { /** * manual implementation for unsupported multi cross reference diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend similarity index 94% rename from org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.xtend rename to org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend index e23f0686c..1c873c4bb 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend @@ -22,17 +22,17 @@ import org.eclipse.xtext.generator.trace.ILocationData /** * @author Sven Efftinge - Initial contribution and API */ -@Active(TracingExtensionsForEMFProcessor) -annotation TracingExtensionsForEMF { +@Active(TracingExtensionsProcessor) +annotation TracingExtensions { Class[] value } -class TracingExtensionsForEMFProcessor extends AbstractClassProcessor { +class TracingExtensionsProcessor extends AbstractClassProcessor { override doTransform(MutableClassDeclaration annotatedClass, extension TransformationContext context) { val eobjectType = EObject.newTypeReference() annotatedClass.extendedClass = TracingSugar.newTypeReference() - val annotationType = findTypeGlobally(TracingExtensionsForEMF) + val annotationType = findTypeGlobally(TracingExtensions) val factories = annotatedClass.findAnnotation(annotationType)?.getClassArrayValue("value") if (factories === null) { return; diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensions.java similarity index 76% rename from org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.java rename to org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensions.java index 7d6e64fbb..4856ec5d4 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMF.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensions.java @@ -9,12 +9,12 @@ package org.eclipse.xtext.generator.trace.node; import org.eclipse.emf.ecore.EFactory; import org.eclipse.xtend.lib.macro.Active; -import org.eclipse.xtext.generator.trace.node.TracingExtensionsForEMFProcessor; +import org.eclipse.xtext.generator.trace.node.TracingExtensionsProcessor; /** * @author Sven Efftinge - Initial contribution and API */ -@Active(TracingExtensionsForEMFProcessor.class) -public @interface TracingExtensionsForEMF { +@Active(TracingExtensionsProcessor.class) +public @interface TracingExtensions { public Class[] value(); } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMFProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java similarity index 94% rename from org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMFProcessor.java rename to org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java index 463f20d71..4623c4ea9 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsForEMFProcessor.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java @@ -28,7 +28,7 @@ import org.eclipse.xtend2.lib.StringConcatenationClient; import org.eclipse.xtext.generator.trace.ILocationData; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; -import org.eclipse.xtext.generator.trace.node.TracingExtensionsForEMF; +import org.eclipse.xtext.generator.trace.node.TracingExtensions; import org.eclipse.xtext.generator.trace.node.TracingSugar; import org.eclipse.xtext.xbase.lib.CollectionLiterals; import org.eclipse.xtext.xbase.lib.Conversions; @@ -40,12 +40,12 @@ import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; import org.eclipse.xtext.xbase.lib.StringExtensions; @SuppressWarnings("all") -public class TracingExtensionsForEMFProcessor extends AbstractClassProcessor { +public class TracingExtensionsProcessor extends AbstractClassProcessor { @Override public void doTransform(final MutableClassDeclaration annotatedClass, @Extension final TransformationContext context) { final TypeReference eobjectType = context.newTypeReference(EObject.class); annotatedClass.setExtendedClass(context.newTypeReference(TracingSugar.class)); - final Type annotationType = context.findTypeGlobally(TracingExtensionsForEMF.class); + final Type annotationType = context.findTypeGlobally(TracingExtensions.class); AnnotationReference _findAnnotation = annotatedClass.findAnnotation(annotationType); TypeReference[] _classArrayValue = null; if (_findAnnotation!=null) { @@ -75,7 +75,7 @@ public class TracingExtensionsForEMFProcessor extends AbstractClassProcessor { for (final ResolvedMethod getter : _filter_1) { { final TypeReference rt = getter.getResolvedReturnType(); - boolean _contains = TracingExtensionsForEMFProcessor.allowedLowerCaseTypeNames.contains(rt.getType().getSimpleName().toLowerCase()); + boolean _contains = TracingExtensionsProcessor.allowedLowerCaseTypeNames.contains(rt.getType().getSimpleName().toLowerCase()); if (_contains) { final Procedure1 _function_4 = (MutableMethodDeclaration it) -> { it.setReturnType(context.newTypeReference(IGeneratorNode.class)); @@ -85,7 +85,7 @@ public class TracingExtensionsForEMFProcessor extends AbstractClassProcessor { protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { _builder.append(EStructuralFeature.class); _builder.append(" feature = target.eClass().getEStructuralFeature(\""); - String _featureName = TracingExtensionsForEMFProcessor.this.featureName(getter); + String _featureName = TracingExtensionsProcessor.this.featureName(getter); _builder.append(_featureName); _builder.append("\");"); _builder.newLineIfNotEmpty(); @@ -120,7 +120,7 @@ public class TracingExtensionsForEMFProcessor extends AbstractClassProcessor { protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { _builder.append(EStructuralFeature.class); _builder.append(" feature = target.eClass().getEStructuralFeature(\""); - String _featureName = TracingExtensionsForEMFProcessor.this.featureName(getter); + String _featureName = TracingExtensionsProcessor.this.featureName(getter); _builder.append(_featureName); _builder.append("\");"); _builder.newLineIfNotEmpty(); From d909078dfd1d0803c10fa705d8261ddcc059a304 Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Mon, 27 Feb 2017 14:14:34 +0100 Subject: [PATCH 4/5] [tracing] various improvements (#287) - fixed indentation issues - support newLineIfNotEmpty semantics - indent and newline nodes contain the actual string - better naming - documentation --- .../trace/node/GeneratorNodeTest.xtend | 57 ++-- .../trace/node/TemplateNodeTest.xtend | 13 +- .../trace/node/TracingSugarTest.xtend | 4 +- .../trace/node/GeneratorNodeTest.java | 158 ++++----- .../trace/node/TemplateNodeTest.java | 16 +- .../trace/node/TracingSugarTest.java | 18 +- .../trace/node/CompositeGeneratorNode.xtend | 8 + .../trace/node/GeneratorNodeExtensions.xtend | 72 +++- .../trace/node/GeneratorNodeProcessor.xtend | 137 +++++--- .../generator/trace/node/IndentNode.xtend | 6 +- .../generator/trace/node/NewLineNode.xtend | 7 +- .../generator/trace/node/TemplateNode.xtend | 42 +-- .../generator/trace/node/TraceNode.xtend | 7 +- .../xtext/generator/trace/node/Traced.xtend | 2 +- .../trace/node/TracingExtensions.xtend | 4 +- .../generator/trace/node/TracingSugar.xtend | 75 ++--- .../trace/node/CompositeGeneratorNode.java | 21 ++ .../trace/node/GeneratorNodeExtensions.java | 81 ++++- .../trace/node/GeneratorNodeProcessor.java | 308 +++++++++++++----- .../generator/trace/node/IndentNode.java | 37 +-- .../generator/trace/node/NewLineNode.java | 62 ++++ .../generator/trace/node/TemplateNode.java | 53 +-- .../xtext/generator/trace/node/TraceNode.java | 43 +-- .../generator/trace/node/TracedProcessor.java | 2 +- .../node/TracingExtensionsProcessor.java | 4 +- .../generator/trace/node/TracingSugar.java | 154 +++------ 26 files changed, 811 insertions(+), 580 deletions(-) diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend index 4c0cf9458..98e6b345b 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.xtend @@ -22,19 +22,19 @@ class GeneratorNodeTest { @Test def void testBasicCreationAndProcessing() { val root = loc(0) - var node = root.startTrace + var node = root.trace .append('notindented').appendNewLine node.indent.trace(loc(1)) .append("indented1").appendNewLine .append("indented2") node.appendNewLine.append("dedented") - val processor = new GeneratorNodeProcessor(new StringBuilder, " ", "\n") - processor.process(node) + val processor = new GeneratorNodeProcessor() + val result = processor.process(node) Assert.assertEquals(''' notindented indented1 indented2 - dedented'''.toString, processor.contents.toString) + dedented'''.toString, result.toString) Assert.assertEquals(''' CompletableTraceRegion [myOffset=0, myLength=44] associations={ LocationData [TextRegionWithLineInformation [0:100][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] @@ -42,64 +42,51 @@ class GeneratorNodeTest { CompletableTraceRegion [myOffset=14, myLength=21] associations={ LocationData [TextRegionWithLineInformation [1:99][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] } - }'''.toString, processor.currentRegion.toString) + }'''.toString, result.traceRegion.toString) } @Test def void testTemplateProcessing() { val root = loc(0) - var node = root.startTrace + var node = root.trace .appendTemplate(''' «someCodeGen(2)» ''') - val processor = new GeneratorNodeProcessor(new StringBuilder, " ", "\n") - processor.process(node) + + val processor = new GeneratorNodeProcessor() + val result = processor.process(node) + Assert.assertEquals(someCodeGen_noTrace(2).toString, result.toString) Assert.assertEquals(''' - before Hello after - before Hello after - - before Hello after - - - before Hello after - before Hello after - - before Hello after - - - - '''.toString, processor.contents.toString) - Assert.assertEquals(''' - CompletableTraceRegion [myOffset=0, myLength=153] associations={ + CompletableTraceRegion [myOffset=0, myLength=80] associations={ LocationData [TextRegionWithLineInformation [0:100][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] } nestedRegions={ CompletableTraceRegion [myOffset=7, myLength=5] associations={ LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] } - CompletableTraceRegion [myOffset=30, myLength=5] associations={ + CompletableTraceRegion [myOffset=28, myLength=5] associations={ LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] } - CompletableTraceRegion [myOffset=58, myLength=5] associations={ - LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] - } - CompletableTraceRegion [myOffset=83, myLength=5] associations={ + CompletableTraceRegion [myOffset=47, myLength=5] associations={ LocationData [TextRegionWithLineInformation [11:89][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] } - CompletableTraceRegion [myOffset=106, myLength=5] associations={ + CompletableTraceRegion [myOffset=68, myLength=5] associations={ LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] } - CompletableTraceRegion [myOffset=134, myLength=5] associations={ - LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl] - } - }'''.toString, processor.currentRegion.toString) + }'''.toString, result.traceRegion.toString) } def StringConcatenationClient someCodeGen(int n) ''' «FOR i : 0.. 1» - «FOR i : 1..4» + d «IF 2 > 1»s + ee «FOR i : 1..4» + «''» «other» «i» «multiLineString» «multiLineString» «ENDFOR» @@ -53,14 +54,14 @@ class TemplateNodeTest { def void assertEquals(StringConcatenationClient c) { val ext = new GeneratorNodeExtensions() - val processor = new GeneratorNodeProcessor(new StringBuilder, " ", "\n") + val processor = new GeneratorNodeProcessor() val root = new CompositeGeneratorNode() ext.appendTemplate(root, c); - processor.process(root) + val result = processor.process(root) val expected = new StringConcatenation() expected.append(c) - Assert.assertEquals(expected.toString, processor.contents.toString) + Assert.assertEquals(expected.toString, result.toString) } } \ No newline at end of file diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend index 8a624395f..12939a594 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend @@ -37,7 +37,7 @@ class TracingSugarTest { */ def IGeneratorNode _type(Property it, (Type)=>String provider) { val location = location(eClass.getEStructuralFeature("type"), 0) - val result = location.startTrace + val result = location.trace result.append(provider.apply(type.head)) return result } @@ -93,7 +93,7 @@ class TracingSugarTest { CompletableTraceRegion [myOffset=23, myLength=3] associations={ LocationData [TextRegionWithLineInformation [20:3][lineNumber=1, endLineNumber=1]][path=__synthetic0.lazylinkingtestlanguage] } - CompletableTraceRegion [myOffset=30, myLength=23] associations={ + CompletableTraceRegion [myOffset=30, myLength=24] associations={ LocationData [TextRegionWithLineInformation [27:12][lineNumber=2, endLineNumber=2]][path=__synthetic0.lazylinkingtestlanguage] } nestedRegions={ CompletableTraceRegion [myOffset=39, myLength=4] associations={ diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java index c35db37ae..4df1c2ca5 100644 --- a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeTest.java @@ -30,12 +30,11 @@ public class GeneratorNodeTest { @Test public void testBasicCreationAndProcessing() { final LocationData root = this.loc(0); - CompositeGeneratorNode node = this.exts.appendNewLine(this.exts.append(this.exts.startTrace(root), "notindented")); + CompositeGeneratorNode node = this.exts.appendNewLine(this.exts.append(this.exts.trace(root), "notindented")); this.exts.append(this.exts.appendNewLine(this.exts.append(this.exts.trace(this.exts.indent(node), this.loc(1)), "indented1")), "indented2"); this.exts.append(this.exts.appendNewLine(node), "dedented"); - StringBuilder _stringBuilder = new StringBuilder(); - final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); - processor.process(node); + final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(); + final GeneratorNodeProcessor.Result result = processor.process(node); StringConcatenation _builder = new StringConcatenation(); _builder.append("notindented"); _builder.newLine(); @@ -46,7 +45,7 @@ public class GeneratorNodeTest { _builder.append("indented2"); _builder.newLine(); _builder.append("dedented"); - Assert.assertEquals(_builder.toString(), processor.getContents().toString()); + Assert.assertEquals(_builder.toString(), result.toString()); StringConcatenation _builder_1 = new StringConcatenation(); _builder_1.append("CompletableTraceRegion [myOffset=0, myLength=44] associations={"); _builder_1.newLine(); @@ -65,13 +64,13 @@ public class GeneratorNodeTest { _builder_1.append("}"); _builder_1.newLine(); _builder_1.append("}"); - Assert.assertEquals(_builder_1.toString(), processor.getCurrentRegion().toString()); + Assert.assertEquals(_builder_1.toString(), result.getTraceRegion().toString()); } @Test public void testTemplateProcessing() { final LocationData root = this.loc(0); - CompositeGeneratorNode _startTrace = this.exts.startTrace(root); + CompositeGeneratorNode _trace = this.exts.trace(root); StringConcatenationClient _client = new StringConcatenationClient() { @Override protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { @@ -80,103 +79,56 @@ public class GeneratorNodeTest { _builder.newLineIfNotEmpty(); } }; - CompositeGeneratorNode node = this.exts.appendTemplate(_startTrace, _client); - StringBuilder _stringBuilder = new StringBuilder(); - final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); - processor.process(node); + CompositeGeneratorNode node = this.exts.appendTemplate(_trace, _client); + final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(); + final GeneratorNodeProcessor.Result result = processor.process(node); + Assert.assertEquals(this.someCodeGen_noTrace(2).toString(), result.toString()); StringConcatenation _builder = new StringConcatenation(); - _builder.append("before Hello after"); - _builder.newLine(); - _builder.append(" "); - _builder.append("before Hello after"); - _builder.newLine(); - _builder.append(" "); + _builder.append("CompletableTraceRegion [myOffset=0, myLength=80] associations={"); _builder.newLine(); _builder.append(" "); - _builder.append("before Hello after"); + _builder.append("LocationData [TextRegionWithLineInformation [0:100][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); _builder.newLine(); - _builder.append(" "); - _builder.newLine(); - _builder.newLine(); - _builder.append("before Hello after"); - _builder.newLine(); - _builder.append(" "); - _builder.append("before Hello after"); - _builder.newLine(); - _builder.append(" "); + _builder.append("} nestedRegions={"); _builder.newLine(); _builder.append(" "); - _builder.append("before Hello after"); + _builder.append("CompletableTraceRegion [myOffset=7, myLength=5] associations={"); _builder.newLine(); _builder.append(" "); + _builder.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); _builder.newLine(); + _builder.append(" "); + _builder.append("}"); _builder.newLine(); + _builder.append(" "); + _builder.append("CompletableTraceRegion [myOffset=28, myLength=5] associations={"); _builder.newLine(); - Assert.assertEquals(_builder.toString(), processor.getContents().toString()); - StringConcatenation _builder_1 = new StringConcatenation(); - _builder_1.append("CompletableTraceRegion [myOffset=0, myLength=153] associations={"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("LocationData [TextRegionWithLineInformation [0:100][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); - _builder_1.newLine(); - _builder_1.append("} nestedRegions={"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("CompletableTraceRegion [myOffset=7, myLength=5] associations={"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("CompletableTraceRegion [myOffset=30, myLength=5] associations={"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("CompletableTraceRegion [myOffset=58, myLength=5] associations={"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("CompletableTraceRegion [myOffset=83, myLength=5] associations={"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("LocationData [TextRegionWithLineInformation [11:89][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("CompletableTraceRegion [myOffset=106, myLength=5] associations={"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("CompletableTraceRegion [myOffset=134, myLength=5] associations={"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append("}"); - Assert.assertEquals(_builder_1.toString(), processor.getCurrentRegion().toString()); + _builder.append(" "); + _builder.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append("CompletableTraceRegion [myOffset=47, myLength=5] associations={"); + _builder.newLine(); + _builder.append(" "); + _builder.append("LocationData [TextRegionWithLineInformation [11:89][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append("CompletableTraceRegion [myOffset=68, myLength=5] associations={"); + _builder.newLine(); + _builder.append(" "); + _builder.append("LocationData [TextRegionWithLineInformation [10:90][lineNumber=0, endLineNumber=0]][path=foo/mymodel.dsl]"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append("}"); + Assert.assertEquals(_builder.toString(), result.getTraceRegion().toString()); } public StringConcatenationClient someCodeGen(final int n) { @@ -187,7 +139,7 @@ public class GeneratorNodeTest { ExclusiveRange _doubleDotLessThan = new ExclusiveRange(0, n, true); for(final Integer i : _doubleDotLessThan) { _builder.append("before "); - CompositeGeneratorNode _append = GeneratorNodeTest.this.exts.append(GeneratorNodeTest.this.exts.startTrace(GeneratorNodeTest.this.loc((10 + (i).intValue()))), "Hello"); + CompositeGeneratorNode _append = GeneratorNodeTest.this.exts.append(GeneratorNodeTest.this.exts.trace(GeneratorNodeTest.this.loc((10 + (i).intValue()))), "Hello"); _builder.append(_append); _builder.append(" after"); _builder.newLineIfNotEmpty(); @@ -202,6 +154,24 @@ public class GeneratorNodeTest { return _client; } + public String someCodeGen_noTrace(final int n) { + StringConcatenation _builder = new StringConcatenation(); + { + ExclusiveRange _doubleDotLessThan = new ExclusiveRange(0, n, true); + for(final Integer i : _doubleDotLessThan) { + _builder.append("before "); + _builder.append("Hello"); + _builder.append(" after"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _someCodeGen_noTrace = this.someCodeGen_noTrace((n - 1)); + _builder.append(_someCodeGen_noTrace, " "); + _builder.newLineIfNotEmpty(); + } + } + return _builder.toString(); + } + public LocationData loc(final int idx) { SourceRelativeURI _sourceRelativeURI = new SourceRelativeURI("foo/mymodel.dsl"); return new LocationData(idx, (100 - idx), 0, 0, _sourceRelativeURI); diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java index c4ec4dd1d..5dad89cb3 100644 --- a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNodeTest.java @@ -50,17 +50,24 @@ public class TemplateNodeTest { } @Test - public void testString() { + public void testWeirdTemplateString() { StringConcatenationClient _client = new StringConcatenationClient() { @Override protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { _builder.append("fooo bar"); _builder.newLine(); + _builder.append("d "); { if ((2 > 1)) { + _builder.append("s"); + _builder.newLineIfNotEmpty(); + _builder.append("\t "); + _builder.append("ee "); { IntegerRange _upTo = new IntegerRange(1, 4); for(final Integer i : _upTo) { + _builder.newLineIfNotEmpty(); + _builder.newLineIfNotEmpty(); CharSequence _other = TemplateNodeTest.this.other(); _builder.append(_other); _builder.append(" "); @@ -105,13 +112,12 @@ public class TemplateNodeTest { public void assertEquals(final StringConcatenationClient c) { final GeneratorNodeExtensions ext = new GeneratorNodeExtensions(); - StringBuilder _stringBuilder = new StringBuilder(); - final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); + final GeneratorNodeProcessor processor = new GeneratorNodeProcessor(); final CompositeGeneratorNode root = new CompositeGeneratorNode(); ext.appendTemplate(root, c); - processor.process(root); + final GeneratorNodeProcessor.Result result = processor.process(root); final StringConcatenation expected = new StringConcatenation(); expected.append(c); - Assert.assertEquals(expected.toString(), processor.getContents().toString()); + Assert.assertEquals(expected.toString(), result.toString()); } } diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java index 5825bea81..816aeae03 100644 --- a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java @@ -53,7 +53,7 @@ public class TracingSugarTest { */ public IGeneratorNode _type(final Property it, final Function1 provider) { final ILocationData location = this.location(it, it.eClass().getEStructuralFeature("type"), 0); - final CompositeGeneratorNode result = this.startTrace(location); + final CompositeGeneratorNode result = this.trace(location); this.append(result, provider.apply(IterableExtensions.head(it.getType()))); return result; } @@ -61,7 +61,7 @@ public class TracingSugarTest { public IGeneratorNode _name(final Property target) { EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); ILocationData location = this.location(target, feature, -1); - CompositeGeneratorNode trace = this.startTrace(location); + CompositeGeneratorNode trace = this.trace(location); this.append(trace, target.getName()); return trace; } @@ -69,7 +69,7 @@ public class TracingSugarTest { public IGeneratorNode _extends(final Type target, final Function stringProvider) { EStructuralFeature feature = target.eClass().getEStructuralFeature("extends"); ILocationData location = this.location(target, feature, -1); - CompositeGeneratorNode trace = this.startTrace(location); + CompositeGeneratorNode trace = this.trace(location); this.append(trace, stringProvider.apply(target.getExtends())); return trace; } @@ -77,7 +77,7 @@ public class TracingSugarTest { public IGeneratorNode _name(final Type target) { EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); ILocationData location = this.location(target, feature, -1); - CompositeGeneratorNode trace = this.startTrace(location); + CompositeGeneratorNode trace = this.trace(location); this.append(trace, target.getName()); return trace; } @@ -85,7 +85,7 @@ public class TracingSugarTest { public IGeneratorNode _parentId(final Type target, final Function stringProvider) { EStructuralFeature feature = target.eClass().getEStructuralFeature("parentId"); ILocationData location = this.location(target, feature, -1); - CompositeGeneratorNode trace = this.startTrace(location); + CompositeGeneratorNode trace = this.trace(location); this.append(trace, stringProvider.apply(target.getParentId())); return trace; } @@ -93,7 +93,7 @@ public class TracingSugarTest { public IGeneratorNode _name(final UnresolvedProxyProperty target) { EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); ILocationData location = this.location(target, feature, -1); - CompositeGeneratorNode trace = this.startTrace(location); + CompositeGeneratorNode trace = this.trace(location); this.append(trace, target.getName()); return trace; } @@ -203,7 +203,7 @@ public class TracingSugarTest { _builder_2.append("}"); _builder_2.newLine(); _builder_2.append(" "); - _builder_2.append("CompletableTraceRegion [myOffset=30, myLength=23] associations={"); + _builder_2.append("CompletableTraceRegion [myOffset=30, myLength=24] associations={"); _builder_2.newLine(); _builder_2.append(" "); _builder_2.append("LocationData [TextRegionWithLineInformation [27:12][lineNumber=2, endLineNumber=2]][path=__synthetic0.lazylinkingtestlanguage]"); @@ -245,7 +245,7 @@ public class TracingSugarTest { @Traced public IGeneratorNode _generateType(final Type it) { ILocationData _location = this._myExtensions.location(it); - CompositeGeneratorNode _traceNode = this._myExtensions.startTrace(_location); + CompositeGeneratorNode _traceNode = this._myExtensions.trace(_location); this._myExtensions.appendTemplate(_traceNode, __generateType(it)); return _traceNode; } @@ -253,7 +253,7 @@ public class TracingSugarTest { @Traced public IGeneratorNode _generateProperty(final Property it) { ILocationData _location = this._myExtensions.location(it); - CompositeGeneratorNode _traceNode = this._myExtensions.startTrace(_location); + CompositeGeneratorNode _traceNode = this._myExtensions.trace(_location); this._myExtensions.appendTemplate(_traceNode, __generateProperty(it)); return _traceNode; } diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.xtend index 40e990d94..8236afac4 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.xtend @@ -17,4 +17,12 @@ import org.eclipse.xtend.lib.annotations.Accessors val List children = newArrayList + override toString() ''' + «class.simpleName» { + «FOR c: children» + «c.toString» + «ENDFOR» + } + ''' + } \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend index 378ff8c3f..d18b6c795 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend @@ -12,34 +12,87 @@ import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtext.generator.trace.ILocationData /** + * A builder API to create generator node trees + * * @author Sven Efftinge - Initial contribution and API */ class GeneratorNodeExtensions { @Inject WhiteSpaceConfig wsConfig = new WhiteSpaceConfig - def CompositeGeneratorNode startTrace(ILocationData data) { + /** + * @return a root trace node for the given location + */ + def CompositeGeneratorNode trace(ILocationData data) { val result = new TraceNode(data) return result } + /** + * @return a trace node for the given location, appended as a child on the given parent + */ def CompositeGeneratorNode trace(CompositeGeneratorNode parent, ILocationData data) { val result = new TraceNode(data) parent.children += result return result } + /** + * @return an indentation node, using the default indentation string, appended as a child on the given parent + */ def CompositeGeneratorNode indent(CompositeGeneratorNode parent) { - val result = new IndentNode + return indent(parent, wsConfig.indentationString) + } + + /** + * Appends the indentation string at the current position of the parent and adds a new composite node, indicating the same indentation for + * subsequent lines. + * + * @return an indentation node, using the given indentString, appended as a child on the given parent + */ + def CompositeGeneratorNode indent(CompositeGeneratorNode parent, String indentString) { + val text = new TextNode(indentString) + parent.children += text + val result = new IndentNode(indentString) parent.children += result return result } + /** + * Appends a line separator node to the given parent. + * + * @return the given parent node + */ def CompositeGeneratorNode appendNewLine(CompositeGeneratorNode parent) { - parent.children += new NewLineNode + parent.children += new NewLineNode(wsConfig.lineDelimiter, false) return parent } + /** + * Appends a line separator node to the given parent. + * + * @return the given parent node + */ + def CompositeGeneratorNode appendNewLine(CompositeGeneratorNode parent, String lineSeparator) { + parent.children += new NewLineNode(lineSeparator, false) + return parent + } + + /** + * Appends a line separator node that will only be effective if the current line contains non-whitespace text. + * + * @return the given parent node + */ + def CompositeGeneratorNode appendNewLineIfNotEmpty(CompositeGeneratorNode parent) { + parent.children += new NewLineNode(wsConfig.lineDelimiter, true) + return parent + } + /** + * Creates a text node containing the toString() representation of the given object and + * appends it to the given parent node. + * + * @return the given parent node + */ def CompositeGeneratorNode append(CompositeGeneratorNode parent, Object object) { if (object !== null) { parent.children += new TextNode(object.toString) @@ -47,9 +100,18 @@ class GeneratorNodeExtensions { return parent } - def CompositeGeneratorNode appendTemplate(CompositeGeneratorNode parent, StringConcatenationClient contents) { - val proc = new TemplateNode(wsConfig.indentationString, contents, this) + /** + * Creates a template node for the given templateString and appends it to the given parent node. + * + * Templates are translated to generator node trees and expressions in templates can be of type IGeneratorNode. + * + * @return the given parent node + */ + def CompositeGeneratorNode appendTemplate(CompositeGeneratorNode parent, StringConcatenationClient templateString) { + val proc = new TemplateNode(templateString, this) parent.children += proc return parent } + + } \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend index d16080e3e..c99641d4e 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.xtend @@ -7,76 +7,133 @@ *******************************************************************************/ package org.eclipse.xtext.generator.trace.node +import java.util.ArrayDeque +import java.util.Deque +import java.util.List import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtend.lib.annotations.Data import org.eclipse.xtend.lib.annotations.Delegate -import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor import org.eclipse.xtext.generator.trace.AbstractStatefulTraceRegion import org.eclipse.xtext.generator.trace.AbstractTraceRegion import org.eclipse.xtext.generator.trace.ILocationData +import org.eclipse.xtext.generator.trace.ITraceRegionProvider +import org.eclipse.xtext.generator.trace.TraceNotFoundException import org.eclipse.xtext.util.ITextRegionWithLineInformation import org.eclipse.xtext.util.TextRegionWithLineInformation /** * @author Sven Efftinge - Initial contribution and API */ -@FinalFieldsConstructor class GeneratorNodeProcessor { +class GeneratorNodeProcessor { - @Accessors(PUBLIC_GETTER) val StringBuilder contents - val String indentationString - val String newLineString - - int currentIndentLevel = 0 - int currentLine = 0 - @Accessors(PUBLIC_GETTER) AbstractTraceRegion currentRegion = null + @Data static class Result implements CharSequence, ITraceRegionProvider { + @Delegate CharSequence contents + AbstractTraceRegion traceRegion + + override getTraceRegion() throws TraceNotFoundException { + return traceRegion + } + + override toString() { + contents.toString() + } + } - def dispatch void process(IGeneratorNode node) { - throw new IllegalArgumentException("No processing for " + node) + @Accessors protected static class Context { + List lines + Deque currentIndents + boolean pendingIndent + AbstractTraceRegion currentRegion = null + + def StringBuilder currentLine() { + return lines.get(currentLineNumber); + } + + def int contentLength() { + val contentLength = lines.fold(0) [ $0 + $1.length ] + if (pendingIndent) { + return contentLength + currentIndents.fold(0) [ $0 + $1.length ] + } else { + return contentLength + } + } + + def int currentLineNumber() { + return lines.size - 1 + } + } + + def Result process(IGeneratorNode root) { + val ctx = new Context => [ + lines = newArrayList(new StringBuilder()) + currentIndents = new ArrayDeque() + pendingIndent = true + ] + doProcess(root, ctx) + return new Result(ctx.lines.join, ctx.currentRegion); } - def dispatch void process(IndentNode node) { + /** + * Indent nodes apply indentation between newline and content of its children. + */ + protected def dispatch void doProcess(IndentNode node, Context ctx) { try { - this.currentIndentLevel++ - this.contents.append(indentationString) - processChildren(node); + ctx.currentIndents.push(node.indentationString); + doProcessChildren(node, ctx); } finally { - this.currentIndentLevel-- + ctx.currentIndents.pop } } - - def dispatch void process(NewLineNode node) { - currentLine++ - contents.append(newLineString) - for (i : 0 ..< currentIndentLevel) { - contents.append(indentationString) - } - } - - def dispatch void process(TextNode node) { - contents.append(node.text) - } - def dispatch void process(CompositeGeneratorNode node) { - processChildren(node) + protected def dispatch void doProcess(NewLineNode node, Context ctx) { + val trimmedLine = ctx.currentLine.toString.trim + if (node.ifNotEmpty && trimmedLine.empty) { + ctx.lines.set(ctx.currentLineNumber, new StringBuilder()) + return + } + ctx.currentLine.append(node.lineDelimiter) + ctx.lines.add(new StringBuilder) + ctx.pendingIndent = true } - def dispatch void process(TraceNode node) { - val beforeRegion = currentRegion + protected def dispatch void doProcess(TextNode node, Context ctx) { + val txt = node.text.toString + if (txt.empty) { + return; + } + if (ctx.pendingIndent) { + val indentString = new StringBuilder() + for (indentationString : ctx.currentIndents) { + indentString.append(indentationString) + } + ctx.currentLine.insert(0, indentString) + ctx.pendingIndent = false + } + ctx.currentLine.append(node.text) + } + + protected def dispatch void doProcess(CompositeGeneratorNode node, Context ctx) { + doProcessChildren(node, ctx) + } + + protected def dispatch void doProcess(TraceNode node, Context ctx) { + val beforeRegion = ctx.currentRegion val newRegion = new CompletableTraceRegion(false, node.sourceLocation, beforeRegion) - val offset = contents.length - val startLine = currentLine; + val offset = ctx.contentLength + val startLineNumber = ctx.currentLineNumber; try { - currentRegion = newRegion - processChildren(node); + ctx.currentRegion = newRegion + doProcessChildren(node, ctx); } finally { if (beforeRegion !== null) - currentRegion = beforeRegion - newRegion.complete(offset, contents.length - offset, startLine, currentLine) + ctx.currentRegion = beforeRegion + newRegion.complete(offset, ctx.contentLength - offset, startLineNumber, ctx.currentLineNumber) } } - protected def void processChildren(CompositeGeneratorNode node) { + protected def void doProcessChildren(CompositeGeneratorNode node, Context ctx) { for (child : node.children) { - process(child) + doProcess(child, ctx) } } diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend index 8657cbece..df50c9f89 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/IndentNode.xtend @@ -7,11 +7,13 @@ *******************************************************************************/ package org.eclipse.xtext.generator.trace.node -import org.eclipse.xtend.lib.annotations.Data +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor /** * @author Sven Efftinge - Initial contribution and API */ -@Data class IndentNode extends CompositeGeneratorNode { +@FinalFieldsConstructor class IndentNode extends CompositeGeneratorNode { + @Accessors val String indentationString } \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/NewLineNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/NewLineNode.xtend index f731f15bf..4c8a2a741 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/NewLineNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/NewLineNode.xtend @@ -7,9 +7,12 @@ *******************************************************************************/ package org.eclipse.xtext.generator.trace.node +import org.eclipse.xtend.lib.annotations.Data + /** * @author Sven Efftinge - Initial contribution and API */ -class NewLineNode implements IGeneratorNode { - +@Data class NewLineNode implements IGeneratorNode { + String lineDelimiter + boolean ifNotEmpty } \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend index 64fa0c6dc..c160128ea 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TemplateNode.xtend @@ -18,11 +18,9 @@ import org.eclipse.xtend2.lib.StringConcatenationClient.TargetStringConcatenatio */ class TemplateNode extends CompositeGeneratorNode implements TargetStringConcatenation { - val String indentationString val GeneratorNodeExtensions nodeFactory - new(String indentationString, StringConcatenationClient contents, GeneratorNodeExtensions nodeFactory) { - this.indentationString = indentationString + new(StringConcatenationClient contents, GeneratorNodeExtensions nodeFactory) { this.nodeFactory = nodeFactory StringConcatenationClient.appendTo(contents, this) } @@ -31,34 +29,32 @@ class TemplateNode extends CompositeGeneratorNode implements TargetStringConcate boolean isEmptyLine = true; override append(Object object, String indentation) { - val idx = indentation.indexOf(indentationString) - if (idx === 0) { + if (indentation.length > 0) { val before = currentParent try { - currentParent = new IndentNode + currentParent = new IndentNode(indentation) before.children += currentParent - append(object, indentation.substring(indentationString.length)) + append(object) } finally { currentParent = before } + } else { + append(object) } - // TODO check indentation string for consistency - append(object) } - val splitter = Splitter.on(Pattern.compile("\\R")) + val lineSplitter = Splitter.on(Pattern.compile("\\R")) override append(Object object) { switch object { StringConcatenationClient: nodeFactory.appendTemplate(currentParent, object) IGeneratorNode: { - isEmptyLine = isEmptyLine(object) currentParent.children += object } default: { val str = object.toString - val iter = splitter.split(str).iterator + val iter = lineSplitter.split(str).iterator while (iter.hasNext) { val segment = iter.next if (!segment.isEmpty) @@ -72,21 +68,7 @@ class TemplateNode extends CompositeGeneratorNode implements TargetStringConcate } } - private def boolean isEmptyLine(IGeneratorNode n) { - for (leaf : n.leafsBackwards) { - if (leaf instanceof TextNode) { - if (!leaf.text.toString().trim().empty) { - return false - } - } - if (leaf instanceof NewLineNode) { - return true; - } - } - return false; - } - - private def Iterable leafsBackwards(IGeneratorNode it) { + protected def Iterable leafsBackwards(IGeneratorNode it) { switch it { CompositeGeneratorNode : { children.reverseView.map[leafsBackwards].reduce[p1, p2| Iterables.concat(p1, p2)] @@ -110,13 +92,11 @@ class TemplateNode extends CompositeGeneratorNode implements TargetStringConcate } override newLine() { - currentParent.children += new NewLineNode - isEmptyLine = true + this.nodeFactory.appendNewLine(currentParent) } override newLineIfNotEmpty() { - if (!isEmptyLine) - newLine + this.nodeFactory.appendNewLineIfNotEmpty(currentParent) } // diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend index ddde8254f..c9b814fab 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TraceNode.xtend @@ -7,14 +7,15 @@ *******************************************************************************/ package org.eclipse.xtext.generator.trace.node -import org.eclipse.xtend.lib.annotations.Data +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor import org.eclipse.xtext.generator.trace.ILocationData /** * @author Sven Efftinge - initial contribution and API */ -@Data class TraceNode extends CompositeGeneratorNode { +@FinalFieldsConstructor class TraceNode extends CompositeGeneratorNode { - final ILocationData sourceLocation + @Accessors final ILocationData sourceLocation } \ No newline at end of file diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/Traced.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/Traced.xtend index d9fff2135..433756d24 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/Traced.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/Traced.xtend @@ -55,7 +55,7 @@ class TracedProcessor extends AbstractMethodProcessor { annotatedMethod.returnType = nodeType annotatedMethod.body = ''' «ILocationData» _location = this.«field.simpleName».location(«traceParam.simpleName»); - «CompositeGeneratorNode» _traceNode = this.«field.simpleName».startTrace(_location); + «CompositeGeneratorNode» _traceNode = this.«field.simpleName».trace(_location); this.«field.simpleName».appendTemplate(_traceNode, _«annotatedMethod.simpleName»(«annotatedMethod.parameters.join(',')[simpleName]»)); return _traceNode; ''' diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend index 1c873c4bb..81775b634 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend @@ -48,7 +48,7 @@ class TracingExtensionsProcessor extends AbstractClassProcessor { body = ''' «EStructuralFeature» feature = target.eClass().getEStructuralFeature("«getter.featureName»"); «ILocationData» location = this.location(target, feature, -1); - «CompositeGeneratorNode» trace = this.startTrace(location); + «CompositeGeneratorNode» trace = this.trace(location); this.append(trace, target.«getter.declaration.simpleName»()); return trace; ''' @@ -62,7 +62,7 @@ class TracingExtensionsProcessor extends AbstractClassProcessor { body = ''' «EStructuralFeature» feature = target.eClass().getEStructuralFeature("«getter.featureName»"); «ILocationData» location = this.location(target, feature, -1); - «CompositeGeneratorNode» trace = this.startTrace(location); + «CompositeGeneratorNode» trace = this.trace(location); this.append(trace, stringProvider.apply(target.«getter.declaration.simpleName»())); return trace; ''' diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend index fbc2a6636..11aad1da9 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend @@ -2,77 +2,78 @@ package org.eclipse.xtext.generator.trace.node import com.google.inject.Inject import org.eclipse.emf.ecore.EObject -import org.eclipse.xtend.lib.annotations.Data -import org.eclipse.xtend.lib.annotations.Delegate +import org.eclipse.emf.ecore.EStructuralFeature import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtext.generator.IFileSystemAccess2 -import org.eclipse.xtext.generator.trace.AbstractTraceRegion -import org.eclipse.xtext.generator.trace.ITraceRegionProvider +import org.eclipse.xtext.generator.trace.ILocationData import org.eclipse.xtext.generator.trace.ITraceURIConverter import org.eclipse.xtext.generator.trace.LocationData -import org.eclipse.xtext.generator.trace.TraceNotFoundException -import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions -import org.eclipse.xtext.generator.trace.node.IGeneratorNode import org.eclipse.xtext.resource.ILocationInFileProvider import org.eclipse.xtext.util.ITextRegionWithLineInformation -import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor -import org.eclipse.xtext.generator.trace.ILocationData -import org.eclipse.emf.ecore.EStructuralFeature +/** + * Some additional sugar extension to + * - create generator nodes for EObjects + * - create ILocationData for EObjects. + * - enhance FileSystemAccess for tracing + */ class TracingSugar extends GeneratorNodeExtensions { @Inject protected ILocationInFileProvider locationProvider @Inject protected ITraceURIConverter traceURIConverter @Inject protected WhiteSpaceConfig whiteSpaceConfig + /** + * Convenience extension, to generate traced code. + */ def void generateTracedFile(IFileSystemAccess2 fsa, String path, EObject rootTrace, StringConcatenationClient code) { val node = trace(rootTrace, code) - val proc = new GeneratorNodeProcessor(new StringBuilder(), whiteSpaceConfig.indentationString, whiteSpaceConfig.lineDelimiter) - proc.process(node); - fsa.generateFile(path, new Result(proc.contents, proc.currentRegion)) + generateTracedFile(fsa, path, node); } + /** + * Use to generate a file based on generator node. + */ def void generateTracedFile(IFileSystemAccess2 fsa, String path, CompositeGeneratorNode rootNode) { - val proc = new GeneratorNodeProcessor(new StringBuilder(), " ", "\n") - proc.process(rootNode); - fsa.generateFile(path, new Result(proc.contents, proc.currentRegion)) + val proc = new GeneratorNodeProcessor() + val result = proc.process(rootNode); + fsa.generateFile(path, result) } - def IGeneratorNode trace(EObject obj, StringConcatenationClient code) { - val region = locationProvider.getFullTextRegion(obj) - val uri = traceURIConverter.getURIForTrace(obj.eResource) - val location = new LocationData(region as ITextRegionWithLineInformation, uri); - return location.startTrace.appendTemplate(code) + /** + * Convenience shorthand for obj.location.trace + */ + def CompositeGeneratorNode trace(EObject obj) { + return obj.location.trace; } - def IGeneratorNode trace(T obj, (T)=>String code) { - val string = code.apply(obj); - val location = location(obj); - return location.startTrace.append(string) + /** + * Convenience shorthand for obj.trace.appendTemplate('''some template''') + */ + def CompositeGeneratorNode trace(EObject obj, StringConcatenationClient code) { + return obj.trace.appendTemplate(code) } + /** + * @return ILocationData covering the fullTextRegion of the given EObject. + */ def ILocationData location(EObject obj) { val region = locationProvider.getFullTextRegion(obj) val uri = traceURIConverter.getURIForTrace(obj.eResource) return new LocationData(region as ITextRegionWithLineInformation, uri); } + /** + * @param obj the EObject containing the feature + * @param feature the EStructuralFeature to trace + * @param idx the index of the value to trace, in case the feature contains a list, should be -1 otherwise. + * + * @return ILocationData covering the fullTextRegion of the given feature in the given EObject. + */ def ILocationData location(EObject obj, EStructuralFeature feature, int idx) { val region = locationProvider.getFullTextRegion(obj, feature, idx) val uri = traceURIConverter.getURIForTrace(obj.eResource) return new LocationData(region as ITextRegionWithLineInformation, uri); } - @Data static class Result implements CharSequence, ITraceRegionProvider { - @Delegate CharSequence contents - AbstractTraceRegion traceRegion - - override getTraceRegion() throws TraceNotFoundException { - return traceRegion - } - - override toString() { - contents.toString() - } - } } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.java index a8963f3d5..783711c9e 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/CompositeGeneratorNode.java @@ -9,6 +9,7 @@ package org.eclipse.xtext.generator.trace.node; import java.util.List; import org.eclipse.xtend.lib.annotations.Accessors; +import org.eclipse.xtend2.lib.StringConcatenation; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.xbase.lib.CollectionLiterals; import org.eclipse.xtext.xbase.lib.Pure; @@ -21,6 +22,26 @@ import org.eclipse.xtext.xbase.lib.Pure; public class CompositeGeneratorNode implements IGeneratorNode { private final List children = CollectionLiterals.newArrayList(); + @Override + public String toString() { + StringConcatenation _builder = new StringConcatenation(); + String _simpleName = this.getClass().getSimpleName(); + _builder.append(_simpleName); + _builder.append(" {"); + _builder.newLineIfNotEmpty(); + { + for(final IGeneratorNode c : this.children) { + _builder.append("\t"); + String _string = c.toString(); + _builder.append(_string, "\t"); + _builder.newLineIfNotEmpty(); + } + } + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } + @Pure public List getChildren() { return this.children; diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java index 90e564a4b..cb80bfb3a 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java @@ -21,6 +21,8 @@ import org.eclipse.xtext.generator.trace.node.TraceNode; import org.eclipse.xtext.generator.trace.node.WhiteSpaceConfig; /** + * A builder API to create generator node trees + * * @author Sven Efftinge - Initial contribution and API */ @SuppressWarnings("all") @@ -28,11 +30,17 @@ public class GeneratorNodeExtensions { @Inject private WhiteSpaceConfig wsConfig = new WhiteSpaceConfig(); - public CompositeGeneratorNode startTrace(final ILocationData data) { + /** + * @return a root trace node for the given location + */ + public CompositeGeneratorNode trace(final ILocationData data) { final TraceNode result = new TraceNode(data); return result; } + /** + * @return a trace node for the given location, appended as a child on the given parent + */ public CompositeGeneratorNode trace(final CompositeGeneratorNode parent, final ILocationData data) { final TraceNode result = new TraceNode(data); List _children = parent.getChildren(); @@ -40,20 +48,73 @@ public class GeneratorNodeExtensions { return result; } + /** + * @return an indentation node, using the default indentation string, appended as a child on the given parent + */ public CompositeGeneratorNode indent(final CompositeGeneratorNode parent) { - final IndentNode result = new IndentNode(); + return this.indent(parent, this.wsConfig.getIndentationString()); + } + + /** + * Appends the indentation string at the current position of the parent and adds a new composite node, indicating the same indentation for + * subsequent lines. + * + * @return an indentation node, using the given indentString, appended as a child on the given parent + */ + public CompositeGeneratorNode indent(final CompositeGeneratorNode parent, final String indentString) { + final TextNode text = new TextNode(indentString); List _children = parent.getChildren(); - _children.add(result); + _children.add(text); + final IndentNode result = new IndentNode(indentString); + List _children_1 = parent.getChildren(); + _children_1.add(result); return result; } + /** + * Appends a line separator node to the given parent. + * + * @return the given parent node + */ public CompositeGeneratorNode appendNewLine(final CompositeGeneratorNode parent) { List _children = parent.getChildren(); - NewLineNode _newLineNode = new NewLineNode(); + String _lineDelimiter = this.wsConfig.getLineDelimiter(); + NewLineNode _newLineNode = new NewLineNode(_lineDelimiter, false); _children.add(_newLineNode); return parent; } + /** + * Appends a line separator node to the given parent. + * + * @return the given parent node + */ + public CompositeGeneratorNode appendNewLine(final CompositeGeneratorNode parent, final String lineSeparator) { + List _children = parent.getChildren(); + NewLineNode _newLineNode = new NewLineNode(lineSeparator, false); + _children.add(_newLineNode); + return parent; + } + + /** + * Appends a line separator node that will only be effective if the current line contains non-whitespace text. + * + * @return the given parent node + */ + public CompositeGeneratorNode appendNewLineIfNotEmpty(final CompositeGeneratorNode parent) { + List _children = parent.getChildren(); + String _lineDelimiter = this.wsConfig.getLineDelimiter(); + NewLineNode _newLineNode = new NewLineNode(_lineDelimiter, true); + _children.add(_newLineNode); + return parent; + } + + /** + * Creates a text node containing the toString() representation of the given object and + * appends it to the given parent node. + * + * @return the given parent node + */ public CompositeGeneratorNode append(final CompositeGeneratorNode parent, final Object object) { if ((object != null)) { List _children = parent.getChildren(); @@ -64,9 +125,15 @@ public class GeneratorNodeExtensions { return parent; } - public CompositeGeneratorNode appendTemplate(final CompositeGeneratorNode parent, final StringConcatenationClient contents) { - String _indentationString = this.wsConfig.getIndentationString(); - final TemplateNode proc = new TemplateNode(_indentationString, contents, this); + /** + * Creates a template node for the given templateString and appends it to the given parent node. + * + * Templates are translated to generator node trees and expressions in templates can be of type IGeneratorNode. + * + * @return the given parent node + */ + public CompositeGeneratorNode appendTemplate(final CompositeGeneratorNode parent, final StringConcatenationClient templateString) { + final TemplateNode proc = new TemplateNode(templateString, this); List _children = parent.getChildren(); _children.add(proc); return parent; diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java index 9fc62309c..875eb03b2 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeProcessor.java @@ -7,15 +7,19 @@ */ package org.eclipse.xtext.generator.trace.node; +import java.util.ArrayDeque; import java.util.Arrays; +import java.util.Deque; import java.util.List; -import org.eclipse.xtend.lib.annotations.AccessorType; +import java.util.stream.IntStream; import org.eclipse.xtend.lib.annotations.Accessors; +import org.eclipse.xtend.lib.annotations.Data; import org.eclipse.xtend.lib.annotations.Delegate; -import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor; import org.eclipse.xtext.generator.trace.AbstractStatefulTraceRegion; import org.eclipse.xtext.generator.trace.AbstractTraceRegion; import org.eclipse.xtext.generator.trace.ILocationData; +import org.eclipse.xtext.generator.trace.ITraceRegionProvider; +import org.eclipse.xtext.generator.trace.TraceNotFoundException; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.IndentNode; @@ -25,15 +29,174 @@ import org.eclipse.xtext.generator.trace.node.TraceNode; import org.eclipse.xtext.util.ITextRegion; import org.eclipse.xtext.util.ITextRegionWithLineInformation; import org.eclipse.xtext.util.TextRegionWithLineInformation; -import org.eclipse.xtext.xbase.lib.ExclusiveRange; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.Functions.Function2; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.ObjectExtensions; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; import org.eclipse.xtext.xbase.lib.Pure; /** * @author Sven Efftinge - Initial contribution and API */ -@FinalFieldsConstructor @SuppressWarnings("all") public class GeneratorNodeProcessor { + @Data + public static class Result implements CharSequence, ITraceRegionProvider { + @Delegate + private final CharSequence contents; + + private final AbstractTraceRegion traceRegion; + + @Override + public AbstractTraceRegion getTraceRegion() throws TraceNotFoundException { + return this.traceRegion; + } + + @Override + public String toString() { + return this.contents.toString(); + } + + public Result(final CharSequence contents, final AbstractTraceRegion traceRegion) { + super(); + this.contents = contents; + this.traceRegion = traceRegion; + } + + @Override + @Pure + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.contents== null) ? 0 : this.contents.hashCode()); + result = prime * result + ((this.traceRegion== null) ? 0 : this.traceRegion.hashCode()); + return result; + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + GeneratorNodeProcessor.Result other = (GeneratorNodeProcessor.Result) obj; + if (this.contents == null) { + if (other.contents != null) + return false; + } else if (!this.contents.equals(other.contents)) + return false; + if (this.traceRegion == null) { + if (other.traceRegion != null) + return false; + } else if (!this.traceRegion.equals(other.traceRegion)) + return false; + return true; + } + + @Pure + public CharSequence getContents() { + return this.contents; + } + + public char charAt(final int index) { + return this.contents.charAt(index); + } + + public IntStream chars() { + return this.contents.chars(); + } + + public IntStream codePoints() { + return this.contents.codePoints(); + } + + public int length() { + return this.contents.length(); + } + + public CharSequence subSequence(final int start, final int end) { + return this.contents.subSequence(start, end); + } + } + + @Accessors + protected static class Context { + private List lines; + + private Deque currentIndents; + + private boolean pendingIndent; + + private AbstractTraceRegion currentRegion = null; + + public StringBuilder currentLine() { + return this.lines.get(this.currentLineNumber()); + } + + public int contentLength() { + final Function2 _function = (Integer $0, StringBuilder $1) -> { + int _length = $1.length(); + return Integer.valueOf((($0).intValue() + _length)); + }; + final Integer contentLength = IterableExtensions.fold(this.lines, Integer.valueOf(0), _function); + if (this.pendingIndent) { + final Function2 _function_1 = (Integer $0, String $1) -> { + int _length = $1.length(); + return Integer.valueOf((($0).intValue() + _length)); + }; + Integer _fold = IterableExtensions.fold(this.currentIndents, Integer.valueOf(0), _function_1); + return ((contentLength).intValue() + (_fold).intValue()); + } else { + return (contentLength).intValue(); + } + } + + public int currentLineNumber() { + int _size = this.lines.size(); + return (_size - 1); + } + + @Pure + public List getLines() { + return this.lines; + } + + public void setLines(final List lines) { + this.lines = lines; + } + + @Pure + public Deque getCurrentIndents() { + return this.currentIndents; + } + + public void setCurrentIndents(final Deque currentIndents) { + this.currentIndents = currentIndents; + } + + @Pure + public boolean isPendingIndent() { + return this.pendingIndent; + } + + public void setPendingIndent(final boolean pendingIndent) { + this.pendingIndent = pendingIndent; + } + + @Pure + public AbstractTraceRegion getCurrentRegion() { + return this.currentRegion; + } + + public void setCurrentRegion(final AbstractTraceRegion currentRegion) { + this.currentRegion = currentRegion; + } + } + /** * Used to avoid multi-pass processing, when constructing a trace region tree. * @@ -106,116 +269,113 @@ public class GeneratorNodeProcessor { } } - @Accessors(AccessorType.PUBLIC_GETTER) - private final StringBuilder contents; - - private final String indentationString; - - private final String newLineString; - - private int currentIndentLevel = 0; - - private int currentLine = 0; - - @Accessors(AccessorType.PUBLIC_GETTER) - private AbstractTraceRegion currentRegion = null; - - protected void _process(final IGeneratorNode node) { - throw new IllegalArgumentException(("No processing for " + node)); + public GeneratorNodeProcessor.Result process(final IGeneratorNode root) { + GeneratorNodeProcessor.Context _context = new GeneratorNodeProcessor.Context(); + final Procedure1 _function = (GeneratorNodeProcessor.Context it) -> { + StringBuilder _stringBuilder = new StringBuilder(); + it.lines = CollectionLiterals.newArrayList(_stringBuilder); + ArrayDeque _arrayDeque = new ArrayDeque(); + it.currentIndents = _arrayDeque; + it.pendingIndent = true; + }; + final GeneratorNodeProcessor.Context ctx = ObjectExtensions.operator_doubleArrow(_context, _function); + this.doProcess(root, ctx); + String _join = IterableExtensions.join(ctx.lines); + return new GeneratorNodeProcessor.Result(_join, ctx.currentRegion); } - protected void _process(final IndentNode node) { + /** + * Indent nodes apply indentation between newline and content of its children. + */ + protected void _doProcess(final IndentNode node, final GeneratorNodeProcessor.Context ctx) { try { - this.currentIndentLevel++; - this.contents.append(this.indentationString); - this.processChildren(node); + ctx.currentIndents.push(node.getIndentationString()); + this.doProcessChildren(node, ctx); } finally { - this.currentIndentLevel--; + ctx.currentIndents.pop(); } } - protected void _process(final NewLineNode node) { - this.currentLine++; - this.contents.append(this.newLineString); - ExclusiveRange _doubleDotLessThan = new ExclusiveRange(0, this.currentIndentLevel, true); - for (final Integer i : _doubleDotLessThan) { - this.contents.append(this.indentationString); + protected void _doProcess(final NewLineNode node, final GeneratorNodeProcessor.Context ctx) { + final String trimmedLine = ctx.currentLine().toString().trim(); + if ((node.isIfNotEmpty() && trimmedLine.isEmpty())) { + int _currentLineNumber = ctx.currentLineNumber(); + StringBuilder _stringBuilder = new StringBuilder(); + ctx.lines.set(_currentLineNumber, _stringBuilder); + return; } + ctx.currentLine().append(node.getLineDelimiter()); + StringBuilder _stringBuilder_1 = new StringBuilder(); + ctx.lines.add(_stringBuilder_1); + ctx.pendingIndent = true; } - protected void _process(final TextNode node) { - this.contents.append(node.getText()); + protected void _doProcess(final TextNode node, final GeneratorNodeProcessor.Context ctx) { + final String txt = node.getText().toString(); + boolean _isEmpty = txt.isEmpty(); + if (_isEmpty) { + return; + } + if (ctx.pendingIndent) { + final StringBuilder indentString = new StringBuilder(); + for (final String indentationString : ctx.currentIndents) { + indentString.append(indentationString); + } + ctx.currentLine().insert(0, indentString); + ctx.pendingIndent = false; + } + ctx.currentLine().append(node.getText()); } - protected void _process(final CompositeGeneratorNode node) { - this.processChildren(node); + protected void _doProcess(final CompositeGeneratorNode node, final GeneratorNodeProcessor.Context ctx) { + this.doProcessChildren(node, ctx); } - protected void _process(final TraceNode node) { - final AbstractTraceRegion beforeRegion = this.currentRegion; + protected void _doProcess(final TraceNode node, final GeneratorNodeProcessor.Context ctx) { + final AbstractTraceRegion beforeRegion = ctx.currentRegion; ILocationData _sourceLocation = node.getSourceLocation(); final GeneratorNodeProcessor.CompletableTraceRegion newRegion = new GeneratorNodeProcessor.CompletableTraceRegion(false, _sourceLocation, beforeRegion); - final int offset = this.contents.length(); - final int startLine = this.currentLine; + final int offset = ctx.contentLength(); + final int startLineNumber = ctx.currentLineNumber(); try { - this.currentRegion = newRegion; - this.processChildren(node); + ctx.currentRegion = newRegion; + this.doProcessChildren(node, ctx); } finally { if ((beforeRegion != null)) { - this.currentRegion = beforeRegion; + ctx.currentRegion = beforeRegion; } - int _length = this.contents.length(); - int _minus = (_length - offset); - newRegion.complete(offset, _minus, startLine, this.currentLine); + int _contentLength = ctx.contentLength(); + int _minus = (_contentLength - offset); + newRegion.complete(offset, _minus, startLineNumber, ctx.currentLineNumber()); } } - protected void processChildren(final CompositeGeneratorNode node) { + protected void doProcessChildren(final CompositeGeneratorNode node, final GeneratorNodeProcessor.Context ctx) { List _children = node.getChildren(); for (final IGeneratorNode child : _children) { - this.process(child); + this.doProcess(child, ctx); } } - public void process(final IGeneratorNode node) { + protected void doProcess(final IGeneratorNode node, final GeneratorNodeProcessor.Context ctx) { if (node instanceof IndentNode) { - _process((IndentNode)node); + _doProcess((IndentNode)node, ctx); return; } else if (node instanceof TraceNode) { - _process((TraceNode)node); + _doProcess((TraceNode)node, ctx); return; } else if (node instanceof CompositeGeneratorNode) { - _process((CompositeGeneratorNode)node); + _doProcess((CompositeGeneratorNode)node, ctx); return; } else if (node instanceof NewLineNode) { - _process((NewLineNode)node); + _doProcess((NewLineNode)node, ctx); return; } else if (node instanceof TextNode) { - _process((TextNode)node); - return; - } else if (node != null) { - _process(node); + _doProcess((TextNode)node, ctx); return; } else { throw new IllegalArgumentException("Unhandled parameter types: " + - Arrays.asList(node).toString()); + Arrays.asList(node, ctx).toString()); } } - - public GeneratorNodeProcessor(final StringBuilder contents, final String indentationString, final String newLineString) { - super(); - this.contents = contents; - this.indentationString = indentationString; - this.newLineString = newLineString; - } - - @Pure - public StringBuilder getContents() { - return this.contents; - } - - @Pure - public AbstractTraceRegion getCurrentRegion() { - return this.currentRegion; - } } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java index 932a75fdf..40c1b10d8 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/IndentNode.java @@ -7,42 +7,27 @@ */ package org.eclipse.xtext.generator.trace.node; -import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtend.lib.annotations.Accessors; +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.xbase.lib.Pure; -import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; /** * @author Sven Efftinge - Initial contribution and API */ -@Data +@FinalFieldsConstructor @SuppressWarnings("all") public class IndentNode extends CompositeGeneratorNode { - @Override - @Pure - public int hashCode() { - int result = 1; - return result; + @Accessors + private final String indentationString; + + public IndentNode(final String indentationString) { + super(); + this.indentationString = indentationString; } - @Override @Pure - public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - return true; - } - - @Override - @Pure - public String toString() { - String result = new ToStringBuilder(this) - .addAllFields() - .toString(); - return result; + public String getIndentationString() { + return this.indentationString; } } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/NewLineNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/NewLineNode.java index cd10ac188..7afc35327 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/NewLineNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/NewLineNode.java @@ -7,11 +7,73 @@ */ package org.eclipse.xtext.generator.trace.node; +import org.eclipse.xtend.lib.annotations.Data; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; +import org.eclipse.xtext.xbase.lib.Pure; +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; /** * @author Sven Efftinge - Initial contribution and API */ +@Data @SuppressWarnings("all") public class NewLineNode implements IGeneratorNode { + private final String lineDelimiter; + + private final boolean ifNotEmpty; + + public NewLineNode(final String lineDelimiter, final boolean ifNotEmpty) { + super(); + this.lineDelimiter = lineDelimiter; + this.ifNotEmpty = ifNotEmpty; + } + + @Override + @Pure + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.lineDelimiter== null) ? 0 : this.lineDelimiter.hashCode()); + result = prime * result + (this.ifNotEmpty ? 1231 : 1237); + return result; + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + NewLineNode other = (NewLineNode) obj; + if (this.lineDelimiter == null) { + if (other.lineDelimiter != null) + return false; + } else if (!this.lineDelimiter.equals(other.lineDelimiter)) + return false; + if (other.ifNotEmpty != this.ifNotEmpty) + return false; + return true; + } + + @Override + @Pure + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("lineDelimiter", this.lineDelimiter); + b.add("ifNotEmpty", this.ifNotEmpty); + return b.toString(); + } + + @Pure + public String getLineDelimiter() { + return this.lineDelimiter; + } + + @Pure + public boolean isIfNotEmpty() { + return this.ifNotEmpty; + } } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java index 6729f75c4..456bdc913 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TemplateNode.java @@ -18,7 +18,6 @@ import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.IndentNode; -import org.eclipse.xtext.generator.trace.node.NewLineNode; import org.eclipse.xtext.generator.trace.node.TextNode; import org.eclipse.xtext.xbase.lib.CollectionLiterals; import org.eclipse.xtext.xbase.lib.Functions.Function1; @@ -31,12 +30,9 @@ import org.eclipse.xtext.xbase.lib.ListExtensions; */ @SuppressWarnings("all") public class TemplateNode extends CompositeGeneratorNode implements StringConcatenationClient.TargetStringConcatenation { - private final String indentationString; - private final GeneratorNodeExtensions nodeFactory; - public TemplateNode(final String indentationString, final StringConcatenationClient contents, final GeneratorNodeExtensions nodeFactory) { - this.indentationString = indentationString; + public TemplateNode(final StringConcatenationClient contents, final GeneratorNodeExtensions nodeFactory) { this.nodeFactory = nodeFactory; StringConcatenationClient.appendTo(contents, this); } @@ -47,23 +43,25 @@ public class TemplateNode extends CompositeGeneratorNode implements StringConcat @Override public void append(final Object object, final String indentation) { - final int idx = indentation.indexOf(this.indentationString); - if ((idx == 0)) { + int _length = indentation.length(); + boolean _greaterThan = (_length > 0); + if (_greaterThan) { final CompositeGeneratorNode before = this.currentParent; try { - IndentNode _indentNode = new IndentNode(); + IndentNode _indentNode = new IndentNode(indentation); this.currentParent = _indentNode; List _children = before.getChildren(); _children.add(this.currentParent); - this.append(object, indentation.substring(this.indentationString.length())); + this.append(object); } finally { this.currentParent = before; } + } else { + this.append(object); } - this.append(object); } - private final Splitter splitter = Splitter.on(Pattern.compile("\\R")); + private final Splitter lineSplitter = Splitter.on(Pattern.compile("\\R")); @Override public void append(final Object object) { @@ -75,7 +73,6 @@ public class TemplateNode extends CompositeGeneratorNode implements StringConcat if (!_matched) { if (object instanceof IGeneratorNode) { _matched=true; - this.isEmptyLine = this.isEmptyLine(((IGeneratorNode)object)); List _children = this.currentParent.getChildren(); _children.add(((IGeneratorNode)object)); } @@ -83,7 +80,7 @@ public class TemplateNode extends CompositeGeneratorNode implements StringConcat if (!_matched) { { final String str = object.toString(); - final Iterator iter = this.splitter.split(str).iterator(); + final Iterator iter = this.lineSplitter.split(str).iterator(); while (iter.hasNext()) { { final String segment = iter.next(); @@ -103,26 +100,7 @@ public class TemplateNode extends CompositeGeneratorNode implements StringConcat } } - private boolean isEmptyLine(final IGeneratorNode n) { - Iterable _leafsBackwards = this.leafsBackwards(n); - for (final IGeneratorNode leaf : _leafsBackwards) { - { - if ((leaf instanceof TextNode)) { - boolean _isEmpty = ((TextNode)leaf).getText().toString().trim().isEmpty(); - boolean _not = (!_isEmpty); - if (_not) { - return false; - } - } - if ((leaf instanceof NewLineNode)) { - return true; - } - } - } - return false; - } - - private Iterable leafsBackwards(final IGeneratorNode it) { + protected Iterable leafsBackwards(final IGeneratorNode it) { Iterable _switchResult = null; boolean _matched = false; if (it instanceof CompositeGeneratorNode) { @@ -160,17 +138,12 @@ public class TemplateNode extends CompositeGeneratorNode implements StringConcat @Override public void newLine() { - List _children = this.currentParent.getChildren(); - NewLineNode _newLineNode = new NewLineNode(); - _children.add(_newLineNode); - this.isEmptyLine = true; + this.nodeFactory.appendNewLine(this.currentParent); } @Override public void newLineIfNotEmpty() { - if ((!this.isEmptyLine)) { - this.newLine(); - } + this.nodeFactory.appendNewLineIfNotEmpty(this.currentParent); } @Override diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java index 9a371e7b8..fd364de74 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TraceNode.java @@ -7,18 +7,19 @@ */ package org.eclipse.xtext.generator.trace.node; -import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtend.lib.annotations.Accessors; +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor; import org.eclipse.xtext.generator.trace.ILocationData; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.xbase.lib.Pure; -import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; /** * @author Sven Efftinge - initial contribution and API */ -@Data +@FinalFieldsConstructor @SuppressWarnings("all") public class TraceNode extends CompositeGeneratorNode { + @Accessors private final ILocationData sourceLocation; public TraceNode(final ILocationData sourceLocation) { @@ -26,42 +27,6 @@ public class TraceNode extends CompositeGeneratorNode { this.sourceLocation = sourceLocation; } - @Override - @Pure - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((this.sourceLocation== null) ? 0 : this.sourceLocation.hashCode()); - return result; - } - - @Override - @Pure - public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - TraceNode other = (TraceNode) obj; - if (this.sourceLocation == null) { - if (other.sourceLocation != null) - return false; - } else if (!this.sourceLocation.equals(other.sourceLocation)) - return false; - return true; - } - - @Override - @Pure - public String toString() { - String result = new ToStringBuilder(this) - .addAllFields() - .toString(); - return result; - } - @Pure public ILocationData getSourceLocation() { return this.sourceLocation; diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedProcessor.java index 0fe34a026..88a335422 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedProcessor.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedProcessor.java @@ -95,7 +95,7 @@ public class TracedProcessor extends AbstractMethodProcessor { _builder.append(" _traceNode = this."); String _simpleName_2 = field.getSimpleName(); _builder.append(_simpleName_2); - _builder.append(".startTrace(_location);"); + _builder.append(".trace(_location);"); _builder.newLineIfNotEmpty(); _builder.append("this."); String _simpleName_3 = field.getSimpleName(); diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java index 4623c4ea9..51d545361 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java @@ -93,7 +93,7 @@ public class TracingExtensionsProcessor extends AbstractClassProcessor { _builder.append(" location = this.location(target, feature, -1);"); _builder.newLineIfNotEmpty(); _builder.append(CompositeGeneratorNode.class); - _builder.append(" trace = this.startTrace(location);"); + _builder.append(" trace = this.trace(location);"); _builder.newLineIfNotEmpty(); _builder.append("this.append(trace, target."); String _simpleName = getter.getDeclaration().getSimpleName(); @@ -128,7 +128,7 @@ public class TracingExtensionsProcessor extends AbstractClassProcessor { _builder.append(" location = this.location(target, feature, -1);"); _builder.newLineIfNotEmpty(); _builder.append(CompositeGeneratorNode.class); - _builder.append(" trace = this.startTrace(location);"); + _builder.append(" trace = this.trace(location);"); _builder.newLineIfNotEmpty(); _builder.append("this.append(trace, stringProvider.apply(target."); String _simpleName = getter.getDeclaration().getSimpleName(); diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java index 4e8fb589a..5a3d4aaa6 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java @@ -1,115 +1,30 @@ package org.eclipse.xtext.generator.trace.node; import com.google.inject.Inject; -import java.util.stream.IntStream; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.xtend.lib.annotations.Data; -import org.eclipse.xtend.lib.annotations.Delegate; import org.eclipse.xtend2.lib.StringConcatenationClient; import org.eclipse.xtext.generator.IFileSystemAccess2; -import org.eclipse.xtext.generator.trace.AbstractTraceRegion; import org.eclipse.xtext.generator.trace.ILocationData; -import org.eclipse.xtext.generator.trace.ITraceRegionProvider; import org.eclipse.xtext.generator.trace.ITraceURIConverter; import org.eclipse.xtext.generator.trace.LocationData; import org.eclipse.xtext.generator.trace.SourceRelativeURI; -import org.eclipse.xtext.generator.trace.TraceNotFoundException; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor; -import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.WhiteSpaceConfig; import org.eclipse.xtext.resource.ILocationInFileProvider; import org.eclipse.xtext.util.ITextRegion; import org.eclipse.xtext.util.ITextRegionWithLineInformation; -import org.eclipse.xtext.xbase.lib.Functions.Function1; -import org.eclipse.xtext.xbase.lib.Pure; +/** + * Some additional sugar extension to + * - create generator nodes for EObjects + * - create ILocationData for EObjects. + * - enhance FileSystemAccess for tracing + */ @SuppressWarnings("all") public class TracingSugar extends GeneratorNodeExtensions { - @Data - public static class Result implements CharSequence, ITraceRegionProvider { - @Delegate - private final CharSequence contents; - - private final AbstractTraceRegion traceRegion; - - @Override - public AbstractTraceRegion getTraceRegion() throws TraceNotFoundException { - return this.traceRegion; - } - - @Override - public String toString() { - return this.contents.toString(); - } - - public Result(final CharSequence contents, final AbstractTraceRegion traceRegion) { - super(); - this.contents = contents; - this.traceRegion = traceRegion; - } - - @Override - @Pure - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((this.contents== null) ? 0 : this.contents.hashCode()); - result = prime * result + ((this.traceRegion== null) ? 0 : this.traceRegion.hashCode()); - return result; - } - - @Override - @Pure - public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - TracingSugar.Result other = (TracingSugar.Result) obj; - if (this.contents == null) { - if (other.contents != null) - return false; - } else if (!this.contents.equals(other.contents)) - return false; - if (this.traceRegion == null) { - if (other.traceRegion != null) - return false; - } else if (!this.traceRegion.equals(other.traceRegion)) - return false; - return true; - } - - @Pure - public CharSequence getContents() { - return this.contents; - } - - public char charAt(final int index) { - return this.contents.charAt(index); - } - - public IntStream chars() { - return this.contents.chars(); - } - - public IntStream codePoints() { - return this.contents.codePoints(); - } - - public int length() { - return this.contents.length(); - } - - public CharSequence subSequence(final int start, final int end) { - return this.contents.subSequence(start, end); - } - } - @Inject protected ILocationInFileProvider locationProvider; @@ -119,48 +34,53 @@ public class TracingSugar extends GeneratorNodeExtensions { @Inject protected WhiteSpaceConfig whiteSpaceConfig; + /** + * Convenience extension, to generate traced code. + */ public void generateTracedFile(final IFileSystemAccess2 fsa, final String path, final EObject rootTrace, final StringConcatenationClient code) { - final IGeneratorNode node = this.trace(rootTrace, code); - StringBuilder _stringBuilder = new StringBuilder(); - String _indentationString = this.whiteSpaceConfig.getIndentationString(); - String _lineDelimiter = this.whiteSpaceConfig.getLineDelimiter(); - final GeneratorNodeProcessor proc = new GeneratorNodeProcessor(_stringBuilder, _indentationString, _lineDelimiter); - proc.process(node); - StringBuilder _contents = proc.getContents(); - AbstractTraceRegion _currentRegion = proc.getCurrentRegion(); - TracingSugar.Result _result = new TracingSugar.Result(_contents, _currentRegion); - fsa.generateFile(path, _result); + final CompositeGeneratorNode node = this.trace(rootTrace, code); + this.generateTracedFile(fsa, path, node); } + /** + * Use to generate a file based on generator node. + */ public void generateTracedFile(final IFileSystemAccess2 fsa, final String path, final CompositeGeneratorNode rootNode) { - StringBuilder _stringBuilder = new StringBuilder(); - final GeneratorNodeProcessor proc = new GeneratorNodeProcessor(_stringBuilder, " ", "\n"); - proc.process(rootNode); - StringBuilder _contents = proc.getContents(); - AbstractTraceRegion _currentRegion = proc.getCurrentRegion(); - TracingSugar.Result _result = new TracingSugar.Result(_contents, _currentRegion); - fsa.generateFile(path, _result); + final GeneratorNodeProcessor proc = new GeneratorNodeProcessor(); + final GeneratorNodeProcessor.Result result = proc.process(rootNode); + fsa.generateFile(path, result); } - public IGeneratorNode trace(final EObject obj, final StringConcatenationClient code) { - final ITextRegion region = this.locationProvider.getFullTextRegion(obj); - final SourceRelativeURI uri = this.traceURIConverter.getURIForTrace(obj.eResource()); - final LocationData location = new LocationData(((ITextRegionWithLineInformation) region), uri); - return this.appendTemplate(this.startTrace(location), code); + /** + * Convenience shorthand for obj.location.trace + */ + public CompositeGeneratorNode trace(final EObject obj) { + return this.trace(this.location(obj)); } - public IGeneratorNode trace(final T obj, final Function1 code) { - final String string = code.apply(obj); - final ILocationData location = this.location(obj); - return this.append(this.startTrace(location), string); + /** + * Convenience shorthand for obj.trace.appendTemplate('''some template''') + */ + public CompositeGeneratorNode trace(final EObject obj, final StringConcatenationClient code) { + return this.appendTemplate(this.trace(obj), code); } + /** + * @return ILocationData covering the fullTextRegion of the given EObject. + */ public ILocationData location(final EObject obj) { final ITextRegion region = this.locationProvider.getFullTextRegion(obj); final SourceRelativeURI uri = this.traceURIConverter.getURIForTrace(obj.eResource()); return new LocationData(((ITextRegionWithLineInformation) region), uri); } + /** + * @param obj the EObject containing the feature + * @param feature the EStructuralFeature to trace + * @param idx the index of the value to trace, in case the feature contains a list, should be -1 otherwise. + * + * @return ILocationData covering the fullTextRegion of the given feature in the given EObject. + */ public ILocationData location(final EObject obj, final EStructuralFeature feature, final int idx) { final ITextRegion region = this.locationProvider.getFullTextRegion(obj, feature, idx); final SourceRelativeURI uri = this.traceURIConverter.getURIForTrace(obj.eResource()); From 0ac49cb58c3da42a723585b259eb279e3477b42e Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Mon, 27 Feb 2017 16:34:50 +0100 Subject: [PATCH 5/5] =?UTF-8?q?[tracing]=20changes=20regarding=20moritz?= =?UTF-8?q?=E2=80=99=20feedback=20(fixes=20#287)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trace/node/TracingSugarTest.xtend | 2 +- .../trace/node/TracingSugarTest.java | 60 ++++++++++- org.eclipse.xtext/META-INF/MANIFEST.MF | 2 +- .../trace/node/GeneratorNodeExtensions.xtend | 2 +- ....xtend => GeneratorWhiteSpaceConfig.xtend} | 2 +- ...Extensions.xtend => TracedAccessors.xtend} | 50 +++++----- .../generator/trace/node/TracingSugar.xtend | 6 +- .../trace/node/GeneratorNodeExtensions.java | 4 +- ...ig.java => GeneratorWhiteSpaceConfig.java} | 2 +- ...ngExtensions.java => TracedAccessors.java} | 6 +- ...sor.java => TracedAccessorsProcessor.java} | 99 +++++++++---------- .../generator/trace/node/TracingSugar.java | 10 +- 12 files changed, 150 insertions(+), 95 deletions(-) rename org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/{WhiteSpaceConfig.xtend => GeneratorWhiteSpaceConfig.xtend} (95%) rename org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/{TracingExtensions.xtend => TracedAccessors.xtend} (66%) rename org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/{WhiteSpaceConfig.java => GeneratorWhiteSpaceConfig.java} (93%) rename org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/{TracingExtensions.java => TracedAccessors.java} (78%) rename org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/{TracingExtensionsProcessor.java => TracedAccessorsProcessor.java} (67%) diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend index 12939a594..2fff38db9 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/generator/trace/node/TracingSugarTest.xtend @@ -29,7 +29,7 @@ import org.eclipse.xtext.generator.trace.ITraceRegionProvider @InjectWith(LazyLinkingTestLanguageInjectorProvider) class TracingSugarTest { - @TracingExtensions(LazyLinkingFactory) + @TracedAccessors(LazyLinkingFactory) static class MyExtensions { /** diff --git a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java index 816aeae03..f879a52c0 100644 --- a/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java +++ b/org.eclipse.xtext.tests/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugarTest.java @@ -20,7 +20,7 @@ import org.eclipse.xtext.generator.trace.ITraceRegionProvider; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.Traced; -import org.eclipse.xtext.generator.trace.node.TracingExtensions; +import org.eclipse.xtext.generator.trace.node.TracedAccessors; import org.eclipse.xtext.generator.trace.node.TracingSugar; import org.eclipse.xtext.linking.lazy.lazyLinking.LazyLinkingFactory; import org.eclipse.xtext.linking.lazy.lazyLinking.Model; @@ -46,7 +46,7 @@ import org.junit.runner.RunWith; @InjectWith(LazyLinkingTestLanguageInjectorProvider.class) @SuppressWarnings("all") public class TracingSugarTest { - @TracingExtensions(LazyLinkingFactory.class) + @TracedAccessors(LazyLinkingFactory.class) public static class MyExtensions extends TracingSugar { /** * manual implementation for unsupported multi cross reference @@ -58,6 +58,14 @@ public class TracingSugarTest { return result; } + public IGeneratorNode _class(final Model target, final Function, String> stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("class"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.trace(location); + this.append(trace, stringProvider.apply(target.getClass())); + return trace; + } + public IGeneratorNode _name(final Property target) { EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); ILocationData location = this.location(target, feature, -1); @@ -66,6 +74,22 @@ public class TracingSugarTest { return trace; } + public IGeneratorNode _name(final Property target, final Function stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.trace(location); + this.append(trace, stringProvider.apply(target.getName())); + return trace; + } + + public IGeneratorNode _class(final Property target, final Function, String> stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("class"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.trace(location); + this.append(trace, stringProvider.apply(target.getClass())); + return trace; + } + public IGeneratorNode _extends(final Type target, final Function stringProvider) { EStructuralFeature feature = target.eClass().getEStructuralFeature("extends"); ILocationData location = this.location(target, feature, -1); @@ -82,6 +106,14 @@ public class TracingSugarTest { return trace; } + public IGeneratorNode _name(final Type target, final Function stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.trace(location); + this.append(trace, stringProvider.apply(target.getName())); + return trace; + } + public IGeneratorNode _parentId(final Type target, final Function stringProvider) { EStructuralFeature feature = target.eClass().getEStructuralFeature("parentId"); ILocationData location = this.location(target, feature, -1); @@ -90,6 +122,14 @@ public class TracingSugarTest { return trace; } + public IGeneratorNode _class(final Type target, final Function, String> stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("class"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.trace(location); + this.append(trace, stringProvider.apply(target.getClass())); + return trace; + } + public IGeneratorNode _name(final UnresolvedProxyProperty target) { EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); ILocationData location = this.location(target, feature, -1); @@ -97,6 +137,22 @@ public class TracingSugarTest { this.append(trace, target.getName()); return trace; } + + public IGeneratorNode _name(final UnresolvedProxyProperty target, final Function stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("name"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.trace(location); + this.append(trace, stringProvider.apply(target.getName())); + return trace; + } + + public IGeneratorNode _class(final UnresolvedProxyProperty target, final Function, String> stringProvider) { + EStructuralFeature feature = target.eClass().getEStructuralFeature("class"); + ILocationData location = this.location(target, feature, -1); + CompositeGeneratorNode trace = this.trace(location); + this.append(trace, stringProvider.apply(target.getClass())); + return trace; + } } @Inject diff --git a/org.eclipse.xtext/META-INF/MANIFEST.MF b/org.eclipse.xtext/META-INF/MANIFEST.MF index 484f7a4b7..881364ce9 100644 --- a/org.eclipse.xtext/META-INF/MANIFEST.MF +++ b/org.eclipse.xtext/META-INF/MANIFEST.MF @@ -34,7 +34,7 @@ Export-Package: org.eclipse.xtext, org.eclipse.xtext.generator, org.eclipse.xtext.generator.trace;x-friends:="org.eclipse.xtext.xbase.ui,org.eclipse.xtend.ide", org.eclipse.xtext.generator.trace.internal;x-friends:="org.eclipse.xtext.ui,org.eclipse.xtext.xbase.ui", - org.eclipse.xtext.generator.trace.node, + org.eclipse.xtext.generator.trace.node;x-friends:="org.eclipse.xtext.tests", org.eclipse.xtext.grammaranalysis;x-internal:=true, org.eclipse.xtext.grammaranalysis.impl;x-friends:="org.eclipse.xtext.junit4,org.eclipse.xtext.xtext.generator", org.eclipse.xtext.impl, diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend index d18b6c795..72cd3d4b5 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.xtend @@ -18,7 +18,7 @@ import org.eclipse.xtext.generator.trace.ILocationData */ class GeneratorNodeExtensions { - @Inject WhiteSpaceConfig wsConfig = new WhiteSpaceConfig + @Inject GeneratorWhiteSpaceConfig wsConfig = new GeneratorWhiteSpaceConfig /** * @return a root trace node for the given location diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorWhiteSpaceConfig.xtend similarity index 95% rename from org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.xtend rename to org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorWhiteSpaceConfig.xtend index 827289e0e..7551d3aad 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/GeneratorWhiteSpaceConfig.xtend @@ -10,7 +10,7 @@ package org.eclipse.xtext.generator.trace.node /** * @author Sven Efftinge - Initial contribution and API */ -class WhiteSpaceConfig { +class GeneratorWhiteSpaceConfig { def String getIndentationString() { ' ' diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracedAccessors.xtend similarity index 66% rename from org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend rename to org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracedAccessors.xtend index 81775b634..a53007179 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingExtensions.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracedAccessors.xtend @@ -9,7 +9,6 @@ package org.eclipse.xtext.generator.trace.node import java.util.function.Function import org.eclipse.emf.ecore.EFactory -import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.EStructuralFeature import org.eclipse.xtend.lib.macro.AbstractClassProcessor import org.eclipse.xtend.lib.macro.Active @@ -22,26 +21,26 @@ import org.eclipse.xtext.generator.trace.ILocationData /** * @author Sven Efftinge - Initial contribution and API */ -@Active(TracingExtensionsProcessor) -annotation TracingExtensions { +@Active(TracedAccessorsProcessor) +annotation TracedAccessors { Class[] value } -class TracingExtensionsProcessor extends AbstractClassProcessor { +class TracedAccessorsProcessor extends AbstractClassProcessor { override doTransform(MutableClassDeclaration annotatedClass, extension TransformationContext context) { - val eobjectType = EObject.newTypeReference() annotatedClass.extendedClass = TracingSugar.newTypeReference() - val annotationType = findTypeGlobally(TracingExtensions) - val factories = annotatedClass.findAnnotation(annotationType)?.getClassArrayValue("value") + val iterableType = Iterable.newTypeReference(newWildcardTypeReference) + val annotationType = TracedAccessors.newTypeReference + val factories = annotatedClass.findAnnotation(annotationType.type)?.getClassArrayValue("value") if (factories === null) { return; } for (f : factories.map[type].filter(InterfaceDeclaration)) { for (t: f.declaredMethods.filter[simpleName.startsWith('create') && parameters.empty].map[returnType]) { - for (getter : t.allResolvedMethods.filter[ isGetter]) { + for (getter : t.allResolvedMethods.filter[ isSupportedGetter].filter[!iterableType.isAssignableFrom(declaration.returnType)]) { val rt = getter.resolvedReturnType - if (allowedLowerCaseTypeNames.contains(rt.type.simpleName.toLowerCase)) { + if (TYPES_WITH_GOOD_TO_STRING.contains(rt.type.simpleName.toLowerCase)) { annotatedClass.addMethod(getter.tracerName) [ returnType = IGeneratorNode.newTypeReference() addParameter('target', t) @@ -53,21 +52,20 @@ class TracingExtensionsProcessor extends AbstractClassProcessor { return trace; ''' ] - } else if (eobjectType.isAssignableFrom(rt)) { - annotatedClass.addMethod(getter.tracerName) [ - returnType = IGeneratorNode.newTypeReference - addParameter('target', t) - val stringProvider = Function.newTypeReference(rt, string) - addParameter('stringProvider', stringProvider) - body = ''' - «EStructuralFeature» feature = target.eClass().getEStructuralFeature("«getter.featureName»"); - «ILocationData» location = this.location(target, feature, -1); - «CompositeGeneratorNode» trace = this.trace(location); - this.append(trace, stringProvider.apply(target.«getter.declaration.simpleName»())); - return trace; - ''' - ] - } + } + annotatedClass.addMethod(getter.tracerName) [ + returnType = IGeneratorNode.newTypeReference + addParameter('target', t) + val stringProvider = Function.newTypeReference(rt, string) + addParameter('stringProvider', stringProvider) + body = ''' + «EStructuralFeature» feature = target.eClass().getEStructuralFeature("«getter.featureName»"); + «ILocationData» location = this.location(target, feature, -1); + «CompositeGeneratorNode» trace = this.trace(location); + this.append(trace, stringProvider.apply(target.«getter.declaration.simpleName»())); + return trace; + ''' + ] } } } @@ -83,9 +81,9 @@ class TracingExtensionsProcessor extends AbstractClassProcessor { m.declaration.simpleName.substring(skip).toFirstLower } - static val allowedLowerCaseTypeNames = #{'string','boolean','int','long','integer'} + static val TYPES_WITH_GOOD_TO_STRING = #{'string','boolean','int','long','integer'} - def boolean isGetter(ResolvedMethod it) { + def boolean isSupportedGetter(ResolvedMethod it) { if (!declaration.parameters.empty) return false if (declaration.static) diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend index 11aad1da9..b2e995d17 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend +++ b/org.eclipse.xtext/src/org/eclipse/xtext/generator/trace/node/TracingSugar.xtend @@ -21,7 +21,8 @@ class TracingSugar extends GeneratorNodeExtensions { @Inject protected ILocationInFileProvider locationProvider @Inject protected ITraceURIConverter traceURIConverter - @Inject protected WhiteSpaceConfig whiteSpaceConfig + @Inject protected GeneratorWhiteSpaceConfig whiteSpaceConfig + @Inject protected GeneratorNodeProcessor processor /** * Convenience extension, to generate traced code. @@ -35,8 +36,7 @@ class TracingSugar extends GeneratorNodeExtensions { * Use to generate a file based on generator node. */ def void generateTracedFile(IFileSystemAccess2 fsa, String path, CompositeGeneratorNode rootNode) { - val proc = new GeneratorNodeProcessor() - val result = proc.process(rootNode); + val result = processor.process(rootNode); fsa.generateFile(path, result) } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java index cb80bfb3a..0d9139216 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorNodeExtensions.java @@ -12,13 +12,13 @@ import java.util.List; import org.eclipse.xtend2.lib.StringConcatenationClient; import org.eclipse.xtext.generator.trace.ILocationData; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; +import org.eclipse.xtext.generator.trace.node.GeneratorWhiteSpaceConfig; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; import org.eclipse.xtext.generator.trace.node.IndentNode; import org.eclipse.xtext.generator.trace.node.NewLineNode; import org.eclipse.xtext.generator.trace.node.TemplateNode; import org.eclipse.xtext.generator.trace.node.TextNode; import org.eclipse.xtext.generator.trace.node.TraceNode; -import org.eclipse.xtext.generator.trace.node.WhiteSpaceConfig; /** * A builder API to create generator node trees @@ -28,7 +28,7 @@ import org.eclipse.xtext.generator.trace.node.WhiteSpaceConfig; @SuppressWarnings("all") public class GeneratorNodeExtensions { @Inject - private WhiteSpaceConfig wsConfig = new WhiteSpaceConfig(); + private GeneratorWhiteSpaceConfig wsConfig = new GeneratorWhiteSpaceConfig(); /** * @return a root trace node for the given location diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorWhiteSpaceConfig.java similarity index 93% rename from org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.java rename to org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorWhiteSpaceConfig.java index 2b581fd98..fa4520dce 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/WhiteSpaceConfig.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/GeneratorWhiteSpaceConfig.java @@ -11,7 +11,7 @@ package org.eclipse.xtext.generator.trace.node; * @author Sven Efftinge - Initial contribution and API */ @SuppressWarnings("all") -public class WhiteSpaceConfig { +public class GeneratorWhiteSpaceConfig { public String getIndentationString() { return " "; } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensions.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedAccessors.java similarity index 78% rename from org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensions.java rename to org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedAccessors.java index 4856ec5d4..3ccfbb603 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensions.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedAccessors.java @@ -9,12 +9,12 @@ package org.eclipse.xtext.generator.trace.node; import org.eclipse.emf.ecore.EFactory; import org.eclipse.xtend.lib.macro.Active; -import org.eclipse.xtext.generator.trace.node.TracingExtensionsProcessor; +import org.eclipse.xtext.generator.trace.node.TracedAccessorsProcessor; /** * @author Sven Efftinge - Initial contribution and API */ -@Active(TracingExtensionsProcessor.class) -public @interface TracingExtensions { +@Active(TracedAccessorsProcessor.class) +public @interface TracedAccessors { public Class[] value(); } diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedAccessorsProcessor.java similarity index 67% rename from org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java rename to org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedAccessorsProcessor.java index 51d545361..c46ac2b62 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingExtensionsProcessor.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracedAccessorsProcessor.java @@ -12,7 +12,6 @@ import java.util.Collections; import java.util.List; import java.util.Set; import java.util.function.Function; -import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.xtend.lib.macro.AbstractClassProcessor; import org.eclipse.xtend.lib.macro.TransformationContext; @@ -28,7 +27,7 @@ import org.eclipse.xtend2.lib.StringConcatenationClient; import org.eclipse.xtext.generator.trace.ILocationData; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.IGeneratorNode; -import org.eclipse.xtext.generator.trace.node.TracingExtensions; +import org.eclipse.xtext.generator.trace.node.TracedAccessors; import org.eclipse.xtext.generator.trace.node.TracingSugar; import org.eclipse.xtext.xbase.lib.CollectionLiterals; import org.eclipse.xtext.xbase.lib.Conversions; @@ -40,13 +39,13 @@ import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; import org.eclipse.xtext.xbase.lib.StringExtensions; @SuppressWarnings("all") -public class TracingExtensionsProcessor extends AbstractClassProcessor { +public class TracedAccessorsProcessor extends AbstractClassProcessor { @Override public void doTransform(final MutableClassDeclaration annotatedClass, @Extension final TransformationContext context) { - final TypeReference eobjectType = context.newTypeReference(EObject.class); annotatedClass.setExtendedClass(context.newTypeReference(TracingSugar.class)); - final Type annotationType = context.findTypeGlobally(TracingExtensions.class); - AnnotationReference _findAnnotation = annotatedClass.findAnnotation(annotationType); + final TypeReference iterableType = context.newTypeReference(Iterable.class, context.newWildcardTypeReference()); + final TypeReference annotationType = context.newTypeReference(TracedAccessors.class); + AnnotationReference _findAnnotation = annotatedClass.findAnnotation(annotationType.getType()); TypeReference[] _classArrayValue = null; if (_findAnnotation!=null) { _classArrayValue=_findAnnotation.getClassArrayValue("value"); @@ -69,15 +68,19 @@ public class TracingExtensionsProcessor extends AbstractClassProcessor { Iterable _map = IterableExtensions.map(IterableExtensions.filter(f.getDeclaredMethods(), _function_1), _function_2); for (final TypeReference t : _map) { final Function1 _function_3 = (ResolvedMethod it) -> { - return Boolean.valueOf(this.isGetter(it)); + return Boolean.valueOf(this.isSupportedGetter(it)); }; - Iterable _filter_1 = IterableExtensions.filter(t.getAllResolvedMethods(), _function_3); + final Function1 _function_4 = (ResolvedMethod it) -> { + boolean _isAssignableFrom = iterableType.isAssignableFrom(it.getDeclaration().getReturnType()); + return Boolean.valueOf((!_isAssignableFrom)); + }; + Iterable _filter_1 = IterableExtensions.filter(IterableExtensions.filter(t.getAllResolvedMethods(), _function_3), _function_4); for (final ResolvedMethod getter : _filter_1) { { final TypeReference rt = getter.getResolvedReturnType(); - boolean _contains = TracingExtensionsProcessor.allowedLowerCaseTypeNames.contains(rt.getType().getSimpleName().toLowerCase()); + boolean _contains = TracedAccessorsProcessor.TYPES_WITH_GOOD_TO_STRING.contains(rt.getType().getSimpleName().toLowerCase()); if (_contains) { - final Procedure1 _function_4 = (MutableMethodDeclaration it) -> { + final Procedure1 _function_5 = (MutableMethodDeclaration it) -> { it.setReturnType(context.newTypeReference(IGeneratorNode.class)); it.addParameter("target", t); StringConcatenationClient _client = new StringConcatenationClient() { @@ -85,7 +88,7 @@ public class TracingExtensionsProcessor extends AbstractClassProcessor { protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { _builder.append(EStructuralFeature.class); _builder.append(" feature = target.eClass().getEStructuralFeature(\""); - String _featureName = TracingExtensionsProcessor.this.featureName(getter); + String _featureName = TracedAccessorsProcessor.this.featureName(getter); _builder.append(_featureName); _builder.append("\");"); _builder.newLineIfNotEmpty(); @@ -106,44 +109,40 @@ public class TracingExtensionsProcessor extends AbstractClassProcessor { }; it.setBody(_client); }; - annotatedClass.addMethod(this.tracerName(getter), _function_4); - } else { - boolean _isAssignableFrom = eobjectType.isAssignableFrom(rt); - if (_isAssignableFrom) { - final Procedure1 _function_5 = (MutableMethodDeclaration it) -> { - it.setReturnType(context.newTypeReference(IGeneratorNode.class)); - it.addParameter("target", t); - final TypeReference stringProvider = context.newTypeReference(Function.class, rt, context.getString()); - it.addParameter("stringProvider", stringProvider); - StringConcatenationClient _client = new StringConcatenationClient() { - @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append(EStructuralFeature.class); - _builder.append(" feature = target.eClass().getEStructuralFeature(\""); - String _featureName = TracingExtensionsProcessor.this.featureName(getter); - _builder.append(_featureName); - _builder.append("\");"); - _builder.newLineIfNotEmpty(); - _builder.append(ILocationData.class); - _builder.append(" location = this.location(target, feature, -1);"); - _builder.newLineIfNotEmpty(); - _builder.append(CompositeGeneratorNode.class); - _builder.append(" trace = this.trace(location);"); - _builder.newLineIfNotEmpty(); - _builder.append("this.append(trace, stringProvider.apply(target."); - String _simpleName = getter.getDeclaration().getSimpleName(); - _builder.append(_simpleName); - _builder.append("()));"); - _builder.newLineIfNotEmpty(); - _builder.append("return trace;"); - _builder.newLine(); - } - }; - it.setBody(_client); - }; - annotatedClass.addMethod(this.tracerName(getter), _function_5); - } + annotatedClass.addMethod(this.tracerName(getter), _function_5); } + final Procedure1 _function_6 = (MutableMethodDeclaration it) -> { + it.setReturnType(context.newTypeReference(IGeneratorNode.class)); + it.addParameter("target", t); + final TypeReference stringProvider = context.newTypeReference(Function.class, rt, context.getString()); + it.addParameter("stringProvider", stringProvider); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append(EStructuralFeature.class); + _builder.append(" feature = target.eClass().getEStructuralFeature(\""); + String _featureName = TracedAccessorsProcessor.this.featureName(getter); + _builder.append(_featureName); + _builder.append("\");"); + _builder.newLineIfNotEmpty(); + _builder.append(ILocationData.class); + _builder.append(" location = this.location(target, feature, -1);"); + _builder.newLineIfNotEmpty(); + _builder.append(CompositeGeneratorNode.class); + _builder.append(" trace = this.trace(location);"); + _builder.newLineIfNotEmpty(); + _builder.append("this.append(trace, stringProvider.apply(target."); + String _simpleName = getter.getDeclaration().getSimpleName(); + _builder.append(_simpleName); + _builder.append("()));"); + _builder.newLineIfNotEmpty(); + _builder.append("return trace;"); + _builder.newLine(); + } + }; + it.setBody(_client); + }; + annotatedClass.addMethod(this.tracerName(getter), _function_6); } } } @@ -172,9 +171,9 @@ public class TracingExtensionsProcessor extends AbstractClassProcessor { return _xblockexpression; } - private final static Set allowedLowerCaseTypeNames = Collections.unmodifiableSet(CollectionLiterals.newHashSet("string", "boolean", "int", "long", "integer")); + private final static Set TYPES_WITH_GOOD_TO_STRING = Collections.unmodifiableSet(CollectionLiterals.newHashSet("string", "boolean", "int", "long", "integer")); - public boolean isGetter(final ResolvedMethod it) { + public boolean isSupportedGetter(final ResolvedMethod it) { boolean _isEmpty = IterableExtensions.isEmpty(it.getDeclaration().getParameters()); boolean _not = (!_isEmpty); if (_not) { diff --git a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java index 5a3d4aaa6..035035037 100644 --- a/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java +++ b/org.eclipse.xtext/xtend-gen/org/eclipse/xtext/generator/trace/node/TracingSugar.java @@ -12,7 +12,7 @@ import org.eclipse.xtext.generator.trace.SourceRelativeURI; import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode; import org.eclipse.xtext.generator.trace.node.GeneratorNodeExtensions; import org.eclipse.xtext.generator.trace.node.GeneratorNodeProcessor; -import org.eclipse.xtext.generator.trace.node.WhiteSpaceConfig; +import org.eclipse.xtext.generator.trace.node.GeneratorWhiteSpaceConfig; import org.eclipse.xtext.resource.ILocationInFileProvider; import org.eclipse.xtext.util.ITextRegion; import org.eclipse.xtext.util.ITextRegionWithLineInformation; @@ -32,7 +32,10 @@ public class TracingSugar extends GeneratorNodeExtensions { protected ITraceURIConverter traceURIConverter; @Inject - protected WhiteSpaceConfig whiteSpaceConfig; + protected GeneratorWhiteSpaceConfig whiteSpaceConfig; + + @Inject + protected GeneratorNodeProcessor processor; /** * Convenience extension, to generate traced code. @@ -46,8 +49,7 @@ public class TracingSugar extends GeneratorNodeExtensions { * Use to generate a file based on generator node. */ public void generateTracedFile(final IFileSystemAccess2 fsa, final String path, final CompositeGeneratorNode rootNode) { - final GeneratorNodeProcessor proc = new GeneratorNodeProcessor(); - final GeneratorNodeProcessor.Result result = proc.process(rootNode); + final GeneratorNodeProcessor.Result result = this.processor.process(rootNode); fsa.generateFile(path, result); }