Clover coverage report - DrJava Test Coverage (drjava-20120422-r5456)
Coverage timestamp: Sun Apr 22 2012 03:13:25 CDT
file stats: LOC: 215   Methods: 11
NCLOC: 104   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
SExpParser.java 75% 91.3% 100% 88.3%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.util.sexp;
 38   
 39    import java.io.File;
 40    import java.io.Reader;
 41    import java.io.FileReader;
 42    import java.io.StringReader;
 43    import java.io.IOException;
 44    import java.util.List;
 45    import java.util.ArrayList;
 46    import java.util.LinkedList;
 47   
 48    /**
 49    * This parser is not meant to be instantiated. It has
 50    * static methods that do all the work for you. These
 51    * parse methods take in the data that is to be parsed
 52    * and simply returns an s-expression abstract syntax.
 53    * @author Jonathan Lugo, PLT Group
 54    */
 55    public class SExpParser {
 56   
 57  9 public static List<SEList> parse(File f) throws SExpParseException, IOException{
 58  9 return parse(new FileReader(f));
 59    }
 60   
 61  12 public static List<SEList> parse(String s) throws SExpParseException {
 62  12 return parse(new StringReader(s));
 63    }
 64   
 65  22 public static List<SEList> parse(Reader r) throws SExpParseException {
 66  22 try {
 67  22 return new ParseHelper(r).parseMultiple();
 68    }
 69    catch(LexingException e) {
 70  0 throw new SExpParseException(e.getMessage());
 71    }
 72    catch(PrivateParseException e) {
 73  8 throw new SExpParseException(e.getMessage());
 74    }
 75    }
 76   
 77    /** A new helper is instantiated for each time
 78    * the user wants to parse data. This is not
 79    * reused. The instances of the ParseHelpers are
 80    * handled solely in the outer class SExpParser.
 81    */
 82    private static class ParseHelper {
 83   
 84    private Lexer _lex;
 85   
 86  22 public ParseHelper(Reader r) {
 87  22 _lex = new Lexer(r);
 88    }
 89   
 90    /**
 91    * Parse a forest of top-level s-expressions from {@link #parseTopLevelExp()}.
 92    * @see #parseTopLevelExp()
 93    */
 94  22 public List<SEList> parseMultiple() {
 95  22 ArrayList<SEList> l = new ArrayList<SEList>();
 96  22 SEList exp;
 97  ? while ( (exp = parseTopLevelExp()) != null) {
 98  55 l.add(exp);
 99    }
 100  14 return l;
 101    }
 102   
 103    /**
 104    * A top-level s-expression is simply a non-empty list. Our s-expression files
 105    * can be a forest of several trees, but the Atomic values are not allowed
 106    * at the top level, only lists.
 107    * @return the top-level list s-expression
 108    */
 109  77 public SEList parseTopLevelExp() {
 110  77 Tokens.SExpToken t = _lex.readToken();
 111  77 if (t == Tokens.LeftParenToken.ONLY) {
 112  59 return parseList();
 113    }
 114  18 else if (t == null) {
 115  14 return null;
 116    }
 117    else {
 118  4 throw new PrivateParseException("A top-level s-expression must be a list. " +
 119    "Invalid start of list: " + t);
 120    }
 121    }
 122   
 123    /**
 124    * Parses the next s-expression in the lexer's buffer.
 125    * This may be either a cons or an atom
 126    * @return the next s-expression in the read buffer.
 127    */
 128  808 public SExp parseExp() {
 129  808 Tokens.SExpToken t = _lex.readToken();
 130  808 assertNotEOF(t);
 131  805 if (t == Tokens.LeftParenToken.ONLY) {
 132  254 return parseList();
 133    }
 134    else {
 135  551 return parseAtom(t);
 136    }
 137    }
 138   
 139    /**
 140    * The left paren has already been read. This starts
 141    * building up the recursive list structure
 142    * @return the parsed recursive s-expression list
 143    */
 144  313 private SEList parseList() {
 145  313 LinkedList<SExp> list = new LinkedList<SExp>();
 146  313 Tokens.SExpToken t = _lex.peek();
 147  313 assertNotEOF(t);
 148   
 149  312 while (t != Tokens.RightParenToken.ONLY) {
 150  808 list.addFirst(parseExp());
 151  805 t = _lex.peek();
 152    }
 153   
 154    // t has to be a Tokens.RightParenToken at this point.
 155    // simply eat the token
 156  309 _lex.readToken();
 157   
 158    // Compile the cons structure from the list of exps
 159  309 SEList cons = Empty.ONLY;
 160  309 for (SExp exp : list) {
 161  801 cons = new Cons(exp, cons);
 162    }
 163  309 return cons;
 164    }
 165   
 166    /**
 167    * Parses an atom. The token was already read and
 168    * found not to start a list, this method interprets
 169    * what is given. This method chooses which type of
 170    * atom the token represents and creates the atom.
 171    * @param t the token to interpret
 172    * @return the correct corresponding atom
 173    */
 174  551 private Atom parseAtom(Tokens.SExpToken t) {
 175  551 if (t instanceof Tokens.BooleanToken) {
 176  0 if (((Tokens.BooleanToken)t).getValue())
 177  0 return BoolAtom.TRUE;
 178    else
 179  0 return BoolAtom.FALSE;
 180    }
 181  551 else if (t instanceof Tokens.NumberToken) {
 182  114 return new NumberAtom(((Tokens.NumberToken)t).getValue());
 183    }
 184  437 else if (t instanceof Tokens.QuotedTextToken) {
 185  122 return new QuotedTextAtom(t.getText());
 186    }
 187    else {
 188  315 return new TextAtom(t.getText());
 189    }
 190    }
 191   
 192    /**
 193    * Throws the EOF exception if the given token is the end of file
 194    * @param t the token to check
 195    */
 196  1121 private void assertNotEOF(Tokens.SExpToken t) {
 197  1121 if (t == null) {
 198  4 throw new PrivateParseException("Unexpected <EOF> at line " + _lex.lineno());
 199    }
 200    }
 201    }
 202   
 203    /** This runtime exception makes it easier to write the parser since
 204    * the methods of the helper class won't need to constantly declare
 205    * the SExpParseException to be thrown.
 206    */
 207    private static class PrivateParseException extends RuntimeException {
 208    /**
 209    * Creates a runtime exception with the message that is desired for
 210    * the eventual checked exception
 211    * @param msg the message to display
 212    */
 213  8 public PrivateParseException(String msg) { super(msg); }
 214    }
 215    }