From 1aec76fdea5e1db5097c5ed62d9293ea910f6670 Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Tue, 23 Jul 2013 01:46:08 +0000 Subject: [PATCH] Added basic XML output --- astprinter.d | 72 ++++++++++++++++++++++++++++ main.d | 26 +++++++---- std/d/ast.d | 124 ++++++++++++++++++++++++++++++++++--------------- std/d/parser.d | 6 ++- 4 files changed, 180 insertions(+), 48 deletions(-) create mode 100644 astprinter.d diff --git a/astprinter.d b/astprinter.d new file mode 100644 index 0000000..4d4a2fa --- /dev/null +++ b/astprinter.d @@ -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(""); + mod.accept(this); + output.writeln(""); + } + + override void visit(ModuleDeclaration modDec) + { + output.writeln(""); + modDec.accept(this); + output.writeln(""); + } + + override void visit(IdentifierChain chain) + { + output.writeln(""); + foreach (ident; chain.identifiers) + { + output.writeln("", ident.value, ""); + } + output.writeln(""); + } + + override void visit(ClassDeclaration classDec) + { + output.writeln(""); + output.writeln("", classDec.name.value, ""); + output.writeln(""); + } + + override void visit(StructDeclaration structDec) + { + output.writeln(""); + output.writeln("", structDec.name.value, ""); + output.writeln(""); + } + + override void visit(FunctionDeclaration functionDec) + { + output.writeln(""); + output.writeln("", functionDec.name.value, ""); + output.writeln(""); + } + + override void visit(EnumDeclaration enumDec) + { + output.writeln(""); + if (enumDec.name.type == TokenType.identifier) + output.writeln("", enumDec.name.value, ""); + enumDec.accept(this); + output.writeln(""); + } + + override void visit(EnumMember enumMem) + { + output.writeln(""); + output.writeln("", enumMem.name.value, ""); + enumMem.accept(this); + output.writeln(""); + } + + alias ASTVisitor.visit visit; + + File output; +} diff --git a/main.d b/main.d index b431c3c..99a573c 100755 --- a/main.d +++ b/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 diff --git a/std/d/ast.d b/std/d/ast.d index b92cf81..881674e 100755 --- a/std/d/ast.d +++ b/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; } diff --git a/std/d/parser.d b/std/d/parser.d index 7d0157c..39b885e 100755 --- a/std/d/parser.d +++ b/std/d/parser.d @@ -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