Package com.cadrlife.jhaml.internal

Source Code of com.cadrlife.jhaml.internal.JHamlParser

package com.cadrlife.jhaml.internal;

import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;

import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableSet;

public class JHamlParser {
  private final JHamlReader reader;
  private Helper helper;
  public JHamlParser(JHamlReader reader) {
    // TODO the Helper methods called from this class do not require a config.
    // Perhaps Helper should become 2 classes: one that takes a config and one that does not.
    helper = new Helper(null);
   
    this.reader = reader;
  }
  public JHamlParser(Reader in) {
    this(new JHamlReader(new LineNumberReader(in)));
  }
  public List<Line> jHamlSource() {
    List<Line> lines = new ArrayList<Line>();
    while (line(lines));
    return lines;
  }
  private boolean line(List<Line> lines) {
    if (reader.eof()) {
      return false;
    }
    Line line = new Line();
    line.lineNumber = reader.getLineNumber()+1;
    lines.add(line);
    reader.setObserver(line.getTextWriter());
    line.leadingWhitespace = reader.consumeMatching(CharMatchers.INDENTATION_CHAR);
    if (elementDeclaration(line)) {
      line.isElement = true;
      if (reader.isNextChar('/')) {
        reader.skip(1);
        line.isSelfClosing = true;
      }
      ignoreWhitespace();
      line.inlineContent = reader.readLine();
      reader.setObserver(null);
      return true;
    }
    line.inlineContent = reader.readLine();
    reader.setObserver(null);
    return true;
  }
  private boolean elementDeclaration(Line line) {
    boolean hasElementTypeSpecifier = elementTypeSpecifier(line);
    if (hasElementTypeSpecifier || classSpecifier(line) || idSpecifier(line)) {
      while (classSpecifier(line) || idSpecifier(line));
      if (!hasElementTypeSpecifier) {
        line.tag = "div";
      }
      attributeHashes(line);
      return true;
    }
    return false;
  }
 
  private void attributeHashes(Line line) {
    String textBeforeAttrHashes = line.text;
    try {
      boolean foundAttributeHash = attributeHash(line.attrMap);
      htmlStyleAttributeHash(line.attrMap);
      if (!foundAttributeHash) {
        attributeHash(line.attrMap);
      }
    } catch (JHamlInternalParseException e) {
      helper.getErrorChecker().setCurrentLineNumber(reader.getLineNumber());
      helper.getErrorChecker().invalidAttributeList(line.text.substring(textBeforeAttrHashes.length()));
    }
   
  }
 
  private boolean htmlStyleAttributeHash(Map<String, AttributeValue> attrMap) throws JHamlInternalParseException {
    CharMatcher CLOSE_PAREN = CharMatcher.is(')');
    if (reader.isNextChar('(')) {
      reader.skip(1);
      ignoreWhitespaceIncludingNewline();
      boolean attrFound = htmlStyleAttributeMapping(attrMap, CharMatcher.WHITESPACE, CLOSE_PAREN);
      ignoreWhitespaceIncludingNewline();
      while (attrFound && !reader.isNextChar(')') && !reader.eof()) {
        attrFound = htmlStyleAttributeMapping(attrMap, CharMatcher.WHITESPACE, CLOSE_PAREN);
        ignoreWhitespaceIncludingNewline();
      }
      if (reader.isNextChar(')')) {
        reader.skip(1);
        return true;
      }
      fail();
    }
     return false;
  }
  private boolean htmlStyleAttributeMapping(Map<String, AttributeValue> attrMap, CharMatcher separator, CharMatcher endOfAttributes) throws JHamlInternalParseException {
    String attr = "";
    if (reader.nextCharMatches(CharMatchers.XML_NAME_START_CHAR)) {
      attr = reader.consumeMatching(CharMatchers.XML_NAME_CHAR);
    }
    if (StringUtils.isBlank(attr)) {
      return false;
    }
    ignoreWhitespaceIncludingNewline();
    if (reader.isNextChar('=')) {
      reader.skip(1);
      ignoreWhitespaceIncludingNewline();
      attrMap.put(attr, attributeValue(separator.or(endOfAttributes)));
      return true;
    } else {
      attrMap.put(attr, AttributeValue.literal("true"));
      return true;
    }
//    fail();
//    return false;
   
  }
  private boolean attributeHash(Map<String, AttributeValue> attrMap) throws JHamlInternalParseException {
    CharMatcher COMMA = CharMatcher.is(',');
    CharMatcher CLOSE_BRACE = CharMatcher.is('}');
    if (reader.isNextChar('{')) {
      reader.skip(1);
      ignoreWhitespaceIncludingNewline();
      boolean attrFound = attributeMapping(attrMap, COMMA, CLOSE_BRACE);
      ignoreWhitespaceIncludingNewline();
      while (attrFound && reader.nextCharMatches(COMMA)) {
        reader.skip(1);
        ignoreWhitespaceIncludingNewline();
        attributeMapping(attrMap, COMMA, CLOSE_BRACE);
        ignoreWhitespaceIncludingNewline();
      }
      if (reader.isNextChar('}')) {
        reader.skip(1);
        return true;
      }
      fail();
    }
     return false;
  }
 
  private void fail() throws JHamlInternalParseException {
    throw new JHamlInternalParseException()
  }
 
  private boolean attributeMapping(Map<String, AttributeValue> attrMap, CharMatcher separator, CharMatcher endOfAttributes) throws JHamlInternalParseException {
    String attr = "";
    if (reader.isNextChar(':')) {
      reader.skip(1);
      attr = reader.consumeMatching(CharMatchers.XML_NAME_CHAR);
      if (StringUtils.isBlank(attr)) {
        return false;
      }
    } else if (reader.isNextCharOneOf("0123456789")) {
      attr = numberLiteral();
    } else if (reader.isNextCharOneOf("'\"")) {
      attr = helper.parseStringLiteral(stringLiteral());
    } else {
      return false;
    }
    ignoreWhitespaceIncludingNewline();
    if (reader.isNextInput("=>")) {
      reader.skip(2);
      ignoreWhitespaceIncludingNewline();
      if (!html5DataAttributeMap(attr, attrMap)) {
        attrMap.put(attr, attributeValue(separator.or(endOfAttributes)));
      }
      return true;
    }
    fail();
    return false;
  }
 
  private boolean html5DataAttributeMap(String attr, Map<String, AttributeValue> attrMap) throws JHamlInternalParseException {
    Map<String, AttributeValue> dataAttributes = new HashMap<String, AttributeValue>();
    if (attr.equals("data") && attributeHash(dataAttributes)) {
      for (Entry<String, AttributeValue> e : dataAttributes.entrySet()) {
        String key = attr + "-" + e.getKey();
        if (!attrMap.containsKey(key)) {
          attrMap.put(key, e.getValue());
        }
      }
      return true;
    }
    return false;
  }
  private AttributeValue attributeValue(CharMatcher separator) throws JHamlInternalParseException {
    String exp = expression(separator).trim();
    if (exp.startsWith("'") || exp.startsWith("\"")) {
      return AttributeValue.quoted(helper.parseStringLiteral(exp));
    } else {
//      String identifier = reader.consumeMatching(CharMatcher.JAVA_LETTER);
//      if (!identifier.isEmpty()) {
//        identifier += reader.consumeMatching(CharMatcher.JAVA_LETTER_OR_DIGIT);
//        return AttributeValue.literal(identifier);
//      }
      CharMatcher NUMBER_LITERAL_CHARS = CharMatcher.JAVA_LETTER_OR_DIGIT.or(CharMatcher.is('.'));
      if (CharMatcher.JAVA_DIGIT.indexIn(exp) == 0 && NUMBER_LITERAL_CHARS.matchesAllOf(exp)) {
        return AttributeValue.literal(helper.parseNumberLiteral(exp));
      }
      ImmutableSet<String> keywords = ImmutableSet.of("null","true","false");
      if (keywords.contains(exp)) {
        return AttributeValue.literal(exp);
      }     
      return AttributeValue.literal("<%= " + exp + " %>");
    }
//    fail();
//    return null;
  }
 
  private String expression(CharMatcher delim) throws JHamlInternalParseException {
    int parenDepth = 0;
    int braceDepth = 0;
    int bracketDepth = 0;
    String exp = "";
    while (!reader.eof()) {
      if (parenDepth < 1 && braceDepth <1 && braceDepth <1 && bracketDepth <1 && reader.nextCharMatches(delim)) {
        break;
      }
      if (reader.isNextCharOneOf("'\"")) {
        exp += stringLiteral();
        continue;
      }
      char c = (char)reader.read();
      exp += c;
      switch (c) {
      case '{': braceDepth++; break;
      case '}': braceDepth--; break;
      case '(': parenDepth++; break;
      case ')': parenDepth--; break;
      case '[': bracketDepth++; break;
      case ']': bracketDepth--; break;
      }
    }
    return exp;
  }
  private String numberLiteral() {
    String val = "";
      if (reader.isNextInput("0x")) {
        val = "0x";
        reader.skip(2);
      }
      val += reader.consumeMatching(CharMatcher.inRange('0', '9'));
      if (reader.isNextChar('.')) {
        reader.skip(1);
        val += "." + reader.consumeMatching(CharMatcher.inRange('0', '9'));
        if (reader.isNextCharOneOf("dDfF")) {
          reader.skip(1);
        }
        return helper.parseDoubleLiteral(val);
       
      }
      if (reader.isNextCharOneOf("lL")) {
        reader.skip(1);
      }
      return helper.parseIntegerLiteral(val);
  }
  private String stringLiteral() throws JHamlInternalParseException {
    char quote = (char) reader.read();
    String val = reader.consumeMatchingWithEscaping(CharMatcher.is(quote).negate(),'\\');
//    String ret = StringEscapeUtils.unescapeJava(val);
    if (reader.isNextChar(quote)) {
      reader.skip(1);
      return quote + val + quote;
    }
    fail();
    return null;
  }
  private void ignoreWhitespace() {
    reader.consumeMatching(CharMatchers.INDENTATION_CHAR);
  }
  private void ignoreWhitespaceIncludingNewline() {
    reader.consumeMatching(CharMatcher.WHITESPACE);
  }
  private boolean elementTypeSpecifier(Line line) {
    if (reader.isNextChar('%')) {
      reader.skip(1);
      line.tag = reader.consumeMatching(CharMatchers.XML_NAME_CHAR);
      return true;
    }
    return false;
  }
  private boolean classSpecifier(Line line) {
    if (reader.isNextChar('.')) {
      reader.skip(1);
      line.classes.add(reader.consumeMatching(CharMatchers.CLASS_CHAR));
      return true;
    }
    return false;
  }
  private boolean idSpecifier(Line line) {
    if (reader.isNextChar('#')) {
      reader.skip(1);
      line.ids.add(reader.consumeMatching(CharMatchers.ID_CHAR));
      return true;
    }
    return false;
  }
}
TOP

Related Classes of com.cadrlife.jhaml.internal.JHamlParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.