All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cb.parser.Parser Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2001 Markus Dahm
 * Copyright (C) 2015-2018 BITPlan GmbH http://www.bitplan.com
 *
 * This source is part of
 * https://github.com/BITPlan/CrazyBeans
 * and the license as outlined there applies
 */
package cb.parser;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

import cb.petal.Design;
import cb.petal.Petal;
import cb.petal.PetalFile;
import cb.petal.PetalNode;
import cb.petal.PetalNodeList;
import cb.petal.PetalObject;
import cb.petal.StringLiteral;
import cb.petal.Value;

/**
 * parser
 * 
 * @author wf
 *
 */
public class Parser {
  private Lexer lexer;

  private PetalNode current_parent = null;
  private Stack parent_stack = new Stack();

  private void saveParent(PetalNode new_parent) {
    parent_stack.push(current_parent);
    current_parent = new_parent;
  }

  private void restoreParent() {
    current_parent = (PetalNode) parent_stack.pop();
  }

  private static ObjectFactory factory = ObjectFactory.getInstance();

  public Parser(Reader r) {
    lexer = new Lexer(r);
  }

  private List ignored_nodes = new ArrayList();

  /**
   * If the parser finds such a node while building the petal tree, the node
   * will be ignored and not added to the tree. E.g,
   * setIgnoredNodes(Diagram.class) will abandon all diagrams of the model.
   */
  public void setIgnoredNodes(java.lang.Class[] nodes) {
    ignored_nodes = new ArrayList(Arrays.asList(nodes));
  }

  public java.lang.Class[] getIgnoredNodes() {
    java.lang.Class[] nodes = new java.lang.Class[ignored_nodes.size()];
    ignored_nodes.toArray(nodes);
    return nodes;
  }

  private boolean ignored(PetalNode obj) {
    for (Iterator i = ignored_nodes.iterator(); i.hasNext();) {
      java.lang.Class clazz = (java.lang.Class) i.next();
      if (clazz.isInstance(obj)) {
        return true;
      }
    }

    return false;
  }

  private Token match(int kind, String match) {
    Token t = lexer.getToken();

    if (t.kind != kind)
      throw new RuntimeException("Mismatch: Expected " + kind + " but got "
          + t.kind + " at line " + t.line);

    if ((match != null) && !match.equals(t.image))
      throw new RuntimeException("Mismatch: Expected " + match + " but got "
          + t.image + " at line " + t.line);

    return t;
  }

  private Token match(int kind) {
    return match(kind, null);
  }

  private ArrayList list = new ArrayList(); // Reused list to collect docs

  /**
   * (...)* wildcard
   * 
   * @return images
   */
  private ArrayList matchAll(int kind) {
    list.clear();

    Token t = lexer.getToken();

    while (t.kind == kind) {
      list.add(t.image);
      t = lexer.getToken();
    }

    lexer.ungetToken(t);

    return list;
  }

  /**
   * [...] optional
   * 
   * @return image
   */
  private Token matchAny(int kind) {
    Token t = lexer.getToken();

    if (t.kind == kind)
      return t;
    else {
      lexer.ungetToken(t);
      return null;
    }
  }

  public static PetalFile parse(String file_name) {
    return parse(new File(file_name));
  }

  public static PetalFile parse(java.net.URL url) {
    try {
      return parse(url.openStream());
    } catch (IOException e) {
      throw new RuntimeException(e.toString());
    }
  }

  public static PetalFile parse(File file) {
    try {
      PetalFile tree = parse(new FileReader(file));
      String name = file.getName();
      int index = name.lastIndexOf('.');

      if (index > 0)
        name = name.substring(0, index);

      tree.setModelName(name);

      return tree;
    } catch (IOException e) {
      throw new RuntimeException(e.toString());
    }
  }

  public static PetalFile parse(Reader stream) {
    return new Parser(stream).parse();
  }

  public static PetalFile parse(InputStream stream) {
    return parse(new InputStreamReader(stream));
  }

  /**
   * Top level construct are always petal and design objects
   */
  public PetalFile parse() {
    PetalObject petal, design;
    PetalFile file = new PetalFile();
    current_parent = file;

    petal = parseObject();
    design = parseObject();

    file.setPetal((Petal) petal);
    file.setDesign((Design) design);
    return file;
  }

  /*
   * Example: (object ClassView "Class" "Use Case View::Student" @76 location
   * (160, 176))
   */
  public PetalObject parseObject() {
    match(Lexer.LPAREN);
    match(Lexer.IDENT, "object");

    Token t1 = match(Lexer.IDENT);
    ArrayList docs = matchAll(Lexer.STRING);
    Token t3 = matchAny(Lexer.TAG);

    PetalNode parent = ignored(current_parent) ? null : current_parent;
    PetalObject obj = factory.createObject(parent, t1.image, docs,
        t3 == null ? null : t3.image);
    saveParent(obj);

    /*
     * List of properties
     */
    Token t4 = matchAny(Lexer.IDENT);

    while (t4 != null) {
      PetalNode prop = parseValue(false);

      if (prop != null)
        obj.addProperty(t4.image, prop);

      t4 = matchAny(Lexer.IDENT);
    }

    match(Lexer.RPAREN);

    restoreParent();

    if (!ignored(obj)) {
      obj.init();
      return obj;
    } else
      return null;
  }

  public PetalNode parseValue(boolean rparen_ok) {
    Token t = lexer.getToken();

    switch (t.kind) {
    case Lexer.STRING:
      return factory.createString(t.image, false);

    case Lexer.MULTI_STRING:
      return factory.createString(t.image, true);

    case Lexer.INTEGER:
      return factory.createInteger(t.image);

    case Lexer.FLOAT:
      return factory.createFloat(t.image);

    case Lexer.BOOLEAN:
      return factory.createBoolean(t.image);

    case Lexer.TAG:
      return factory.createTag(t.image);

    case Lexer.LPAREN:
      Token t2 = lexer.getToken();

      switch (t2.kind) {
      case Lexer.IDENT:
        lexer.ungetToken(t2);
        lexer.ungetToken(t);

        if (t2.image.equals("object")) {
          return parseObject();
        } else if (t2.image.equals("list")) {
          return parseList();
        } else if (t2.image.equals("value")) {
          return parseValueObject();
        } else
          throw new RuntimeException("Unexpected " + t2.image + " after (");

      case Lexer.INTEGER:
        match(Lexer.COMMA);
        Token t3 = match(Lexer.INTEGER);
        match(Lexer.RPAREN);

        return factory.createLocation(t2.image, t3.image);

      case Lexer.STRING:
        Token t4 = match(Lexer.INTEGER);
        match(Lexer.RPAREN);
        return factory.createTuple(t2.image, t4.image);

      default:
        throw new RuntimeException("Unexpected " + t2.image + "after (");
      }

    default:
      if ((t.kind == Lexer.RPAREN) && rparen_ok)
        return null;
      else
        throw new RuntimeException("Unexpected " + t.image);
    }
  }

  /*
   * Example: (list unit_reference_list (object Module_Diagram "Main" quid
   * "35CB163B03CF"))
   *
   */
  public PetalNodeList parseList() {
    match(Lexer.LPAREN);
    match(Lexer.IDENT, "list");

    Token t = matchAny(Lexer.IDENT);
    PetalNodeList list = factory.createList(t == null ? null : t.image);

    PetalNode obj;

    while ((obj = parseValue(true)) != null) // null == RPAREN
      list.add(obj);
    return list;
  }

  public Value parseValueObject() {
    match(Lexer.LPAREN);
    match(Lexer.IDENT, "value");
    Token t = match(Lexer.IDENT);
    Token t2 = lexer.getToken();
    StringLiteral str;

    switch (t2.kind) {
    case Lexer.STRING:
      str = factory.createString(t2.image, false);
      break;
    case Lexer.MULTI_STRING:
      str = factory.createString(t2.image, true);
      break;
    default:
      throw new RuntimeException("Unexpected " + t2.image + " in (value ...)");
    }

    match(Lexer.RPAREN);
    return factory.createValue(t.image, str);
  }

  public static void main(String[] args) throws Exception {
    FileReader r = new FileReader(args[0]);

    Parser parser = new Parser(r);
    parser.parse();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy