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 stats;
|
||||
import ctags;
|
||||
import astprinter;
|
||||
|
||||
int main(string[] args)
|
||||
{
|
||||
|
@ -28,19 +29,20 @@ int main(string[] args)
|
|||
bool sloc;
|
||||
bool highlight;
|
||||
bool ctags;
|
||||
bool json;
|
||||
bool recursive;
|
||||
bool format;
|
||||
bool help;
|
||||
bool tokenCount;
|
||||
bool syntaxCheck;
|
||||
bool ast;
|
||||
|
||||
try
|
||||
{
|
||||
getopt(args, "I", &importDirs, "sloc|l", &sloc,
|
||||
"json|j", &json, "highlight", &highlight,
|
||||
"highlight", &highlight,
|
||||
"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)
|
||||
{
|
||||
|
@ -53,8 +55,8 @@ int main(string[] args)
|
|||
return 0;
|
||||
}
|
||||
|
||||
auto optionCount = count!"a"([sloc, highlight, ctags, json, tokenCount,
|
||||
syntaxCheck]);
|
||||
auto optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
|
||||
syntaxCheck, ast]);
|
||||
if (optionCount > 1)
|
||||
{
|
||||
stderr.writeln("Too many options specified");
|
||||
|
@ -104,6 +106,13 @@ int main(string[] args)
|
|||
{
|
||||
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;
|
||||
|
@ -123,10 +132,6 @@ options:
|
|||
count the number of logical lines of code in the given
|
||||
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
|
||||
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
|
||||
of a filename.
|
||||
|
||||
--ast | --xml sourceFile
|
||||
Generates an XML representation of the source files abstract syntax tree
|
||||
|
||||
--recursive | -R | -r directory
|
||||
When used with --ctags, dscanner will produce ctags output for all .d
|
||||
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) {}};
|
||||
|
||||
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 {}
|
||||
|
||||
mixin template BinaryExpressionBody()
|
||||
|
@ -254,7 +262,14 @@ public:
|
|||
class AliasDeclaration : ASTNode
|
||||
{
|
||||
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;
|
||||
/** */ Declarator declarator;
|
||||
/** */ AliasInitializer[] initializers;
|
||||
|
@ -264,7 +279,11 @@ public:
|
|||
class AliasInitializer : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
if (type !is null) visitor.visit(type);
|
||||
}
|
||||
|
||||
/** */ Token identifier;
|
||||
/** */ Type type;
|
||||
}
|
||||
|
@ -305,7 +324,14 @@ public:
|
|||
class ArgumentList : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
foreach (item; items)
|
||||
{
|
||||
if (item !is null)
|
||||
visitor.visit(item);
|
||||
}
|
||||
}
|
||||
/** */ AssignExpression[] items;
|
||||
}
|
||||
|
||||
|
@ -313,7 +339,11 @@ public:
|
|||
class Arguments : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
if (argumentList !is null)
|
||||
visitor.visit(argumentList);
|
||||
}
|
||||
/** */ ArgumentList argumentList;
|
||||
}
|
||||
|
||||
|
@ -321,7 +351,13 @@ public:
|
|||
class ArrayInitializer : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
foreach(init; arrayMemberInitializations)
|
||||
{
|
||||
if (init !is null) visitor.visit(init);
|
||||
}
|
||||
}
|
||||
/** */ ArrayMemberInitialization[] arrayMemberInitializations;
|
||||
}
|
||||
|
||||
|
@ -784,30 +820,16 @@ public:
|
|||
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
if (importDeclaration !is null) visitor.visit(importDeclaration);
|
||||
if (functionDeclaration !is null) visitor.visit(functionDeclaration);
|
||||
if (variableDeclaration !is null) visitor.visit(variableDeclaration);
|
||||
if (aliasThisDeclaration !is null) visitor.visit(aliasThisDeclaration);
|
||||
if (structDeclaration !is null) visitor.visit(structDeclaration);
|
||||
if (classDeclaration !is null) visitor.visit(classDeclaration);
|
||||
if (interfaceDeclaration !is null) visitor.visit(interfaceDeclaration);
|
||||
if (unionDeclaration !is null) visitor.visit(unionDeclaration);
|
||||
if (enumDeclaration !is null) visitor.visit(enumDeclaration);
|
||||
if (aliasDeclaration !is null) visitor.visit(aliasDeclaration);
|
||||
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);
|
||||
|
||||
mixin(visitIfNotNull!(importDeclaration, functionDeclaration,
|
||||
variableDeclaration, aliasThisDeclaration, structDeclaration,
|
||||
classDeclaration, interfaceDeclaration, unionDeclaration,
|
||||
enumDeclaration, aliasDeclaration, mixinDeclaration,
|
||||
mixinTemplateDeclaration, unittest_, staticAssertDeclaration,
|
||||
templateDeclaration, constructor,
|
||||
destructor, staticConstructor, staticDestructor,
|
||||
sharedStaticDestructor, sharedStaticConstructor,
|
||||
conditionalDeclaration, pragmaDeclaration, versionSpecification));
|
||||
}
|
||||
|
||||
/** */ Attribute[] attributes;
|
||||
|
@ -873,7 +895,12 @@ public:
|
|||
class Declarator : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
mixin(visitIfNotNull!(initializer));
|
||||
}
|
||||
|
||||
/** */ Token name;
|
||||
/** */ Initializer initializer;
|
||||
}
|
||||
|
@ -931,7 +958,13 @@ public:
|
|||
class EnumBody : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
foreach (member; enumMembers)
|
||||
{
|
||||
if (member !is null) visitor.visit(member);
|
||||
}
|
||||
}
|
||||
/** */ EnumMember[] enumMembers;
|
||||
}
|
||||
|
||||
|
@ -939,7 +972,10 @@ public:
|
|||
class EnumDeclaration : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
mixin(visitIfNotNull!(type, enumBody));
|
||||
}
|
||||
/** */ Token name;
|
||||
/** */ Type type;
|
||||
/** */ EnumBody enumBody;
|
||||
|
@ -949,8 +985,11 @@ public:
|
|||
class EnumMember : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
/** */ Token identifier;
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
mixin(visitIfNotNull!(type, assignExpression));
|
||||
}
|
||||
/** */ Token name;
|
||||
/** */ Type type;
|
||||
/** */ AssignExpression assignExpression;
|
||||
}
|
||||
|
@ -1416,7 +1455,10 @@ public:
|
|||
class ModuleDeclaration : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
if (moduleName !is null) visitor.visit(moduleName);
|
||||
}
|
||||
/** */ IdentifierChain moduleName;
|
||||
}
|
||||
|
||||
|
@ -2196,7 +2238,11 @@ public:
|
|||
class WhileStatement : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
mixin(visitIfNotNull!(expression, statementNoCaseNoDefault));
|
||||
}
|
||||
|
||||
/** */ Expression expression;
|
||||
/** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
|
||||
}
|
||||
|
@ -2205,7 +2251,11 @@ public:
|
|||
class WithStatement : ASTNode
|
||||
{
|
||||
public:
|
||||
mixin(DEFAULT_ACCEPT);
|
||||
override void accept(ASTVisitor visitor)
|
||||
{
|
||||
mixin(visitIfNotNull!(expression, statementNoCaseNoDefault));
|
||||
}
|
||||
|
||||
/** */ Expression expression;
|
||||
/** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
|
||||
}
|
||||
|
|
|
@ -2002,6 +2002,8 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
|
|||
if (expect(TokenType.enum_) is null) return null;
|
||||
if (currentIs(TokenType.identifier))
|
||||
node.name = advance();
|
||||
else
|
||||
node.name.line = tokens[index - 1].line; // preserve line number if anonymous
|
||||
if (currentIs(TokenType.colon))
|
||||
{
|
||||
advance();
|
||||
|
@ -2026,10 +2028,10 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
|
|||
if (currentIs(TokenType.identifier))
|
||||
{
|
||||
if (peekIsOneOf(TokenType.comma, TokenType.rBrace))
|
||||
node.identifier = advance();
|
||||
node.name = advance();
|
||||
else if (peekIs(TokenType.assign))
|
||||
{
|
||||
node.identifier = advance();
|
||||
node.name = advance();
|
||||
goto assign;
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue