/*******************************************************************************
* Copyright (c) 2015 Bruno Medeiros and other Contributors.
* 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
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package dtool.parser.structure;
import static melnorme.lang.tooling.EAttributeFlag.ABSTRACT;
import static melnorme.lang.tooling.EAttributeFlag.ALIASED;
import static melnorme.lang.tooling.EAttributeFlag.IMMUTABLE;
import static melnorme.lang.tooling.EAttributeFlag.STATIC;
import static melnorme.lang.tooling.structure.StructureElementKind.ALIAS;
import static melnorme.lang.tooling.structure.StructureElementKind.CLASS;
import static melnorme.lang.tooling.structure.StructureElementKind.CONSTRUCTOR;
import static melnorme.lang.tooling.structure.StructureElementKind.ENUM_TYPE;
import static melnorme.lang.tooling.structure.StructureElementKind.FUNCTION;
import static melnorme.lang.tooling.structure.StructureElementKind.STRUCT;
import static melnorme.lang.tooling.structure.StructureElementKind.VARIABLE;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import org.junit.Test;
import dtool.parser.DeeParser;
import dtool.parser.DeeParserResult.ParsedModule;
import dtool.tests.DToolTestResources;
import melnorme.lang.tooling.EAttributeFlag;
import melnorme.lang.tooling.EProtection;
import melnorme.lang.tooling.ElementAttributes;
import melnorme.lang.tooling.ast.SourceRange;
import melnorme.lang.tooling.common.ParserError;
import melnorme.lang.tooling.structure.AbstractStructureParser;
import melnorme.lang.tooling.structure.AbstractStructureParser_Test;
import melnorme.lang.tooling.structure.SourceFileStructure;
import melnorme.lang.tooling.structure.StructureElement;
import melnorme.utilbox.collections.ArrayList2;
import melnorme.utilbox.collections.Indexable;
import melnorme.utilbox.core.CommonException;
import melnorme.utilbox.misc.ArrayUtil;
import melnorme.utilbox.misc.Location;
public class DeeStructureCreator_Test extends AbstractStructureParser_Test {
public static ElementAttributes attrib(EProtection protection, EAttributeFlag... flags) {
return new ElementAttributes(protection, flags);
}
public static ElementAttributes att(EAttributeFlag... flags) {
return new ElementAttributes(EProtection.PUBLIC, flags);
}
protected static ElementAttributes eat(EAttributeFlag... flags) {
return att(ArrayUtil.concat(flags, EAttributeFlag.TEMPLATED));
}
protected ArrayList2<StructureElement> elems(StructureElement... expectedElements) {
return ArrayList2.create(expectedElements);
}
protected int indexOf(String str) {
int indexOf = source.indexOf(str);
assertTrue(indexOf != -1);
return indexOf;
}
protected int startOf(String str) {
return indexOf(str);
}
protected int endOf(String str) {
return indexOf(str) + str.length();
}
protected SourceRange sr(String start, String end) {
return SourceRange.srStartToEnd(startOf(start), endOf(end));
}
protected SourceRange sr(String start, int length) {
return new SourceRange(startOf(start), length);
}
protected void testParseStructure(String source, StructureElement... expectedElements) throws CommonException {
this.source = source;
SourceFileStructure structure = createStructureParser().parse("XXXXX NOT_APPLICABLE");
ArrayList2<StructureElement> expectedStructure = ArrayList2.create(expectedElements);
SourceFileStructure expected = new SourceFileStructure(structure.getLocation(), expectedStructure,
(Indexable<ParserError>) null);
assertAreEqual(expected.getChildren(), structure.getChildren());
assertEquals(structure, expected);
}
@Override
protected AbstractStructureParser createStructureParser() {
// dummy loc
Location loc = DToolTestResources.getTestResourceLoc().resolve_fromValid("parser-structure/foo.d");
return new AbstractStructureParser(loc, source) {
String source = DeeStructureCreator_Test.this.source;
@Override
public SourceFileStructure parse(String outputParseSource) throws CommonException {
ParsedModule parsedModule = DeeParser.parseSourceModule(source, loc.toPath());
return new DeeStructureCreator().createStructure(parsedModule, loc);
}
};
}
@Test
public void testname() throws Exception { testname$(); }
public void testname$() throws Exception {
source = "int foo; string[] func() {/*2*/} this() {/*3*/}";
testParseStructure(
source,
new StructureElement("foo", sr(4,3), sr(0,8), VARIABLE, att(), "int", null),
new StructureElement("func()", sr("func()", 4), sr("string[] f","2*/}"), FUNCTION, att(), "string[]", null),
new StructureElement("this()", sr("this()", 4), sr("this()","3*/}"), CONSTRUCTOR, att(), null, null)
);
// Test attributes
source = "public: static const(int) foo; private abstract immutable int bar; ";
ElementAttributes fooAttribs = attrib(EProtection.PUBLIC, STATIC);
ElementAttributes barAttribs = attrib(EProtection.PRIVATE, ABSTRACT, IMMUTABLE);
testParseStructure(
source,
new StructureElement("foo", sr("foo", 3), sr("const(","foo;"), VARIABLE, fooAttribs, "const(int)", null),
new StructureElement("bar", sr("bar", 3), sr("int bar","bar;"), VARIABLE, barAttribs, "int", null)
);
source = "string[] func(int a, char) {/*2*/} this(int[] a, char b...) {/*3*/}";
testParseStructure(
source,
elem("func(int, char)", sr("string[] f","2*/}"), sr("func(", 4), FUNCTION, att(), "string[]", null),
elem("this(int[], char...)", sr("this(","3*/}"), sr("this(", 4), CONSTRUCTOR, att(), null, null)
);
source =
"struct Xpto { int foo2; void func(int a){} /*Xpto*/} \n " +
"class Foo { int fox; class Inner(T) { int xxx; } /*Foo*/} \n ";
testParseStructure(
source,
new StructureElement("Xpto", sr("Xpto", 4), sr("struct Xpto","/*Xpto*/}"), STRUCT, att(), null, elems(
new StructureElement("foo2", sr("foo2;", 4), sr("int foo2;","foo2;"), VARIABLE, att(), "int", null),
new StructureElement("func(int)", sr("func", 4), sr("void func","a){}"), FUNCTION, att(), "void", null)
)),
new StructureElement("Foo", sr("Foo", 3), sr("class F","/*Foo*/}"), CLASS, att(), null, elems(
new StructureElement("fox", sr("fox;", 3), sr("int fox;","fox;"), VARIABLE, att(), "int", null),
new StructureElement("Inner", sr("Inner", 5), sr("class In","xxx; }"), CLASS, eat(), null, elems(
new StructureElement("xxx", sr("xxx;", 3), sr("int xxx","xxx;"), VARIABLE, att(), "int", null)
))
))
);
// Test multiple var decl.
source = "static int foo, bar; ";
testParseStructure(
source,
new StructureElement("foo", sr("foo", 3), sr("int foo","bar;"), VARIABLE, att(STATIC), "int", elems(
new StructureElement("bar", sr("bar", 3), sr("bar;","bar"), VARIABLE, attrib(null), "int", null)
)
));
/* TODO: DTool: attribute of fragmentDefUnits*/
// Test enum.
source = "enum Foo : int { ONE, TWO }";
testParseStructure(
source,
new StructureElement("Foo", sr("Foo", 3), sr("enum","}"), ENUM_TYPE, att(), "int", elems(
new StructureElement("ONE", sr("ONE", 3), sr("ONE","ONE"), VARIABLE, attrib(null), null, null),
new StructureElement("TWO", sr("TWO", 3), sr("TWO","TWO"), VARIABLE, attrib(null), null, null)
))
);
source = "enum Foo = 123, Bar = 'abc'";
testParseStructure(
source,
new StructureElement("Foo", sr("Foo", 3), sr("Foo","123"), VARIABLE, attrib(null), null, null),
new StructureElement("Bar", sr("Bar", 3), sr("Bar","'abc'"), VARIABLE, attrib(null), null, null)
);
// Test aliases:
source = "alias Foo = Bar;";
testParseStructure(
source,
new StructureElement("Foo", sr("Foo", 3), sr("Foo","Bar"), ALIAS, attrib(null, ALIASED), "Bar", null)
);
source = "alias Foo = Bar, XXX = XPTO;";
testParseStructure(
source,
new StructureElement("Foo", sr("Foo", 3), sr("Foo","Bar"), ALIAS, attrib(null, ALIASED), "Bar", null),
new StructureElement("XXX", sr("XXX", 3), sr("XXX","XPTO"), ALIAS, attrib(null, ALIASED), "XPTO", null)
);
}
}