Skip to content
This repository has been archived by the owner on Mar 1, 2022. It is now read-only.

Commit

Permalink
[major] rework implement interface
Browse files Browse the repository at this point in the history
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
WebFreak001 committed Nov 9, 2018
1 parent 15652c4 commit 2defc86
Show file tree
Hide file tree
Showing 17 changed files with 1,341 additions and 156 deletions.
480 changes: 330 additions & 150 deletions source/workspaced/com/dcdext.d

Large diffs are not rendered by default.

422 changes: 422 additions & 0 deletions source/workspaced/visitors/attributes.d

Large diffs are not rendered by default.

192 changes: 192 additions & 0 deletions source/workspaced/visitors/classifier.d
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;
}
166 changes: 166 additions & 0 deletions source/workspaced/visitors/methodfinder.d
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;
}
Loading

0 comments on commit 2defc86

Please sign in to comment.