Added basic XML output
This commit is contained in:
parent
a5fd3efdb8
commit
1aec76fdea
|
|
@ -0,0 +1,72 @@
|
||||||
|
import std.d.lexer;
|
||||||
|
import std.d.ast;
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
class XMLPrinter : ASTVisitor
|
||||||
|
{
|
||||||
|
override void visit(Module mod)
|
||||||
|
{
|
||||||
|
output.writeln("<module>");
|
||||||
|
mod.accept(this);
|
||||||
|
output.writeln("</module>");
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(ModuleDeclaration modDec)
|
||||||
|
{
|
||||||
|
output.writeln("<moduleDeclaration>");
|
||||||
|
modDec.accept(this);
|
||||||
|
output.writeln("</moduleDeclaration>");
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(IdentifierChain chain)
|
||||||
|
{
|
||||||
|
output.writeln("<identifierChain>");
|
||||||
|
foreach (ident; chain.identifiers)
|
||||||
|
{
|
||||||
|
output.writeln("<identifier>", ident.value, "</identifier>");
|
||||||
|
}
|
||||||
|
output.writeln("</identifierChain>");
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(ClassDeclaration classDec)
|
||||||
|
{
|
||||||
|
output.writeln("<classDeclaration line=\"", classDec.name.line, "\">");
|
||||||
|
output.writeln("<name>", classDec.name.value, "</name>");
|
||||||
|
output.writeln("</classDeclaration>");
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(StructDeclaration structDec)
|
||||||
|
{
|
||||||
|
output.writeln("<structDeclaration line=\"", structDec.name.line, "\">");
|
||||||
|
output.writeln("<name>", structDec.name.value, "</name>");
|
||||||
|
output.writeln("</structDeclaration>");
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(FunctionDeclaration functionDec)
|
||||||
|
{
|
||||||
|
output.writeln("<functionDeclaration line=\"", functionDec.name.line, "\">");
|
||||||
|
output.writeln("<name>", functionDec.name.value, "</name>");
|
||||||
|
output.writeln("</functionDeclaration>");
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(EnumDeclaration enumDec)
|
||||||
|
{
|
||||||
|
output.writeln("<enumDeclaration line=\"", enumDec.name.line, "\">");
|
||||||
|
if (enumDec.name.type == TokenType.identifier)
|
||||||
|
output.writeln("<name>", enumDec.name.value, "</name>");
|
||||||
|
enumDec.accept(this);
|
||||||
|
output.writeln("</enumDeclaration>");
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(EnumMember enumMem)
|
||||||
|
{
|
||||||
|
output.writeln("<enumMember line=\"", enumMem.name.line, "\">");
|
||||||
|
output.writeln("<name>", enumMem.name.value, "</name>");
|
||||||
|
enumMem.accept(this);
|
||||||
|
output.writeln("</enumMember>");
|
||||||
|
}
|
||||||
|
|
||||||
|
alias ASTVisitor.visit visit;
|
||||||
|
|
||||||
|
File output;
|
||||||
|
}
|
||||||
26
main.d
26
main.d
|
|
@ -21,6 +21,7 @@ import std.d.parser;
|
||||||
import highlighter;
|
import highlighter;
|
||||||
import stats;
|
import stats;
|
||||||
import ctags;
|
import ctags;
|
||||||
|
import astprinter;
|
||||||
|
|
||||||
int main(string[] args)
|
int main(string[] args)
|
||||||
{
|
{
|
||||||
|
|
@ -28,19 +29,20 @@ int main(string[] args)
|
||||||
bool sloc;
|
bool sloc;
|
||||||
bool highlight;
|
bool highlight;
|
||||||
bool ctags;
|
bool ctags;
|
||||||
bool json;
|
|
||||||
bool recursive;
|
bool recursive;
|
||||||
bool format;
|
bool format;
|
||||||
bool help;
|
bool help;
|
||||||
bool tokenCount;
|
bool tokenCount;
|
||||||
bool syntaxCheck;
|
bool syntaxCheck;
|
||||||
|
bool ast;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
getopt(args, "I", &importDirs, "sloc|l", &sloc,
|
getopt(args, "I", &importDirs, "sloc|l", &sloc,
|
||||||
"json|j", &json, "highlight", &highlight,
|
"highlight", &highlight,
|
||||||
"ctags|c", &ctags, "recursive|r|R", &recursive, "help|h", &help,
|
"ctags|c", &ctags, "recursive|r|R", &recursive, "help|h", &help,
|
||||||
"tokenCount", &tokenCount, "syntaxCheck|s", &syntaxCheck);
|
"tokenCount", &tokenCount, "syntaxCheck|s", &syntaxCheck,
|
||||||
|
"ast|xml", &ast);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -53,8 +55,8 @@ int main(string[] args)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto optionCount = count!"a"([sloc, highlight, ctags, json, tokenCount,
|
auto optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
|
||||||
syntaxCheck]);
|
syntaxCheck, ast]);
|
||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
{
|
{
|
||||||
stderr.writeln("Too many options specified");
|
stderr.writeln("Too many options specified");
|
||||||
|
|
@ -104,6 +106,13 @@ int main(string[] args)
|
||||||
{
|
{
|
||||||
parseModule(tokens.array(), args[1]);
|
parseModule(tokens.array(), args[1]);
|
||||||
}
|
}
|
||||||
|
else if (ast)
|
||||||
|
{
|
||||||
|
auto mod = parseModule(tokens.array(), args[1]);
|
||||||
|
auto printer = new XMLPrinter;
|
||||||
|
printer.output = stdout;
|
||||||
|
printer.visit(mod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -123,10 +132,6 @@ options:
|
||||||
count the number of logical lines of code in the given
|
count the number of logical lines of code in the given
|
||||||
source files. If no files are specified, a file is read from stdin.
|
source files. If no files are specified, a file is read from stdin.
|
||||||
|
|
||||||
--json | -j [sourceFile]
|
|
||||||
Generate a JSON summary of the given source file. If no file is
|
|
||||||
specifed, the file is read from stdin.
|
|
||||||
|
|
||||||
--highlight [sourceFile] - Syntax-highlight the given source file. The
|
--highlight [sourceFile] - Syntax-highlight the given source file. The
|
||||||
resulting HTML will be written to standard output.
|
resulting HTML will be written to standard output.
|
||||||
|
|
||||||
|
|
@ -148,6 +153,9 @@ options:
|
||||||
ctags information requires a filename, so stdin cannot be used in place
|
ctags information requires a filename, so stdin cannot be used in place
|
||||||
of a filename.
|
of a filename.
|
||||||
|
|
||||||
|
--ast | --xml sourceFile
|
||||||
|
Generates an XML representation of the source files abstract syntax tree
|
||||||
|
|
||||||
--recursive | -R | -r directory
|
--recursive | -R | -r directory
|
||||||
When used with --ctags, dscanner will produce ctags output for all .d
|
When used with --ctags, dscanner will produce ctags output for all .d
|
||||||
and .di files contained within the given directory and its
|
and .di files contained within the given directory and its
|
||||||
|
|
|
||||||
124
std/d/ast.d
124
std/d/ast.d
|
|
@ -233,6 +233,14 @@ interface ASTNode
|
||||||
|
|
||||||
immutable string DEFAULT_ACCEPT = q{void accept(ASTVisitor visitor) {}};
|
immutable string DEFAULT_ACCEPT = q{void accept(ASTVisitor visitor) {}};
|
||||||
|
|
||||||
|
template visitIfNotNull(fields ...)
|
||||||
|
{
|
||||||
|
static if (fields.length > 1)
|
||||||
|
immutable visitIfNotNull = visitIfNotNull!(fields[0]) ~ visitIfNotNull!(fields[1..$]);
|
||||||
|
else
|
||||||
|
immutable visitIfNotNull = "if (" ~ fields[0].stringof ~ " !is null) visitor.visit(" ~ fields[0].stringof ~ ");";
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ExpressionNode : ASTNode {}
|
abstract class ExpressionNode : ASTNode {}
|
||||||
|
|
||||||
mixin template BinaryExpressionBody()
|
mixin template BinaryExpressionBody()
|
||||||
|
|
@ -254,7 +262,14 @@ public:
|
||||||
class AliasDeclaration : ASTNode
|
class AliasDeclaration : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
mixin(visitIfNotNull!(type, declarator));
|
||||||
|
foreach (initializer; initializers)
|
||||||
|
{
|
||||||
|
if (initializers !is null) visitor.visit(initializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
/** */ Type type;
|
/** */ Type type;
|
||||||
/** */ Declarator declarator;
|
/** */ Declarator declarator;
|
||||||
/** */ AliasInitializer[] initializers;
|
/** */ AliasInitializer[] initializers;
|
||||||
|
|
@ -264,7 +279,11 @@ public:
|
||||||
class AliasInitializer : ASTNode
|
class AliasInitializer : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
if (type !is null) visitor.visit(type);
|
||||||
|
}
|
||||||
|
|
||||||
/** */ Token identifier;
|
/** */ Token identifier;
|
||||||
/** */ Type type;
|
/** */ Type type;
|
||||||
}
|
}
|
||||||
|
|
@ -305,7 +324,14 @@ public:
|
||||||
class ArgumentList : ASTNode
|
class ArgumentList : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
foreach (item; items)
|
||||||
|
{
|
||||||
|
if (item !is null)
|
||||||
|
visitor.visit(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
/** */ AssignExpression[] items;
|
/** */ AssignExpression[] items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,7 +339,11 @@ public:
|
||||||
class Arguments : ASTNode
|
class Arguments : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
if (argumentList !is null)
|
||||||
|
visitor.visit(argumentList);
|
||||||
|
}
|
||||||
/** */ ArgumentList argumentList;
|
/** */ ArgumentList argumentList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -321,7 +351,13 @@ public:
|
||||||
class ArrayInitializer : ASTNode
|
class ArrayInitializer : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
foreach(init; arrayMemberInitializations)
|
||||||
|
{
|
||||||
|
if (init !is null) visitor.visit(init);
|
||||||
|
}
|
||||||
|
}
|
||||||
/** */ ArrayMemberInitialization[] arrayMemberInitializations;
|
/** */ ArrayMemberInitialization[] arrayMemberInitializations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -784,30 +820,16 @@ public:
|
||||||
|
|
||||||
override void accept(ASTVisitor visitor)
|
override void accept(ASTVisitor visitor)
|
||||||
{
|
{
|
||||||
if (importDeclaration !is null) visitor.visit(importDeclaration);
|
|
||||||
if (functionDeclaration !is null) visitor.visit(functionDeclaration);
|
mixin(visitIfNotNull!(importDeclaration, functionDeclaration,
|
||||||
if (variableDeclaration !is null) visitor.visit(variableDeclaration);
|
variableDeclaration, aliasThisDeclaration, structDeclaration,
|
||||||
if (aliasThisDeclaration !is null) visitor.visit(aliasThisDeclaration);
|
classDeclaration, interfaceDeclaration, unionDeclaration,
|
||||||
if (structDeclaration !is null) visitor.visit(structDeclaration);
|
enumDeclaration, aliasDeclaration, mixinDeclaration,
|
||||||
if (classDeclaration !is null) visitor.visit(classDeclaration);
|
mixinTemplateDeclaration, unittest_, staticAssertDeclaration,
|
||||||
if (interfaceDeclaration !is null) visitor.visit(interfaceDeclaration);
|
templateDeclaration, constructor,
|
||||||
if (unionDeclaration !is null) visitor.visit(unionDeclaration);
|
destructor, staticConstructor, staticDestructor,
|
||||||
if (enumDeclaration !is null) visitor.visit(enumDeclaration);
|
sharedStaticDestructor, sharedStaticConstructor,
|
||||||
if (aliasDeclaration !is null) visitor.visit(aliasDeclaration);
|
conditionalDeclaration, pragmaDeclaration, versionSpecification));
|
||||||
if (mixinDeclaration !is null) visitor.visit(mixinDeclaration);
|
|
||||||
if (mixinTemplateDeclaration !is null) visitor.visit(mixinTemplateDeclaration);
|
|
||||||
if (unittest_ !is null) visitor.visit(unittest_);
|
|
||||||
if (staticAssertDeclaration !is null) visitor.visit(staticAssertDeclaration);
|
|
||||||
if (templateDeclaration !is null) visitor.visit(templateDeclaration);
|
|
||||||
if (constructor !is null) visitor.visit(constructor);
|
|
||||||
if (destructor !is null) visitor.visit(destructor);
|
|
||||||
if (staticConstructor !is null) visitor.visit(staticConstructor);
|
|
||||||
if (staticDestructor !is null) visitor.visit(staticDestructor);
|
|
||||||
if (sharedStaticDestructor !is null) visitor.visit(sharedStaticDestructor);
|
|
||||||
if (sharedStaticConstructor !is null) visitor.visit(sharedStaticConstructor);
|
|
||||||
if (conditionalDeclaration !is null) visitor.visit(conditionalDeclaration);
|
|
||||||
if (pragmaDeclaration !is null) visitor.visit(pragmaDeclaration);
|
|
||||||
if (versionSpecification !is null) visitor.visit(versionSpecification);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */ Attribute[] attributes;
|
/** */ Attribute[] attributes;
|
||||||
|
|
@ -873,7 +895,12 @@ public:
|
||||||
class Declarator : ASTNode
|
class Declarator : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
|
||||||
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
mixin(visitIfNotNull!(initializer));
|
||||||
|
}
|
||||||
|
|
||||||
/** */ Token name;
|
/** */ Token name;
|
||||||
/** */ Initializer initializer;
|
/** */ Initializer initializer;
|
||||||
}
|
}
|
||||||
|
|
@ -931,7 +958,13 @@ public:
|
||||||
class EnumBody : ASTNode
|
class EnumBody : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
foreach (member; enumMembers)
|
||||||
|
{
|
||||||
|
if (member !is null) visitor.visit(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
/** */ EnumMember[] enumMembers;
|
/** */ EnumMember[] enumMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -939,7 +972,10 @@ public:
|
||||||
class EnumDeclaration : ASTNode
|
class EnumDeclaration : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
mixin(visitIfNotNull!(type, enumBody));
|
||||||
|
}
|
||||||
/** */ Token name;
|
/** */ Token name;
|
||||||
/** */ Type type;
|
/** */ Type type;
|
||||||
/** */ EnumBody enumBody;
|
/** */ EnumBody enumBody;
|
||||||
|
|
@ -949,8 +985,11 @@ public:
|
||||||
class EnumMember : ASTNode
|
class EnumMember : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
/** */ Token identifier;
|
{
|
||||||
|
mixin(visitIfNotNull!(type, assignExpression));
|
||||||
|
}
|
||||||
|
/** */ Token name;
|
||||||
/** */ Type type;
|
/** */ Type type;
|
||||||
/** */ AssignExpression assignExpression;
|
/** */ AssignExpression assignExpression;
|
||||||
}
|
}
|
||||||
|
|
@ -1416,7 +1455,10 @@ public:
|
||||||
class ModuleDeclaration : ASTNode
|
class ModuleDeclaration : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
if (moduleName !is null) visitor.visit(moduleName);
|
||||||
|
}
|
||||||
/** */ IdentifierChain moduleName;
|
/** */ IdentifierChain moduleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2196,7 +2238,11 @@ public:
|
||||||
class WhileStatement : ASTNode
|
class WhileStatement : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
mixin(visitIfNotNull!(expression, statementNoCaseNoDefault));
|
||||||
|
}
|
||||||
|
|
||||||
/** */ Expression expression;
|
/** */ Expression expression;
|
||||||
/** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
|
/** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
|
||||||
}
|
}
|
||||||
|
|
@ -2205,7 +2251,11 @@ public:
|
||||||
class WithStatement : ASTNode
|
class WithStatement : ASTNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mixin(DEFAULT_ACCEPT);
|
override void accept(ASTVisitor visitor)
|
||||||
|
{
|
||||||
|
mixin(visitIfNotNull!(expression, statementNoCaseNoDefault));
|
||||||
|
}
|
||||||
|
|
||||||
/** */ Expression expression;
|
/** */ Expression expression;
|
||||||
/** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
|
/** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2002,6 +2002,8 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
|
||||||
if (expect(TokenType.enum_) is null) return null;
|
if (expect(TokenType.enum_) is null) return null;
|
||||||
if (currentIs(TokenType.identifier))
|
if (currentIs(TokenType.identifier))
|
||||||
node.name = advance();
|
node.name = advance();
|
||||||
|
else
|
||||||
|
node.name.line = tokens[index - 1].line; // preserve line number if anonymous
|
||||||
if (currentIs(TokenType.colon))
|
if (currentIs(TokenType.colon))
|
||||||
{
|
{
|
||||||
advance();
|
advance();
|
||||||
|
|
@ -2026,10 +2028,10 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
|
||||||
if (currentIs(TokenType.identifier))
|
if (currentIs(TokenType.identifier))
|
||||||
{
|
{
|
||||||
if (peekIsOneOf(TokenType.comma, TokenType.rBrace))
|
if (peekIsOneOf(TokenType.comma, TokenType.rBrace))
|
||||||
node.identifier = advance();
|
node.name = advance();
|
||||||
else if (peekIs(TokenType.assign))
|
else if (peekIs(TokenType.assign))
|
||||||
{
|
{
|
||||||
node.identifier = advance();
|
node.name = advance();
|
||||||
goto assign;
|
goto assign;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue