refactoring
This commit is contained in:
parent
1dfeb281d9
commit
a9519afee4
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright Brian Schott (Sir Alaran) 2012.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
module autocomplete;
|
||||||
|
|
||||||
|
string dotComplete(Tokens)(ref Tokens tokens, size_t cursorPosition)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
string parenComplete(Tokens)(ref Tokens tokens, size_t cursorPosition)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string symbolComplete(Tokens)(ref Tokens tokens, size_t cursorPosition)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
77
main.d
77
main.d
|
@ -19,23 +19,8 @@ import std.range;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
|
|
||||||
import highlighter;
|
import highlighter;
|
||||||
|
import autocomplete;
|
||||||
pure nothrow bool isLineOfCode(TokenType t)
|
import stats;
|
||||||
{
|
|
||||||
switch(t)
|
|
||||||
{
|
|
||||||
case TokenType.semicolon:
|
|
||||||
case TokenType.while_:
|
|
||||||
case TokenType.if_:
|
|
||||||
case TokenType.for_:
|
|
||||||
case TokenType.foreach_:
|
|
||||||
case TokenType.foreach_reverse_:
|
|
||||||
case TokenType.case_:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads any import directories specified in /etc/dmd.conf.
|
* Loads any import directories specified in /etc/dmd.conf.
|
||||||
|
@ -140,33 +125,7 @@ int main(string[] args)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenCount || sloc)
|
if (highlight)
|
||||||
{
|
|
||||||
LexerConfig config;
|
|
||||||
config.tokenStyle = TokenStyle.doNotReplaceSpecial;
|
|
||||||
ulong[] counts = new ulong[args.length - 1];
|
|
||||||
foreach (i, arg; parallel(args[1..$]))
|
|
||||||
{
|
|
||||||
config.fileName = arg;
|
|
||||||
uint count;
|
|
||||||
auto f = File(arg);
|
|
||||||
import core.stdc.stdlib;
|
|
||||||
ubyte[] buffer = (cast(ubyte*)malloc(f.size))[0..f.size];
|
|
||||||
scope(exit) free(buffer.ptr);
|
|
||||||
//uninitializedArray!(ubyte[])(f.size);
|
|
||||||
foreach (t; byToken(f.rawRead(buffer), config))
|
|
||||||
{
|
|
||||||
if (tokenCount)
|
|
||||||
++counts[i];
|
|
||||||
else if (isLineOfCode(t.type))
|
|
||||||
++counts[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
foreach(i; 0 .. counts.length)
|
|
||||||
writefln("%s: %d", args[i + 1], counts[i]);
|
|
||||||
}
|
|
||||||
else if (highlight)
|
|
||||||
{
|
{
|
||||||
LexerConfig config;
|
LexerConfig config;
|
||||||
config.iterStyle = IterationStyle.everything;
|
config.iterStyle = IterationStyle.everything;
|
||||||
|
@ -177,6 +136,36 @@ int main(string[] args)
|
||||||
args.length == 1 ? "stdin" : args[1]);
|
args.length == 1 ? "stdin" : args[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LexerConfig config;
|
||||||
|
|
||||||
|
bool usingStdin = args.length == 3;
|
||||||
|
config.fileName = usingStdin ? "stdin" : args[1];
|
||||||
|
File f = usingStdin ? stdin : File(args[1]);
|
||||||
|
auto bytes = usingStdin ? cast(ubyte[]) [] : uninitializedArray!(ubyte[])(f.size);
|
||||||
|
|
||||||
|
f.rawRead(bytes);
|
||||||
|
|
||||||
|
auto tokens = byToken(bytes, config);
|
||||||
|
if (sloc)
|
||||||
|
{
|
||||||
|
printLineCount(stdout, tokens);
|
||||||
|
}
|
||||||
|
else if (tokenCount)
|
||||||
|
{
|
||||||
|
printTokenCount(stdout, tokens);
|
||||||
|
}
|
||||||
|
else if (dotComplete)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (parenComplete)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (symbolComplete)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
echo -e "file\tstd.d.lexer dmd\tstd.d.lexer ldc\tstd.d.lexer gdc\tdmd"
|
||||||
|
for i in `ls ../phobos/std/*.d`; do
|
||||||
|
f=`echo $i | sed s/.*phobos\\\\///`
|
||||||
|
dmdt=`avgtime -q -r 200 ./dscanner-dmd --tokenCount $i | grep "Median" | sed "s/.*: //"`
|
||||||
|
ldct=`avgtime -q -r 200 ./dscanner-ldc --tokenCount $i | grep "Median" | sed "s/.*: //"`
|
||||||
|
gdct=`avgtime -q -r 200 ./dscanner-gdc --tokenCount $i | grep "Median" | sed "s/.*: //"`
|
||||||
|
gcct=`avgtime -q -r 200 ~/src/dmd-lexer/src/dmd $i | grep "Median" | sed "s/.*: //"`
|
||||||
|
echo -e "${f}\t${dmdt}\t${ldct}\t${gdct}\t${gcct}"
|
||||||
|
done
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright Brian Schott (Sir Alaran) 2012.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
module stats;
|
||||||
|
|
||||||
|
import std.stdio;
|
||||||
|
import std.d.lexer;
|
||||||
|
|
||||||
|
pure nothrow bool isLineOfCode(TokenType t)
|
||||||
|
{
|
||||||
|
switch(t)
|
||||||
|
{
|
||||||
|
case TokenType.semicolon:
|
||||||
|
case TokenType.while_:
|
||||||
|
case TokenType.if_:
|
||||||
|
case TokenType.for_:
|
||||||
|
case TokenType.foreach_:
|
||||||
|
case TokenType.foreach_reverse_:
|
||||||
|
case TokenType.case_:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printTokenCount(Tokens)(File output, ref Tokens tokens)
|
||||||
|
{
|
||||||
|
ulong count;
|
||||||
|
while(!tokens.empty)
|
||||||
|
{
|
||||||
|
tokens.popFront();
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
output.writefln("%d", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printLineCount(Tokens)(File output, ref Tokens tokens)
|
||||||
|
{
|
||||||
|
ulong count;
|
||||||
|
foreach (t; tokens)
|
||||||
|
{
|
||||||
|
if (isLineOfCode(t.type))
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
output.writefln("%d", count);
|
||||||
|
}
|
838
types.d
838
types.d
|
@ -1,838 +0,0 @@
|
||||||
// Copyright Brian Schott (Sir Alaran) 2012.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
module types;
|
|
||||||
|
|
||||||
import std.stdio;
|
|
||||||
import std.array;
|
|
||||||
import std.range;
|
|
||||||
import std.algorithm;
|
|
||||||
import std.typecons;
|
|
||||||
import std.string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: s with any quote characters backslash-escaped
|
|
||||||
*/
|
|
||||||
string escapeJSON(string s)
|
|
||||||
{
|
|
||||||
return s.replace("\"", "\\\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
unittest { assert(escapeJSON("abc\"def") == "abc\\\"def"); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a string in JSON fromat to the given file
|
|
||||||
* Params:
|
|
||||||
* f = the file to write to
|
|
||||||
* name = the name of the json attribute
|
|
||||||
* value = the value of the json attribute
|
|
||||||
* indent = the indent level
|
|
||||||
*/
|
|
||||||
void writeJSONString(File f, const string name, const string value, uint indent = 0)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
f.write(std.array.replicate(" ", indent), "\"", name, "\" : null");
|
|
||||||
else
|
|
||||||
f.write(std.array.replicate(" ", indent), "\"", name, "\" : \"", escapeJSON(value), "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a string array in JSON format to the given file
|
|
||||||
* f = the file to write to
|
|
||||||
* name = the name of the json attribute
|
|
||||||
* values = the strings that should be written
|
|
||||||
* indent = the indent level
|
|
||||||
*/
|
|
||||||
void writeJSONString(File f, const string name, const string[] values, uint indent = 0)
|
|
||||||
{
|
|
||||||
f.writeln(std.array.replicate(" ", indent), "\"", name, "\" : [");
|
|
||||||
foreach(i, v; values)
|
|
||||||
{
|
|
||||||
f.write(std.array.replicate(" ", indent + 1), "\"", escapeJSON(v), "\"");
|
|
||||||
if (i + 1 < values.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.write(std.array.replicate(" ", indent), "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attributes common to everything interesting
|
|
||||||
*/
|
|
||||||
abstract class Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Sybol name
|
|
||||||
string name;
|
|
||||||
|
|
||||||
/// Line number of declaration
|
|
||||||
uint line;
|
|
||||||
|
|
||||||
/// Attributes such as "ref", "const", etc.
|
|
||||||
string[] attributes;
|
|
||||||
|
|
||||||
/// Protection level such as "public", protected, etc.
|
|
||||||
string protection;
|
|
||||||
|
|
||||||
/// See_also: writeJSONString
|
|
||||||
void writeJSONTo(File f, uint indent) const
|
|
||||||
{
|
|
||||||
f.writeln(std.array.replicate(" ", indent + 1), "{");
|
|
||||||
printMembers(f, indent + 2);
|
|
||||||
f.write("\n", std.array.replicate(" ", indent + 1), "}");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void printMembers(File f, uint indent = 0) const
|
|
||||||
{
|
|
||||||
writeJSONString(f, "name", name == null ? "<<anonymous>>" : name, indent);
|
|
||||||
f.writeln(",");
|
|
||||||
f.write(std.array.replicate(" ", indent), "\"line\" : ", line);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "protection", protection, indent);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "attributes", attributes, indent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Alias Declaration
|
|
||||||
*/
|
|
||||||
class Alias : Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
string aliasedType;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
override void printMembers(File f, uint indent = 0) const
|
|
||||||
{
|
|
||||||
super.printMembers(f, indent);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "aliasedType", aliasedType, indent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Varible declaration
|
|
||||||
*/
|
|
||||||
class Variable : Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Variable type
|
|
||||||
string type;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
override void printMembers(File f, uint indent = 0) const
|
|
||||||
{
|
|
||||||
super.printMembers(f, indent);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "type", type, indent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for any type that can be a template
|
|
||||||
*/
|
|
||||||
abstract class Templateable : Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Template constraint, which may be null
|
|
||||||
string constraint;
|
|
||||||
|
|
||||||
/// Template parameters, may be empty
|
|
||||||
string[] templateParameters;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
override void printMembers(File f, uint indent = 0) const
|
|
||||||
{
|
|
||||||
super.printMembers(f, indent);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "constraint", constraint, indent);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "templateParameters", templateParameters, indent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stuff common to struct, interface, and class.
|
|
||||||
*/
|
|
||||||
class Struct : Templateable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// List of methods
|
|
||||||
Function[] functions;
|
|
||||||
|
|
||||||
/// List of member variables; may be empty
|
|
||||||
Variable[] variables;
|
|
||||||
|
|
||||||
/// List of aliases defined
|
|
||||||
Alias[] aliases;
|
|
||||||
|
|
||||||
/// Source code character position of the beginning of the struct body
|
|
||||||
size_t bodyStart;
|
|
||||||
|
|
||||||
/// Source code character position of the end of the struct body
|
|
||||||
size_t bodyEnd;
|
|
||||||
|
|
||||||
string getMemberType(string name) const
|
|
||||||
{
|
|
||||||
foreach (f; functions)
|
|
||||||
if (f.name == name)
|
|
||||||
return f.returnType;
|
|
||||||
foreach (v; variables)
|
|
||||||
if (v.name == name)
|
|
||||||
return v.type;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] getFunctionDocs(string functionName)
|
|
||||||
{
|
|
||||||
auto app = appender!(string[])();
|
|
||||||
foreach (fun; functions)
|
|
||||||
{
|
|
||||||
if (fun.name != functionName)
|
|
||||||
continue;
|
|
||||||
app.put(fun.documentString());
|
|
||||||
}
|
|
||||||
return app.data;
|
|
||||||
// TODO: Try this again with a newer DMD
|
|
||||||
//return array(map!(a => a.documentString())(
|
|
||||||
// filter!(a => a.name == functionName)(functions)));
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] getCtags(string fileName)
|
|
||||||
{
|
|
||||||
auto app = appender!(string[])();
|
|
||||||
app.put(format("%s\t%s\t%d;\"\ts", name, fileName, line));
|
|
||||||
foreach (Function f; functions)
|
|
||||||
{
|
|
||||||
app.put(format("%s\t%s\t%d;\"\tf\tarity:%d\tstruct:", f.name, fileName,
|
|
||||||
f.line, f.parameters.length, name));
|
|
||||||
}
|
|
||||||
foreach (Variable v; variables)
|
|
||||||
{
|
|
||||||
app.put(format("%s\t%s\t%d;\"\tm\tstruct:%s", v.name, fileName,
|
|
||||||
v.line, name));
|
|
||||||
}
|
|
||||||
return app.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
override void printMembers(File f, uint indent = 0) const
|
|
||||||
{
|
|
||||||
super.printMembers(f, indent);
|
|
||||||
f.writeln(",\n", std.array.replicate(" ", indent), "\"functions\" : [");
|
|
||||||
foreach(i, fun; functions)
|
|
||||||
{
|
|
||||||
fun.writeJSONTo(f, indent);
|
|
||||||
if (i + 1 < functions.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(std.array.replicate(" ", indent), "],\n", std.array.replicate(" ", indent), "\"variables\" : [");
|
|
||||||
foreach(i, var; variables)
|
|
||||||
{
|
|
||||||
var.writeJSONTo(f, indent);
|
|
||||||
if (i + 1 < variables.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(std.array.replicate(" ", indent), "],\n", std.array.replicate(" ", indent), "\"aliases\" : [");
|
|
||||||
foreach(i, al; aliases)
|
|
||||||
{
|
|
||||||
al.writeJSONTo(f, indent);
|
|
||||||
if (i + 1 < aliases.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.write(std.array.replicate(" ", indent), "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Functions and delegates
|
|
||||||
*/
|
|
||||||
class Function : Templateable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Function return type
|
|
||||||
string returnType;
|
|
||||||
|
|
||||||
/// Parameter list; may be empty
|
|
||||||
Variable[] parameters;
|
|
||||||
|
|
||||||
string documentString()
|
|
||||||
{
|
|
||||||
string r = returnType ~ " " ~ name ~ "(";
|
|
||||||
foreach (i, param; parameters)
|
|
||||||
{
|
|
||||||
r ~= param.type ~ " " ~ param.name;
|
|
||||||
if (i + 1 < parameters.length)
|
|
||||||
r ~= ",\\n\\t";
|
|
||||||
}
|
|
||||||
r ~= ")";
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
override void printMembers(File f, uint indent) const
|
|
||||||
{
|
|
||||||
super.printMembers(f, indent);
|
|
||||||
f.write(",\n");
|
|
||||||
f.writeln(std.array.replicate(" ", indent), "\"parameters\" : [");
|
|
||||||
foreach(i, params; parameters)
|
|
||||||
{
|
|
||||||
params.writeJSONTo(f, indent);
|
|
||||||
if (i + 1 < parameters.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
|
|
||||||
f.write(std.array.replicate(" ", indent), "],\n");
|
|
||||||
writeJSONString(f, "returnType", returnType, indent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* class and interface
|
|
||||||
*/
|
|
||||||
class Inherits : Struct
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of interfaces and classes that this inherits or implements; may
|
|
||||||
* be empty
|
|
||||||
*/
|
|
||||||
string[] baseClasses;
|
|
||||||
|
|
||||||
override string[] getCtags(string fileName)
|
|
||||||
{
|
|
||||||
auto app = appender!(string[])();
|
|
||||||
app.put(format("%s\t%s\t%d;\"\tc\tinherits:%s", name, fileName, line,
|
|
||||||
array(baseClasses.joiner(","))));
|
|
||||||
foreach (Function f; functions)
|
|
||||||
{
|
|
||||||
app.put(format("%s\t%s\t%d;\"\tf\tarity:%d\tstruct:", f.name, fileName,
|
|
||||||
f.line, f.parameters.length, name));
|
|
||||||
}
|
|
||||||
foreach (Variable v; variables)
|
|
||||||
{
|
|
||||||
app.put(format("%s\t%s\t%d;\"\tm\tstruct:%s", v.name, fileName,
|
|
||||||
v.line, name));
|
|
||||||
}
|
|
||||||
return app.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
override void printMembers(File f, uint indent = 0) const
|
|
||||||
{
|
|
||||||
super.printMembers(f, indent);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "baseClasses", baseClasses, indent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* enum member
|
|
||||||
*/
|
|
||||||
struct EnumMember
|
|
||||||
{
|
|
||||||
uint line;
|
|
||||||
string name;
|
|
||||||
string type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* enum
|
|
||||||
*/
|
|
||||||
class Enum : Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// True in the case of "enum a {b, c}" or
|
|
||||||
/// False in the case of "enum x = 5" or "enum :double {x = 12.9, y = 8.3}"
|
|
||||||
bool hasMembers;
|
|
||||||
|
|
||||||
/// Enum members; may be empty
|
|
||||||
EnumMember[] members;
|
|
||||||
|
|
||||||
string[] getCtags(string fileName) const
|
|
||||||
{
|
|
||||||
auto app = appender!(string[])();
|
|
||||||
app.put(format("%s\t%s\t%d;\"\tg", name, fileName, line));
|
|
||||||
if (hasMembers)
|
|
||||||
{
|
|
||||||
foreach (EnumMember member; members)
|
|
||||||
{
|
|
||||||
app.put(format("%s\t%s\t%d;\"\te\tenum:%s", member.name, fileName, member.line, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return app.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
override void printMembers(File f, uint indent = 0) const
|
|
||||||
{
|
|
||||||
super.printMembers(f, indent);
|
|
||||||
f.writeln(",\n", std.array.replicate(" ", indent), "\"members\" : [");
|
|
||||||
foreach(i, member; members)
|
|
||||||
{
|
|
||||||
f.writeln(std.array.replicate(" ", indent + 1), "{");
|
|
||||||
writeJSONString(f, "name", member.name, indent + 2);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "type", member.type, indent + 2);
|
|
||||||
f.writeln(",");
|
|
||||||
f.writeln(std.array.replicate(" ", indent + 2), "\"line\" : ", member.line);
|
|
||||||
f.write(std.array.replicate(" ", indent + 1), "}");
|
|
||||||
if (i + 1 < members.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.write(std.array.replicate(" ", indent), "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class HasDeclarations
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// List of interfaces declared in this module
|
|
||||||
Inherits[] interfaces;
|
|
||||||
|
|
||||||
/// List of classes declared in this module
|
|
||||||
Inherits[] classes;
|
|
||||||
|
|
||||||
/// List of functions declared in this module
|
|
||||||
Function[] functions;
|
|
||||||
|
|
||||||
/// List of unions declared in this module
|
|
||||||
Struct[] unions;
|
|
||||||
|
|
||||||
/// List of variables declared in this module
|
|
||||||
Variable[] variables;
|
|
||||||
|
|
||||||
/// List of structs declared in this module
|
|
||||||
Struct[] structs;
|
|
||||||
|
|
||||||
/// List of enums declared in this module
|
|
||||||
Enum[] enums;
|
|
||||||
|
|
||||||
/// List of aliases declared in this module
|
|
||||||
Alias[] aliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module is a container class for the other classes
|
|
||||||
*/
|
|
||||||
class Module : HasDeclarations
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Module name. Will be blank if there is no module statement
|
|
||||||
string name;
|
|
||||||
|
|
||||||
/// List of other modules that are imported by this one
|
|
||||||
string[] imports;
|
|
||||||
|
|
||||||
/// Combine this module with another one
|
|
||||||
void merge(Module other)
|
|
||||||
{
|
|
||||||
interfaces.insertInPlace(interfaces.length, other.interfaces);
|
|
||||||
classes.insertInPlace(classes.length, other.classes);
|
|
||||||
functions.insertInPlace(functions.length, other.functions);
|
|
||||||
unions.insertInPlace(unions.length, other.unions);
|
|
||||||
variables.insertInPlace(variables.length, other.variables);
|
|
||||||
structs.insertInPlace(structs.length, other.structs);
|
|
||||||
enums.insertInPlace(enums.length, other.enums);
|
|
||||||
imports.insertInPlace(imports.length, other.imports);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints a JSON representation of this module to the given file
|
|
||||||
*/
|
|
||||||
void writeJSONTo(File f) const
|
|
||||||
{
|
|
||||||
uint indent = 0;
|
|
||||||
f.writeln("{");
|
|
||||||
writeJSONString(f, "name", name, indent + 1);
|
|
||||||
f.writeln(",");
|
|
||||||
writeJSONString(f, "imports", imports, indent + 1);
|
|
||||||
f.writeln(",\n \"interfaces\" : [");
|
|
||||||
foreach(i, inter; interfaces)
|
|
||||||
{
|
|
||||||
inter.writeJSONTo(f, indent + 1);
|
|
||||||
if (i + 1 < interfaces.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(" ],\n \"classes\" : [");
|
|
||||||
foreach(i, cl; classes)
|
|
||||||
{
|
|
||||||
cl.writeJSONTo(f, indent + 1);
|
|
||||||
if (i + 1 < classes.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(" ],\n \"structs\" : [");
|
|
||||||
foreach(i, str; structs)
|
|
||||||
{
|
|
||||||
str.writeJSONTo(f, indent + 1);
|
|
||||||
if (i + 1 < structs.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(" ],\n \"unions\" : [");
|
|
||||||
foreach(i, un; unions)
|
|
||||||
{
|
|
||||||
un.writeJSONTo(f, indent + 1);
|
|
||||||
if (i + 1 < unions.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(" ],\n \"functions\" : [");
|
|
||||||
foreach(i, fun; functions)
|
|
||||||
{
|
|
||||||
fun.writeJSONTo(f, indent + 1);
|
|
||||||
if (i + 1 < functions.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(" ],\n \"variables\" : [");
|
|
||||||
foreach(i, var; variables)
|
|
||||||
{
|
|
||||||
var.writeJSONTo(f, indent + 1);
|
|
||||||
if (i + 1 < variables.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(" ],\n \"enums\" : [");
|
|
||||||
foreach(i, en; enums)
|
|
||||||
{
|
|
||||||
en.writeJSONTo(f, indent + 1);
|
|
||||||
if (i + 1 < enums.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(" ],\n \"aliases\" : [");
|
|
||||||
foreach(i, a; aliases)
|
|
||||||
{
|
|
||||||
a.writeJSONTo(f, indent + 1);
|
|
||||||
if (i + 1 < aliases.length)
|
|
||||||
f.writeln(",");
|
|
||||||
else
|
|
||||||
f.writeln();
|
|
||||||
}
|
|
||||||
f.writeln(" ]\n}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Standards: http://ctags.sourceforge.net/FORMAT
|
|
||||||
*/
|
|
||||||
void writeCtagsTo(File file, string fileName)
|
|
||||||
{
|
|
||||||
string[] tags;
|
|
||||||
foreach (Enum e; enums)
|
|
||||||
{
|
|
||||||
tags ~= e.getCtags(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Variable v; variables)
|
|
||||||
{
|
|
||||||
tags ~= format("%s\t%s\t%d;\"\tv", v.name, fileName, v.line);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Function f; functions)
|
|
||||||
{
|
|
||||||
tags ~= format("%s\t%s\t%d;\"\tf\tarity:%d", f.name, fileName,
|
|
||||||
f.line, f.parameters.length);
|
|
||||||
}
|
|
||||||
foreach (Inherits c; classes)
|
|
||||||
{
|
|
||||||
tags ~= c.getCtags(fileName);
|
|
||||||
}
|
|
||||||
foreach (Inherits i; interfaces)
|
|
||||||
{
|
|
||||||
tags ~= i.getCtags(fileName);
|
|
||||||
}
|
|
||||||
foreach (Struct s; structs)
|
|
||||||
{
|
|
||||||
tags ~= s.getCtags(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
sort(tags);
|
|
||||||
file.writeln("!_TAG_FILE_FORMAT 2");
|
|
||||||
file.writeln("!_TAG_FILE_SORTED 1");
|
|
||||||
file.writeln("!_TAG_PROGRAM_URL https://github.com/Hackerpilot/Dscanner/");
|
|
||||||
foreach (tag; tags)
|
|
||||||
{
|
|
||||||
file.writeln(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
immutable(string[string][string]) typeProperties; // Yo dawg I heard you like maps...
|
|
||||||
immutable(string[string]) floatProperties;
|
|
||||||
immutable(string[string]) integralProperties;
|
|
||||||
immutable(string[string]) commonProperties;
|
|
||||||
immutable(string[string]) arrayProperties;
|
|
||||||
|
|
||||||
static this()
|
|
||||||
{
|
|
||||||
// <#> means "its own type"
|
|
||||||
// for example float.max is of type float
|
|
||||||
floatProperties = [
|
|
||||||
"alignof" : "int",
|
|
||||||
"dig" : "<#>",
|
|
||||||
"epsilon" : "<#>",
|
|
||||||
"im" : "<#>",
|
|
||||||
"infinity" : "<#>",
|
|
||||||
"init" : "<#>",
|
|
||||||
"mangleof" : "string",
|
|
||||||
"mant_dig" : "int",
|
|
||||||
"max" : "<#>",
|
|
||||||
"max_10_exp" : "int",
|
|
||||||
"max_exp" : "int",
|
|
||||||
"min_10_exp" : "int",
|
|
||||||
"min_exp" : "int",
|
|
||||||
"min_normal" : "<#>",
|
|
||||||
"nan" : "<#>",
|
|
||||||
"re" : "<#>",
|
|
||||||
"sizeof" : "size_t"
|
|
||||||
];
|
|
||||||
|
|
||||||
integralProperties = [
|
|
||||||
"alignof" : "int",
|
|
||||||
"init" : "<#>",
|
|
||||||
"mangleof" : "string",
|
|
||||||
"max" : "<#>",
|
|
||||||
"min" : "<#>",
|
|
||||||
"sizeof" : "size_t",
|
|
||||||
"stringof" : "string"
|
|
||||||
];
|
|
||||||
|
|
||||||
commonProperties = [
|
|
||||||
"alignof" : "int",
|
|
||||||
"init" : "<#>",
|
|
||||||
"mangleof" : "string",
|
|
||||||
"stringof" : "string"
|
|
||||||
];
|
|
||||||
|
|
||||||
arrayProperties = [
|
|
||||||
"alignof" : "int",
|
|
||||||
"init" : "<#>",
|
|
||||||
"length" : "size_t",
|
|
||||||
"mangleof" : "string",
|
|
||||||
"ptr" : "<#>*",
|
|
||||||
"stringof" : "string",
|
|
||||||
];
|
|
||||||
|
|
||||||
typeProperties = [
|
|
||||||
"bool" : commonProperties,
|
|
||||||
"byte" : integralProperties,
|
|
||||||
"ubyte" : integralProperties,
|
|
||||||
"short" : integralProperties,
|
|
||||||
"ushort" : integralProperties,
|
|
||||||
"int" : integralProperties,
|
|
||||||
"uint" : integralProperties,
|
|
||||||
"long" : integralProperties,
|
|
||||||
"ulong" : integralProperties,
|
|
||||||
"cent" : integralProperties,
|
|
||||||
"ucent" : integralProperties,
|
|
||||||
"float" : floatProperties,
|
|
||||||
"double" : floatProperties,
|
|
||||||
"real" : floatProperties,
|
|
||||||
"ifloat" : floatProperties,
|
|
||||||
"idouble" : floatProperties,
|
|
||||||
"ireal" : floatProperties,
|
|
||||||
"cfloat" : floatProperties,
|
|
||||||
"cdouble" : floatProperties,
|
|
||||||
"creal" : floatProperties,
|
|
||||||
"char" : commonProperties,
|
|
||||||
"wchar" : commonProperties,
|
|
||||||
"dchar" : commonProperties,
|
|
||||||
"ptrdiff_t" : integralProperties,
|
|
||||||
"size_t" : integralProperties,
|
|
||||||
"string" : arrayProperties,
|
|
||||||
"wstring" : arrayProperties,
|
|
||||||
"dstring" : arrayProperties
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
class CompletionContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
this(Module mod)
|
|
||||||
{
|
|
||||||
this.currentModule = mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tuple!(string, string)[string] getMembersOfType(string name)
|
|
||||||
{
|
|
||||||
// Arrays
|
|
||||||
if (name.length > 2 && name[$ - 2 .. $] == "[]")
|
|
||||||
{
|
|
||||||
Tuple!(string, string)[string] typeMap;
|
|
||||||
foreach(k, v; arrayProperties)
|
|
||||||
typeMap[k] = Tuple!(string, string)(v, "m");
|
|
||||||
return typeMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic types
|
|
||||||
auto tp = name in typeProperties;
|
|
||||||
if (tp !is null)
|
|
||||||
{
|
|
||||||
Tuple!(string, string)[string] typeMap;
|
|
||||||
foreach (k, v; *tp)
|
|
||||||
typeMap[k] = Tuple!(string, string)(v.replace("<#>", name), "m");
|
|
||||||
return typeMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// User-defined types
|
|
||||||
foreach (m; chain(modules, [currentModule]))
|
|
||||||
{
|
|
||||||
foreach (inherits; chain(m.interfaces, m.classes))
|
|
||||||
{
|
|
||||||
if (inherits.name != name)
|
|
||||||
continue;
|
|
||||||
Tuple!(string, string)[string] typeMap;
|
|
||||||
foreach (var; inherits.variables)
|
|
||||||
typeMap[var.name] = Tuple!(string, string)(var.type, "m");
|
|
||||||
foreach (fun; inherits.functions)
|
|
||||||
typeMap[fun.name] = Tuple!(string, string)(fun.returnType, "f");
|
|
||||||
foreach (parent; inherits.baseClasses)
|
|
||||||
{
|
|
||||||
foreach (k, v; getMembersOfType(parent))
|
|
||||||
{
|
|
||||||
typeMap[k] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
typeMap["classInfo"] = Tuple!(string, string)("TypeInfo_Class", "m");
|
|
||||||
return typeMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (s; chain(m.structs, m.unions))
|
|
||||||
{
|
|
||||||
if (s.name != name)
|
|
||||||
continue;
|
|
||||||
Tuple!(string, string)[string] typeMap;
|
|
||||||
foreach (var; s.variables)
|
|
||||||
typeMap[var.name] = Tuple!(string, string)(var.type, "m");
|
|
||||||
foreach (fun; s.functions)
|
|
||||||
typeMap[fun.name] = Tuple!(string, string)(fun.returnType, "f");
|
|
||||||
return typeMap;
|
|
||||||
}
|
|
||||||
foreach (Enum e; m.enums)
|
|
||||||
{
|
|
||||||
if (e.name != name)
|
|
||||||
continue;
|
|
||||||
Tuple!(string, string)[string] typeMap;
|
|
||||||
foreach (member; e.members)
|
|
||||||
typeMap[member.name] = Tuple!(string, string)(member.type, "e");
|
|
||||||
return typeMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Struct[] getStructsContaining(size_t cursorPosition)
|
|
||||||
{
|
|
||||||
auto app = appender!(Struct[])();
|
|
||||||
foreach(s; chain(currentModule.structs, currentModule.interfaces,
|
|
||||||
currentModule.classes, currentModule.unions))
|
|
||||||
{
|
|
||||||
if (s.bodyStart <= cursorPosition && s.bodyEnd >= cursorPosition)
|
|
||||||
app.put(s);
|
|
||||||
}
|
|
||||||
return app.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
string[] getCallTipsFor(string container, string functionName,
|
|
||||||
size_t cursorPosition)
|
|
||||||
{
|
|
||||||
if (container == null || container.length == 0 || container == "void")
|
|
||||||
{
|
|
||||||
// Try member functions first if the cursor is inside of a class
|
|
||||||
// or structure definiton
|
|
||||||
Struct[] structs = getStructsContaining(cursorPosition);
|
|
||||||
foreach (s; structs)
|
|
||||||
{
|
|
||||||
auto docs = s.getFunctionDocs(functionName);
|
|
||||||
if (docs.length > 0)
|
|
||||||
return docs;
|
|
||||||
}
|
|
||||||
// Try global functions if the above failed.
|
|
||||||
return getCallTipsFor(functionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (m; chain(modules, [currentModule]))
|
|
||||||
{
|
|
||||||
foreach (s; chain(m.structs, m.interfaces, m.classes, m.unions))
|
|
||||||
{
|
|
||||||
if (s.name != container)
|
|
||||||
continue;
|
|
||||||
return s.getFunctionDocs(functionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
void addModule(Module mod)
|
|
||||||
{
|
|
||||||
modules ~= mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module currentModule;
|
|
||||||
Module[] modules;
|
|
||||||
string[] importDirectories;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
string[] getCallTipsFor(string functionName)
|
|
||||||
{
|
|
||||||
stderr.writeln("Getting call tips for ", functionName);
|
|
||||||
auto app = appender!(string[])();
|
|
||||||
foreach (m; chain(modules, [currentModule]))
|
|
||||||
{
|
|
||||||
foreach (fun; m.functions)
|
|
||||||
{
|
|
||||||
if (fun.name == functionName)
|
|
||||||
app.put(fun.documentString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return app.data;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue