Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/rxm.git

Clarified names for parts of the query and its parser. Re-using tree class to pose as a list for the from clause. From clause now prints information.

AuthorDave Jarvis <email>
Date2015-03-13 18:05:11 GMT-0700
Commitf16403a9570d1262c97a6000e4b10c9571e94f94
Parentcac18d4
source/java/com/whitemagicsoftware/rxm/Parser.java
-package com.whitemagicsoftware.rxm;
-
-import com.whitemagicsoftware.rxm.grammar.QueryBaseListener;
-import com.whitemagicsoftware.rxm.grammar.QueryLexer;
-import com.whitemagicsoftware.rxm.grammar.QueryParser;
-
-import com.whitemagicsoftware.rxm.tree.Payload;
-import com.whitemagicsoftware.rxm.tree.Tree;
-import com.whitemagicsoftware.rxm.tree.xml.QueryTree;
-
-import org.antlr.v4.runtime.ANTLRInputStream;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.tree.ParseTreeWalker;
-
-/**
- * Parses the Relational eXpression Map (<b>rxm</b>) into a tree.
- */
-public class Parser extends QueryBaseListener {
- /** Map for containing modules. */
- private RXM rxm;
-
- /** Current context. */
- private Tree<Payload> contextTree;
-
- /**
- * Creates a Parser instance that parses a given <b>rxm</b>.
- *
- * @param rxm The <b>rxm</b> instance responsible for receiving information
- * that allows it to build a SQL statement. Must not be null.
- */
- public Parser( RXM rxm ) {
- this.rxm = rxm;
- }
-
- /**
- * Parses the given <b>rxm</b> text. This creates a tree that is used
- * for context when building the query.
- *
- * @param rxm The <b>rxm</b> string to parse.
- */
- public void parse( String rxm ) {
- QueryLexer lexer = new QueryLexer( new ANTLRInputStream( rxm ) );
- CommonTokenStream tokens = new CommonTokenStream( lexer );
-
- QueryParser parser = new QueryParser( tokens );
- QueryParser.QueryContext ctx = parser.query();
-
- ParseTreeWalker walker = new ParseTreeWalker();
- walker.walk( this, ctx );
- }
-
- /**
- * Adds the root context node to the top-most part of the tree. This
- * sets the context tree to the root context node.
- *
- * @param ctx The payload to transform.
- */
- @Override
- public synchronized void enterRoot( QueryParser.RootContext ctx ) {
- setContextTree( createTree( ctx ) );
- }
-
- /**
- * Invoked when parsing <b><code>table &gt; path</code></b>. Adds a new
- * leaf to the context tree, then changes the context tree to the newly
- * added leaf.
- *
- * @param ctx The payload to transform.
- */
- @Override
- public synchronized void enterTableMap( QueryParser.TableMapContext ctx ) {
- setContextTree( addLeaf( ctx ) );
- }
-
- /**
- * Invoked when parsing <b><code>column &gt; path</code></b>. Adds a new
- * leaf to the context tree.
- *
- * @param ctx The payload to transform.
- */
- @Override
- public synchronized void enterColumnMap( QueryParser.ColumnMapContext ctx ) {
- addLeaf( ctx );
- }
-
- /**
- * Invoked when parsing <b><code>column &gt; attribute</code></b>. Adds
- * a new leaf to the context tree.
- *
- * @param ctx The payload to transform.
- */
- @Override
- public synchronized void enterAttributeMap(
- QueryParser.AttributeMapContext ctx ) {
- addLeaf( ctx );
- }
-
- /**
- * Invoked when parsing <b><code>^</code></b>. Changes context tree to
- * its parent. If the parent doesn't exist, this will fail silently.
- *
- * @param ctx Indicates that context should switch, has no payload.
- */
- @Override
- public synchronized void enterPop( QueryParser.PopContext ctx ) {
- Tree<Payload> parent = getContextTree().getParent();
-
- if( parent != null ) {
- setContextTree( parent );
- }
- }
-
- /**
- * Invoked when there are no more <b>rxm</b> tokens to parse.
- *
- * @param ctx Indicates that the query has been parsed.
- */
- @Override
- public synchronized void exitQuery( QueryParser.QueryContext ctx ) {
- String select = getSelectClause();
- String from = getFromClause();
- String where = getWhereClause();
- System.out.printf( "SELECT%n%s%nFROM%n%s%nWHERE%n%s%n",
- select, from, where );
- }
-
- /**
- * This should only be called after the SELECT clause has been
- * constructed using the AST.
- *
- * @return The SELECT portion of a SQL statement.
- */
- private String getSelectClause() {
- return getContextTree().getRoot().toString();
- }
-
- /**
- * Returns the tables JOINed together that are used in the SELECT clause
- * of the SQL statement.
- *
- * @return The FROM portion of a SQL statement.
- */
- private String getFromClause() {
- return "";
- }
-
- private String getWhereClause() {
- return "";
- }
-
- /**
- * Adds the given parser rule context to the current context tree.
- *
- * @param ctx The parser rule context to add as a leaf to the context tree.
- * @return The leaf (tree) that was added.
- */
- private Tree<Payload> addLeaf( ParserRuleContext ctx ) {
- return getContextTree().addLeaf( createTree( ctx ) );
- }
-
- /**
- * Returns the Relational eXpression Map to populate while walking
- * through the AST.
- *
- * @return The <b>rxm</b> instance to update with information from
- * the AST.
- */
- private RXM getRXM() {
- return this.rxm;
- }
-
- /**
- * Changes where the next mapped items will be attached.
- */
- private void setContextTree( Tree<Payload> contextTree ) {
- this.contextTree = contextTree;
- }
-
- /**
- * Returns where to attach upcoming map items.
- */
- private Tree<Payload> getContextTree() {
- return this.contextTree;
- }
-
- /**
- * Creates a new tree with the given parser rule context. This is required
- * so that the *Context classes are aware of their relative position in the
- * hierarchy. As a consequence of that knowledge, the objects have access
- * to the nearest table name, whether siblings exist, etc.
- *
- * @param ctx The context to wrap in a payload that is added to a tree.
- *
- * @return The tree that contains the payload that wraps the context.
- */
- private Tree<Payload> createTree( ParserRuleContext ctx ) {
- Tree<Payload> tree = getContextTree();
- Payload payload = new Payload( ctx );
- QueryTree<Payload> result = new QueryTree<Payload>( payload );
-
- // Ensure that the first payload (root node) has a valid payload tree.
- payload.setTree( tree == null ? result : tree );
-
- return result;
- }
-}
source/java/com/whitemagicsoftware/rxm/QueryBuilder.java
+package com.whitemagicsoftware.rxm;
+
+import com.whitemagicsoftware.rxm.grammar.QueryBaseListener;
+import com.whitemagicsoftware.rxm.grammar.QueryLexer;
+import com.whitemagicsoftware.rxm.grammar.QueryParser;
+
+import com.whitemagicsoftware.rxm.tree.Payload;
+import com.whitemagicsoftware.rxm.tree.Tree;
+import com.whitemagicsoftware.rxm.tree.xml.SelectClauseTree;
+import com.whitemagicsoftware.rxm.tree.xml.FromClauseList;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+
+/**
+ * Parses the Relational eXpression Map (<b>rxm</b>) into a tree.
+ */
+public class QueryBuilder extends QueryBaseListener {
+ /** Map for containing modules. */
+ private RXM rxm;
+
+ /** Current context. */
+ private Tree<Payload> selectClauseTree;
+
+ /** List of inner and outer joins (tree used as flat hierarchy). */
+ private Tree<Payload> fromClauseList;
+
+ /**
+ * Creates a QueryBuilder instance that parses a given <b>rxm</b>.
+ *
+ * @param rxm The <b>rxm</b> instance responsible for receiving information
+ * that allows it to build a SQL statement. Must not be null.
+ */
+ public QueryBuilder( RXM rxm ) {
+ this.rxm = rxm;
+ }
+
+ /**
+ * Parses the given <b>rxm</b> text. This creates a tree that is used
+ * for context when building the query.
+ *
+ * @param rxm The <b>rxm</b> string to parse.
+ */
+ public void parse( String rxm ) {
+ QueryLexer lexer = new QueryLexer( new ANTLRInputStream( rxm ) );
+ CommonTokenStream tokens = new CommonTokenStream( lexer );
+
+ QueryParser parser = new QueryParser( tokens );
+ QueryParser.QueryContext ctx = parser.query();
+
+ ParseTreeWalker walker = new ParseTreeWalker();
+ walker.walk( this, ctx );
+ }
+
+ /**
+ * Adds the root context node to the top-most part of the tree. This
+ * sets the context tree to the root context node.
+ *
+ * @param ctx The payload to transform.
+ */
+ @Override
+ public synchronized void enterRoot( QueryParser.RootContext ctx ) {
+ setSelectClauseTree( createSelectClauseTree( ctx ) );
+ }
+
+ /**
+ * Invoked when parsing <b><code>table &gt; path</code></b>. Adds a new
+ * leaf to the context tree, then changes the context tree to the newly
+ * added leaf.
+ *
+ * @param ctx The payload to transform.
+ */
+ @Override
+ public synchronized void enterTableMap( QueryParser.TableMapContext ctx ) {
+ setSelectClauseTree( addLeaf( ctx ) );
+ }
+
+ /**
+ * Invoked when parsing <b><code>column &gt; path</code></b>. Adds a new
+ * leaf to the context tree.
+ *
+ * @param ctx The payload to transform.
+ */
+ @Override
+ public synchronized void enterColumnMap( QueryParser.ColumnMapContext ctx ) {
+ addLeaf( ctx );
+ }
+
+ /**
+ * Invoked when parsing <b><code>column &gt; attribute</code></b>. Adds
+ * a new leaf to the context tree.
+ *
+ * @param ctx The payload to transform.
+ */
+ @Override
+ public synchronized void enterAttributeMap(
+ QueryParser.AttributeMapContext ctx ) {
+ addLeaf( ctx );
+ }
+
+ /**
+ * Invoked when parsing <b><code>^</code></b>. Changes context tree to
+ * its parent. If the parent doesn't exist, this will fail silently.
+ *
+ * @param ctx Indicates that context should switch, has no payload.
+ */
+ @Override
+ public synchronized void enterPop( QueryParser.PopContext ctx ) {
+ Tree<Payload> parent = getSelectClauseTree().getParent();
+
+ if( parent != null ) {
+ setSelectClauseTree( parent );
+ }
+ }
+
+ @Override
+ public synchronized void enterInnerMap( QueryParser.InnerMapContext ctx ) {
+ addJoinClause( ctx );
+ }
+
+ @Override
+ public synchronized void enterOuterMap( QueryParser.OuterMapContext ctx ) {
+ addJoinClause( ctx );
+ }
+
+ /**
+ * Invoked when there are no more <b>rxm</b> tokens to parse.
+ *
+ * @param ctx Indicates that the query has been parsed.
+ */
+ @Override
+ public synchronized void exitQuery( QueryParser.QueryContext ctx ) {
+ String select = getSelectClause();
+ String from = getFromClause();
+ String where = getWhereClause();
+ System.out.printf( "SELECT%n%s%nFROM%n%s%nWHERE%n%s%n",
+ select, from, where );
+ }
+
+ /**
+ * This should only be called after the SELECT clause has been
+ * constructed using the AST.
+ *
+ * @return The SELECT portion of a SQL statement.
+ */
+ private String getSelectClause() {
+ return getSelectClauseTree().getRoot().toString();
+ }
+
+ /**
+ * Returns the tables JOINed together that are used in the SELECT clause
+ * of the SQL statement.
+ *
+ * @return The FROM portion of a SQL statement.
+ */
+ private String getFromClause() {
+ return getFromClauseList().getRoot().toString();
+ }
+
+ private void addJoinClause( ParserRuleContext ctx ) {
+ getFromClauseList().addLeaf( new FromClauseList<Payload>( new Payload( ctx ) ) );
+ }
+
+ private String getWhereClause() {
+ return "";
+ }
+
+ /**
+ * Adds the given parser rule context to the current context tree.
+ *
+ * @param ctx The parser rule context to add as a leaf to the context tree.
+ * @return The leaf (tree) that was added.
+ */
+ private Tree<Payload> addLeaf( ParserRuleContext ctx ) {
+ return getSelectClauseTree().addLeaf( createSelectClauseTree( ctx ) );
+ }
+
+ /**
+ * Returns the Relational eXpression Map to populate while walking
+ * through the AST.
+ *
+ * @return The <b>rxm</b> instance to update with information from
+ * the AST.
+ */
+ private RXM getRXM() {
+ return this.rxm;
+ }
+
+ /**
+ * Changes where the next mapped items will be attached.
+ */
+ private void setSelectClauseTree( Tree<Payload> selectClauseTree ) {
+ this.selectClauseTree = selectClauseTree;
+ }
+
+ /**
+ * Returns where to attach upcoming map items.
+ */
+ private Tree<Payload> getSelectClauseTree() {
+ return this.selectClauseTree;
+ }
+
+ /**
+ * Creates a new tree with the given parser rule context. This is required
+ * so that the *Context classes are aware of their relative position in the
+ * hierarchy. As a consequence of that knowledge, the objects have access
+ * to the nearest table name, whether siblings exist, etc.
+ *
+ * @param ctx The context to wrap in a payload that is added to a tree.
+ *
+ * @return The tree that contains the payload that wraps the context.
+ */
+ private Tree<Payload> createSelectClauseTree( ParserRuleContext ctx ) {
+ Tree<Payload> tree = getSelectClauseTree();
+ Payload payload = new Payload( ctx );
+ SelectClauseTree<Payload> sct = new SelectClauseTree<Payload>( payload );
+
+ // Ensure that the first payload (root node) has a valid payload tree.
+ payload.setTree( tree == null ? sct : tree );
+
+ return sct;
+ }
+
+ private void setFromClauseList( Tree<Payload> fromClauseList ) {
+ this.fromClauseList = fromClauseList;
+ }
+
+ /**
+ * Lazily-initializes the from clause list.
+ *
+ * @return The list that will contain the query's FROM clause.
+ */
+ private Tree<Payload> getFromClauseList() {
+ Tree<Payload> tree = this.fromClauseList;
+
+ if( tree == null ) {
+ setFromClauseList( tree = createFromClauseList() );
+ }
+
+ return tree;
+ }
+
+ /**
+ * Creates a new FromClauseList instance with an empty payload. The
+ * resulting tree should only have leaves added to the root, never
+ * branching beyond a flat hierarchy (one-level deep).
+ *
+ * @return A new FromClauseList instance, never null.
+ */
+ private Tree<Payload> createFromClauseList() {
+ return FromClauseList.newInstance();
+ }
+}
+
source/java/com/whitemagicsoftware/rxm/RXM.java
*/
public RXM( String rxm ) throws ParserException {
- Parser parser = new Parser( this );
- parser.parse( rxm );
+ QueryBuilder builder = new QueryBuilder( this );
+ builder.parse( rxm );
}
source/java/com/whitemagicsoftware/rxm/tree/Payload.java
}
catch( Exception e ) {
+ e.printStackTrace();
return getParserRuleContext();
}
source/java/com/whitemagicsoftware/rxm/tree/TransformationTree.java
}
+ /**
+ * Answers whether the payload is preceded by at least one sibling. The
+ * siblings must not be split by any other type of playload.
+ *
+ * @param payload The payload with a class that is used as a reference for
+ * finding contiguous payloads.
+ *
+ * @return true There is at least one sibling of the same payload type
+ * that is before the given payload.
+ */
@Override
public boolean hasPrecedingPayload( T payload ) {
return getContiguousSiblings( payload ).indexOf( payload ) > 0;
}
+ /**
+ * Answers whether the payload is followed by at least one sibling. The
+ * siblings must not be split by any other type of playload.
+ *
+ * @param payload The payload with a class that is used as a reference for
+ * finding contiguous payloads.
+ *
+ * @return true There is at least one sibling of the same payload type
+ * that is after the given payload.
+ */
@Override
public boolean hasFollowingPayload( T payload ) {
source/java/com/whitemagicsoftware/rxm/tree/xml/EmptyListContext.java
+package com.whitemagicsoftware.rxm.tree.xml;
+
+import com.whitemagicsoftware.rxm.tree.Payload;
+
+/**
+ * Root context for a FromClauseList.
+ */
+public class EmptyListContext extends PayloadParserRuleContext {
+ /**
+ * Sets the payload to null.
+ */
+ public EmptyListContext() {
+ this( null );
+ }
+
+ /**
+ * Calls the superclass to construct this context instance.
+ *
+ * @param payload Passed to the superclass.
+ */
+ public EmptyListContext( Payload payload ) {
+ super( payload );
+ }
+}
+
source/java/com/whitemagicsoftware/rxm/tree/xml/FromClauseList.java
+package com.whitemagicsoftware.rxm.tree.xml;
+
+import com.whitemagicsoftware.rxm.tree.Payload;
+import com.whitemagicsoftware.rxm.tree.Tree;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+
+
+/**
+ * <p>
+ * Stores a list of Payload instances. This is instantiated by the parser
+ * to create a transformation list capable of generating a SQL/XML FROM
+ * clause. The superclass dynamically determines the set of wrapper classes
+ * by virtue of being in the same package as this class.
+ * </p>
+ * <p>
+ * The tree is being re-used as a list. (A list is simply a tree with
+ * one branch and many siblings.)
+ * </p>
+ */
+public class FromClauseList<T extends Payload> extends SelectClauseTree<T> {
+ /**
+ * Constructs a list capable of transforming itself into a SQL/XML
+ * FROM clause.
+ *
+ * @param payload The data associated with this list (must not be null).
+ */
+ public FromClauseList( T payload ) {
+ super( payload );
+ }
+
+ public static Tree<Payload> newInstance() {
+ Payload p = new Payload( new EmptyListContext() );
+
+ Tree<Payload> fcl = new FromClauseList<Payload>( p );
+ p.setTree( fcl );
+
+ return fcl;
+ }
+}
+
source/java/com/whitemagicsoftware/rxm/tree/xml/InnerMapContext.java
+package com.whitemagicsoftware.rxm.tree.xml;
+
+import com.whitemagicsoftware.rxm.grammar.QueryParser;
+import com.whitemagicsoftware.rxm.tree.Payload;
+import com.whitemagicsoftware.rxm.tree.Token;
+import com.whitemagicsoftware.rxm.tree.Tree;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+
+/**
+ * Transforms <b><code>table.column +&gt; table.column</code></b> into a SQL
+ * <code>JOIN</code> expression.
+ */
+public class InnerMapContext extends PayloadParserRuleContext {
+ /**
+ * Default constructor (calls super).
+ *
+ * @param ctx The payload that associates the parser rule context with
+ * the abstract syntax tree.
+ */
+ public InnerMapContext( Payload ctx ) {
+ super( ctx );
+ }
+
+ /**
+ *
+ */
+ @Override
+ public Token getStart() {
+ return new Token( "TOKEN" );
+ }
+}
+
source/java/com/whitemagicsoftware/rxm/tree/xml/PayloadParserRuleContext.java
*/
public abstract class PayloadParserRuleContext extends ParserRuleContext {
- private Payload initPayload;;
+ private Payload initPayload;
/**
source/java/com/whitemagicsoftware/rxm/tree/xml/QueryTree.java
-package com.whitemagicsoftware.rxm.tree.xml;
-
-import com.whitemagicsoftware.rxm.tree.Payload;
-import com.whitemagicsoftware.rxm.tree.TransformationTree;
-import com.whitemagicsoftware.rxm.tree.Tree;
-import com.whitemagicsoftware.rxm.tree.Token;
-
-/**
- * Stores a tree of Payload instances. This is instantiated by
- * the parser to create a transformation tree capable of generating a
- * SQL/XML SELECT clause. The superclass dynamically determines the set of
- * wrapper classes by virtue of being in the same package as this class.
- */
-public class QueryTree<T extends Payload> extends TransformationTree<T> {
- /**
- * Constructs a tree capable of transforming itself into a SQL/XML
- * SELECT clause.
- *
- * @param payload The data associated with this tree leaf (must not
- * be null).
- */
- @SuppressWarnings( "unchecked" )
- public QueryTree( T payload ) {
- super( payload );
- }
-
- /**
- * Returns the transformed syntax for beginning the payload item.
- *
- * @return A non-null string, possibly empty.
- */
- protected String start( Tree<T> tree ) {
- return tree.getPayload().getStart().toString();
- }
-
- /**
- * Returns the transformed syntax for ending the payload item.
- *
- * @return A non-null string, possibly empty.
- */
- protected String stop( Tree<T> tree ) {
- return tree.getPayload().getStop().toString();
- }
-}
source/java/com/whitemagicsoftware/rxm/tree/xml/RootContext.java
}
-
source/java/com/whitemagicsoftware/rxm/tree/xml/SelectClauseTree.java
+package com.whitemagicsoftware.rxm.tree.xml;
+
+import com.whitemagicsoftware.rxm.tree.Payload;
+import com.whitemagicsoftware.rxm.tree.TransformationTree;
+import com.whitemagicsoftware.rxm.tree.Tree;
+import com.whitemagicsoftware.rxm.tree.Token;
+
+/**
+ * Stores a tree of Payload instances. This is instantiated by
+ * the parser to create a transformation tree capable of generating a
+ * SQL/XML SELECT clause. The superclass dynamically determines the set of
+ * wrapper classes by virtue of being in the same package as this class.
+ */
+public class SelectClauseTree<T extends Payload> extends TransformationTree<T> {
+ /**
+ * Constructs a tree capable of transforming itself into a SQL/XML
+ * SELECT clause.
+ *
+ * @param payload The data associated with this tree leaf (must not
+ * be null).
+ */
+ @SuppressWarnings( "unchecked" )
+ public SelectClauseTree( T payload ) {
+ super( payload );
+ }
+
+ /**
+ * Returns the transformed syntax for beginning the payload item.
+ *
+ * @return A non-null string, possibly empty.
+ */
+ protected String start( Tree<T> tree ) {
+ return tree.getPayload().getStart().toString();
+ }
+
+ /**
+ * Returns the transformed syntax for ending the payload item.
+ *
+ * @return A non-null string, possibly empty.
+ */
+ protected String stop( Tree<T> tree ) {
+ return tree.getPayload().getStop().toString();
+ }
+}
+
Delta424 lines added, 255 lines removed, 169-line increase