/* ***************************************************************************** * ES4Doc.java * ****************************************************************************/ /* J_LZ_COPYRIGHT_BEGIN ******************************************************* * Copyright 2006 Laszlo Systems, Inc. All Rights Reserved. * * Use is subject to license terms. * * J_LZ_COPYRIGHT_END *********************************************************/ package org.openlaszlo.es4doc; import org.openlaszlo.sc.Compiler; import org.openlaszlo.sc.parser.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.*; import java.io.*; import java.util.*; public class ES4Doc { public class DocumentationError extends RuntimeException { /** Constructs an instance. */ public DocumentationError() { super(); } /** Constructs an instance. * @param message a string */ public DocumentationError(String message) { super(message); } } private static class Visitor { public void visit(SimpleNode parseNode, org.w3c.dom.Element docNode) { //System.out.println(parseNode.getClass().getName()); if (parseNode instanceof ASTVariableStatement) { visitVariableStatement(parseNode, docNode); } else if (parseNode instanceof ASTFunctionDeclaration) { visitFunctionDeclaration(parseNode, docNode); } else if (parseNode instanceof ASTClassDefinition) { visitClassDefinition(parseNode, docNode); } else if (parseNode instanceof ASTIncludeDirective) { visitIncludeDirective(parseNode, docNode); } else if (parseNode instanceof ASTIfDirective) { visitIfDirective(parseNode, docNode); } else { SimpleNode[] children = parseNode.getChildren(); for (Iterator iter = Arrays.asList(children).iterator(); iter.hasNext();) { SimpleNode child = (SimpleNode) iter.next(); this.visit(child, docNode); } } } protected void visitVariableStatement(SimpleNode parseNode, org.w3c.dom.Element docNode) { // We want to hand any comment off to all the declarations in the variable statement. // to review: a var statement is "var id (= val)? (, id (= val)?)*" // (This is how javadoc 1.5 does it: see "Declaration with multiple fields" // at http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javadoc.html#comments) String comment = parseNode.getComment(); SimpleNode[] children = parseNode.getChildren(); // assert children.length == 1 SimpleNode child = children[0]; if (child instanceof ASTVariableDeclaration) { this.visitVariableDeclaration(child, comment, docNode); } else if (child instanceof ASTStatementList) { // children of StatementList are VariableDeclarations children = child.getChildren(); for (Iterator iter = Arrays.asList(children).iterator(); iter.hasNext();) { child = (SimpleNode) iter.next(); // assert child instanceof ASTVariableDeclaration this.visitVariableDeclaration(child, comment, docNode); } } } protected void visitVariableDeclaration(SimpleNode parseNode, String defaultComment, org.w3c.dom.Element docNode) { org.w3c.dom.Element varNode = docNode.getOwnerDocument().createElement("variable"); docNode.appendChild(varNode); String comment = parseNode.getComment(); if (comment == null) { comment = defaultComment; } if (comment != null) { this.processComment(varNode, comment); } SimpleNode[] children = parseNode.getChildren(); // assert 0 < children.length < 3 ASTIdentifier name = (ASTIdentifier) children[0]; varNode.setAttribute("name", name.getName()); if (children.length > 1) { // process value } } protected void visitFunctionDeclaration(SimpleNode parseNode, org.w3c.dom.Element docNode) { org.w3c.dom.Element fnNode = docNode.getOwnerDocument().createElement("function"); docNode.appendChild(fnNode); String comment = parseNode.getComment(); if (comment != null) { this.processComment(fnNode, comment); } SimpleNode[] children = parseNode.getChildren(); // assert children.length == 3 ASTIdentifier name = (ASTIdentifier) children[0]; fnNode.setAttribute("name", name.getName()); ASTFormalParameterList paramList = (ASTFormalParameterList) children[1]; SimpleNode[] params = paramList.getChildren(); for (Iterator iter = Arrays.asList(params).iterator(); iter.hasNext();) { SimpleNode param = (SimpleNode) iter.next(); this.visitFunctionParameter(param, fnNode); } } protected void visitFunctionParameter(SimpleNode parseNode, org.w3c.dom.Element docNode) { org.w3c.dom.Element paramNode = docNode.getOwnerDocument().createElement("parameter"); docNode.appendChild(paramNode); // assert parseNode instanceof ASTIdentifier ASTIdentifier param = (ASTIdentifier) parseNode; paramNode.setAttribute("name", param.getName()); } protected void visitClassDefinition(SimpleNode parseNode, org.w3c.dom.Element docNode) { org.w3c.dom.Element classNode = docNode.getOwnerDocument().createElement("class"); docNode.appendChild(classNode); //debugPrintNode(parseNode); //System.out.println("\n"); String comment = parseNode.getComment(); if (comment != null) { this.processComment(classNode, comment); } SimpleNode[] children = parseNode.getChildren(); Iterator iter = Arrays.asList(children).iterator(); // assert iter.hasNext() // children[0] is ASTIdentifier with name=="class" iter.next(); // assert iter.hasNext() ASTIdentifier name = (ASTIdentifier) iter.next(); classNode.setAttribute("name", name.getName()); if (iter.hasNext()) { SimpleNode extendsNode = (SimpleNode) iter.next(); SimpleNode[] extendsChildren = extendsNode.getChildren(); if (extendsChildren.length > 0) { ASTIdentifier extendsID = (ASTIdentifier) extendsNode.getChildren()[0]; classNode.setAttribute("extends", extendsID.getName()); } } while (iter.hasNext()) { SimpleNode variableStatement = (SimpleNode) iter.next(); this.visit(variableStatement, classNode); } } protected void visitIncludeDirective(SimpleNode parseNode, org.w3c.dom.Element docNode) { } protected void visitIfDirective(SimpleNode parseNode, org.w3c.dom.Element docNode) { SimpleNode[] children = parseNode.getChildren(); // assert children.length == 2 // children[0] is conditional SimpleNode conditional = children[0]; if (conditional instanceof ASTLiteral) { Object value = ((ASTLiteral) conditional).getValue(); if ((value instanceof Boolean) && ((Boolean) value == true)) { // fall through } else { return; } } else if (conditional instanceof ASTIdentifier) { String value = ((ASTIdentifier) conditional).getName(); if (value.startsWith("$")) { org.w3c.dom.Element requiresNode = docNode.getOwnerDocument().createElement("requires"); docNode.appendChild(requiresNode); requiresNode.setAttribute("tag", (String) value); docNode = requiresNode; } } SimpleNode directiveBlock = children[1]; this.visit(directiveBlock, docNode); } protected void debugPrintNode(SimpleNode parseNode) { debugPrintNode(parseNode, 0, 0); } protected void debugPrintNode(SimpleNode parseNode, int index, int level) { System.out.println("node: (" + level + ", " + index + ") " + parseNode.getClass().getName()); int n = 0; SimpleNode[] children = parseNode.getChildren(); for (Iterator iter = Arrays.asList(children).iterator(); iter.hasNext(); n++) { SimpleNode child = (SimpleNode) iter.next(); debugPrintNode(child, n, level + 1); } } protected void processComment(org.w3c.dom.Element node, String comment) { org.w3c.dom.Element doc = node.getOwnerDocument().createElement("doc"); node.appendChild(doc); doc.setTextContent(comment.trim()); } } public static Document toXML(String inputString) { org.openlaszlo.sc.Compiler.Parser p = new org.openlaszlo.sc.Compiler.Parser(); SimpleNode parseRoot = p.parse(inputString); org.w3c.dom.Document doc = null; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { doc = factory.newDocumentBuilder().newDocument(); Element docRoot = doc.createElement("es4doc"); doc.appendChild(docRoot); Visitor visitor = new Visitor(); visitor.visit(parseRoot, docRoot); doc.normalizeDocument(); } catch (javax.xml.parsers.ParserConfigurationException e) { e.printStackTrace(); } return doc; } }