Added basic XML output

This commit is contained in:
Hackerpilot 2013-07-23 01:46:08 +00:00
parent a5fd3efdb8
commit 1aec76fdea
4 changed files with 180 additions and 48 deletions

72
astprinter.d Normal file
View File

@ -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
View File

@ -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

View File

@ -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;
}

View File

@ -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