This repository has been archived by the owner on Mar 1, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add more tests for implement interface also adds a private dummy (unfinished) code layouting API which will be used for implement interface in the future to put stuff in the correct places.
- Loading branch information
1 parent
15652c4
commit 2defc86
Showing
17 changed files
with
1,341 additions
and
156 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/// Visitor classifying types and groups of regions of root definitions. | ||
module workspaced.visitors.classifier; | ||
|
||
import workspaced.visitors.attributes; | ||
|
||
import workspaced.com.dcdext; | ||
|
||
import std.algorithm; | ||
import std.ascii; | ||
import std.range; | ||
import std.meta; | ||
|
||
import dparse.ast; | ||
import dparse.lexer; | ||
|
||
class CodeDefinitionClassifier : AttributesVisitor | ||
{ | ||
struct Region | ||
{ | ||
CodeOrderType type; | ||
ProtectionOrderType protection; | ||
StaticOrderType staticness; | ||
string minIndentation; | ||
uint[2] region; | ||
|
||
bool sameBlockAs(in Region other) | ||
{ | ||
return type == other.type && protection == other.protection && staticness == other.staticness; | ||
} | ||
} | ||
|
||
this(string code) | ||
{ | ||
this.code = code; | ||
} | ||
|
||
override void visit(const AliasDeclaration aliasDecl) | ||
{ | ||
putRegion(CodeOrderType.aliases); | ||
} | ||
|
||
override void visit(const AliasThisDeclaration aliasDecl) | ||
{ | ||
putRegion(CodeOrderType.aliases); | ||
} | ||
|
||
override void visit(const ClassDeclaration typeDecl) | ||
{ | ||
putRegion(CodeOrderType.types); | ||
} | ||
|
||
override void visit(const InterfaceDeclaration typeDecl) | ||
{ | ||
putRegion(CodeOrderType.types); | ||
} | ||
|
||
override void visit(const StructDeclaration typeDecl) | ||
{ | ||
putRegion(CodeOrderType.types); | ||
} | ||
|
||
override void visit(const UnionDeclaration typeDecl) | ||
{ | ||
putRegion(CodeOrderType.types); | ||
} | ||
|
||
override void visit(const EnumDeclaration typeDecl) | ||
{ | ||
putRegion(CodeOrderType.types); | ||
} | ||
|
||
override void visit(const AnonymousEnumDeclaration typeDecl) | ||
{ | ||
putRegion(CodeOrderType.types); | ||
} | ||
|
||
override void visit(const AutoDeclaration field) | ||
{ | ||
putRegion(CodeOrderType.fields); | ||
} | ||
|
||
override void visit(const VariableDeclaration field) | ||
{ | ||
putRegion(CodeOrderType.fields); | ||
} | ||
|
||
override void visit(const Constructor ctor) | ||
{ | ||
putRegion(CodeOrderType.ctor); | ||
} | ||
|
||
override void visit(const StaticConstructor ctor) | ||
{ | ||
putRegion(CodeOrderType.ctor); | ||
} | ||
|
||
override void visit(const SharedStaticConstructor ctor) | ||
{ | ||
putRegion(CodeOrderType.ctor); | ||
} | ||
|
||
override void visit(const Postblit copyctor) | ||
{ | ||
putRegion(CodeOrderType.copyctor); | ||
} | ||
|
||
override void visit(const Destructor dtor) | ||
{ | ||
putRegion(CodeOrderType.dtor); | ||
} | ||
|
||
override void visit(const StaticDestructor dtor) | ||
{ | ||
putRegion(CodeOrderType.dtor); | ||
} | ||
|
||
override void visit(const SharedStaticDestructor dtor) | ||
{ | ||
putRegion(CodeOrderType.dtor); | ||
} | ||
|
||
override void visit(const FunctionDeclaration method) | ||
{ | ||
putRegion((method.attributes && method.attributes.any!(a => a.atAttribute | ||
&& a.atAttribute.identifier.text == "property")) ? CodeOrderType.properties | ||
: CodeOrderType.methods); | ||
} | ||
|
||
override void visit(const Declaration dec) | ||
{ | ||
writtenRegion = false; | ||
super.visit(dec); | ||
if (writtenRegion && regions.length >= 2 && regions[$ - 2].sameBlockAs(regions[$ - 1])) | ||
{ | ||
auto range = regions[$ - 1].region; | ||
if (regions[$ - 1].minIndentation.scoreIndent < regions[$ - 2].minIndentation.scoreIndent) | ||
regions[$ - 2].minIndentation = regions[$ - 1].minIndentation; | ||
regions[$ - 2].region[1] = range[1]; | ||
regions.length--; | ||
} | ||
} | ||
|
||
void putRegion(CodeOrderType type) | ||
{ | ||
ProtectionOrderType protection; | ||
StaticOrderType staticness; | ||
|
||
auto prot = context.protectionAttribute; | ||
if (prot) | ||
{ | ||
if (prot[0].type == tok!"private") | ||
protection = ProtectionOrderType.private_; | ||
else if (prot[0].type == tok!"protected") | ||
protection = ProtectionOrderType.protected_; | ||
else if (prot[0].type == tok!"package") | ||
{ | ||
if (prot.length > 1) | ||
protection = ProtectionOrderType.packageIdentifier; | ||
else | ||
protection = ProtectionOrderType.package_; | ||
} | ||
else if (prot[0].type == tok!"public") | ||
protection = ProtectionOrderType.public_; | ||
} | ||
|
||
staticness = context.isStatic ? StaticOrderType.static_ : StaticOrderType.instanced; | ||
|
||
//dfmt off | ||
Region r = { | ||
type: type, | ||
protection: protection, | ||
staticness: staticness | ||
}; | ||
//dfmt on | ||
regions ~= r; | ||
writtenRegion = true; | ||
} | ||
|
||
alias visit = AttributesVisitor.visit; | ||
|
||
bool writtenRegion; | ||
string code; | ||
Region[] regions; | ||
} | ||
|
||
private int scoreIndent(string indent) | ||
{ | ||
auto len = indent.countUntil!(a => !a.isWhite); | ||
if (len == -1) | ||
return cast(int) indent.length; | ||
return indent[0 .. len].map!(a => a == ' ' ? 1 : 4).sum; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/// Finds methods in a specified interface or class location. | ||
module workspaced.visitors.methodfinder; | ||
|
||
import workspaced.visitors.attributes; | ||
|
||
import workspaced.dparseext; | ||
|
||
import dparse.ast; | ||
import dparse.formatter; | ||
import dparse.lexer; | ||
|
||
import std.algorithm; | ||
import std.array; | ||
import std.range; | ||
import std.string; | ||
|
||
struct ArgumentInfo | ||
{ | ||
string signature, type, name; | ||
|
||
string toString() const | ||
{ | ||
return name; | ||
} | ||
} | ||
|
||
struct MethodDetails | ||
{ | ||
string name, signature, returnType; | ||
ArgumentInfo[] arguments; | ||
bool isNothrowOrNogc; | ||
bool hasBody; | ||
bool needsImplementation; | ||
bool optionalImplementation; | ||
|
||
string identifier() | ||
{ | ||
return format("%s %s(%(%s,%))", returnType, name, arguments.map!"a.type"); | ||
} | ||
} | ||
|
||
struct FieldDetails | ||
{ | ||
string name, type; | ||
bool isPrivate; | ||
} | ||
|
||
struct InterfaceDetails | ||
{ | ||
/// Entire code of the file | ||
string code; | ||
bool needsOverride; | ||
string name; | ||
FieldDetails[] fields; | ||
MethodDetails[] methods; | ||
string[] parents; | ||
string[] normalizedParents; | ||
int[] parentPositions; | ||
} | ||
|
||
class InterfaceMethodFinder : AttributesVisitor | ||
{ | ||
this(string code, int targetPosition) | ||
{ | ||
this.code = code; | ||
details.code = code; | ||
this.targetPosition = targetPosition; | ||
} | ||
|
||
override void visit(const ClassDeclaration dec) | ||
{ | ||
auto c = context.save(); | ||
context.pushContainer(ASTContext.ContainerAttribute.Type.class_, dec.name.text); | ||
visitInterface(dec.name, dec.baseClassList, dec.structBody, true); | ||
context.restore(c); | ||
} | ||
|
||
override void visit(const InterfaceDeclaration dec) | ||
{ | ||
auto c = context.save(); | ||
context.pushContainer(ASTContext.ContainerAttribute.Type.interface_, dec.name.text); | ||
visitInterface(dec.name, dec.baseClassList, dec.structBody, false); | ||
context.restore(c); | ||
} | ||
|
||
private void visitInterface(const Token name, const BaseClassList baseClassList, | ||
const StructBody structBody, bool needsOverride) | ||
{ | ||
if (!structBody) | ||
return; | ||
if (targetPosition >= name.index && targetPosition < structBody.endLocation) | ||
{ | ||
details.name = name.text; | ||
if (baseClassList) | ||
foreach (base; baseClassList.items) | ||
{ | ||
if (!base.type2 || !base.type2.typeIdentifierPart | ||
|| !base.type2.typeIdentifierPart.identifierOrTemplateInstance) | ||
continue; | ||
// TODO: template support! | ||
details.parents ~= astToString(base.type2); | ||
details.normalizedParents ~= astToString(base.type2); | ||
details.parentPositions ~= cast( | ||
int) base.type2.typeIdentifierPart.identifierOrTemplateInstance.identifier.index + 1; | ||
} | ||
details.needsOverride = needsOverride; | ||
inTarget = true; | ||
super.visit(structBody); | ||
inTarget = false; | ||
} | ||
} | ||
|
||
override void visit(const FunctionDeclaration dec) | ||
{ | ||
if (!inTarget) | ||
return; | ||
auto origBody = (cast() dec).functionBody; | ||
auto origComment = (cast() dec).comment; | ||
const implLevel = context.requiredImplementationLevel; | ||
const optionalImplementation = implLevel == 1 && origBody is null; | ||
const needsImplementation = implLevel == 9 || optionalImplementation; | ||
(cast() dec).functionBody = null; | ||
(cast() dec).comment = null; | ||
scope (exit) | ||
{ | ||
(cast() dec).functionBody = origBody; | ||
(cast() dec).comment = origComment; | ||
} | ||
auto t = appender!string; | ||
format(t, dec); | ||
string method = context.localFormattedAttributes.chain([t.data.strip]) | ||
.filter!(a => a.length > 0 && !a.among!("abstract", "final")).join(" "); | ||
const hasBody = !!origBody; | ||
ArgumentInfo[] arguments; | ||
if (dec.parameters) | ||
foreach (arg; dec.parameters.parameters) | ||
arguments ~= ArgumentInfo(astToString(arg), astToString(arg.type), arg.name.text); | ||
string returnType = dec.returnType ? astToString(dec.returnType) : "void"; | ||
details.methods ~= MethodDetails(dec.name.text, method, returnType, arguments, | ||
context.isNothrow || context.isNogc, hasBody, needsImplementation, optionalImplementation); | ||
} | ||
|
||
override void visit(const FunctionBody) | ||
{ | ||
} | ||
|
||
override void visit(const VariableDeclaration variable) | ||
{ | ||
if (!inTarget) | ||
return; | ||
if (!variable.type) | ||
return; | ||
string type = astToString(variable.type); | ||
auto isPrivate = context.protectionType == tok!"private"; | ||
|
||
foreach (decl; variable.declarators) | ||
details.fields ~= FieldDetails(decl.name.text, type, isPrivate); | ||
} | ||
|
||
alias visit = AttributesVisitor.visit; | ||
|
||
string code; | ||
bool inTarget; | ||
int targetPosition; | ||
InterfaceDetails details; | ||
} |
Oops, something went wrong.