Commit d16a80a2 authored by Paul Asmuth's avatar Paul Asmuth
Browse files

plist: improved representation and parsing of lists and tuples

parent 57f96de3
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -12,22 +12,22 @@

namespace plist {

PropertyValue::operator const std::string&() const {
  return data;
const Property& Property::operator[](size_t i) const {
  assert(next);
  assert(i < next->size());
  return (*next)[i];
}

const PropertyValue& Property::get(size_t i) const {
  assert(i < values.size());
  return values[i];
size_t Property::size() const {
  if (next) {
    return next->size();
  } else {
    return 0;
  }

const PropertyValue& Property::operator[](size_t i) const {
  assert(i < values.size());
  return values[i];
}

size_t Property::size() const {
  return values.size();
Property::operator const std::string&() const {
  return value;
}

} // namespace plist
+9 −8
Original line number Diff line number Diff line
@@ -17,20 +17,21 @@ struct Property;

using PropertyList = std::vector<Property>;

struct PropertyValue {
  std::string data;
  bool is_literal;
  operator const std::string&() const;
enum class PropertyKind {
  MAP, TUPLE, LIST, VALUE, VALUE_LITERAL
};

struct Property {
  std::string name;
  std::vector<PropertyValue> values;
  std::unique_ptr<std::vector<Property>> child;
  PropertyKind kind;
  std::unique_ptr<std::vector<Property>> next;
  std::string value;

  const PropertyValue& get(size_t i) const;
  const PropertyValue& operator[](size_t i) const;
  const Property& operator[](size_t i) const;
  size_t size() const;

  operator const std::string&() const;

};

} // namespace plist
+121 −26
Original line number Diff line number Diff line
@@ -30,10 +30,9 @@
#include <regex>
#include <iostream>
#include "plist_parser.h"
#include "utils/stringutil.h"
#include "stringutil.h"

namespace plist {
using plotfx::StringUtil;

PropertyListParser::PropertyListParser(
    const char* input,
@@ -52,7 +51,7 @@ bool PropertyListParser::parse(PropertyList* plist) {
  TokenType ttype;
  std::string tbuf;
  while (getToken(&ttype, &tbuf)) {
    if (!parsePropertyOrList(plist)) {
    if (!parsePropertyOrMap(plist)) {
      return false;
    }
  }
@@ -60,7 +59,7 @@ bool PropertyListParser::parse(PropertyList* plist) {
  return true;
}

bool PropertyListParser::parsePropertyOrList(PropertyList* plist) {
bool PropertyListParser::parsePropertyOrMap(PropertyList* plist) {
  std::string pname;
  if (!expectAndConsumeString(&pname)) {
    return false;
@@ -83,7 +82,7 @@ bool PropertyListParser::parsePropertyOrList(PropertyList* plist) {
    case T_LCBRACE:
      return
          consumeToken() &&
          parsePropertyList(pname, plist) &&
          parsePropertyMap(pname, plist) &&
          expectAndConsumeToken(T_RCBRACE);

    default:
@@ -99,52 +98,148 @@ bool PropertyListParser::parseProperty(const std::string& pname, PropertyList* p
  Property prop;
  prop.name = pname;

  PropertyList args;
  if (!parsePropertyListOrTuple(&args)) {
    return false;
  }

  if (args.size() == 1) {
    prop.kind = args[0].kind;
    prop.value = args[0].value;
    prop.next = std::move(args[0].next);
  } else {
    prop.kind = PropertyKind::LIST;
    prop.next = std::make_unique<PropertyList>(std::move(args));
  }

  plist->emplace_back(std::move(prop));
  return true;
}

bool PropertyListParser::parsePropertyListOrTuple(PropertyList* plist) {
  TokenType ttype;
  std::string tbuf;
  for (; getToken(&ttype, &tbuf) && ttype != T_SEMICOLON; consumeToken()) {
    PropertyValue pval;
    pval.is_literal = true;
  while (getToken(&ttype, &tbuf) && ttype != T_SEMICOLON) {
    Property prop;
    if (!parsePropertyTupleOrValue(&prop)) {
      return false;
    }

    plist->emplace_back(std::move(prop));

    if (!getToken(&ttype, &tbuf)) {
      return false;
    }

    switch (ttype) {
      case T_SEMICOLON:
        return true;

      case T_COMMA:
        pval.data = ",";
        break;
      case T_LPAREN:
        pval.data = "(";
        break;
      case T_RPAREN:
        pval.data = ")";
        consumeToken();
        continue;

      default:
        setError(
            StringUtil::format(
                "unexpected token '$0'; expected SEMICOLON OR COMMA",
                printToken(ttype, tbuf)));
        return false;
    }
  }

  return true;
}

bool PropertyListParser::parsePropertyTupleOrValue(Property* prop) {
  PropertyList args;
  if (!parsePropertyTuple(&args)) {
    return false;
  }

  if (args.size() == 1) {
    prop->kind = args[0].kind;
    prop->value = args[0].value;
  } else {
    prop->kind = PropertyKind::TUPLE;
    prop->next = std::make_unique<PropertyList>(std::move(args));
  }

  return true;
}

bool PropertyListParser::parsePropertyTuple(PropertyList* plist) {
  TokenType ttype;
  std::string tbuf;
  while (getToken(&ttype, &tbuf) && ttype != T_SEMICOLON) {
    switch (ttype) {
      case T_STRING_QUOTED:
      case T_STRING: {
        Property prop;
        if (!parsePropertyValue(&prop)) {
          return false;
        }

        plist->emplace_back(std::move(prop));
        break;
      }

      case T_COMMA:
        return true;

      default:
        setError(
            StringUtil::format(
                "unexpected token '$0'; expected STRING",
                printToken(ttype, tbuf)));
        return false;
    }

  }

  return true;
}

bool PropertyListParser::parsePropertyValue(Property* prop) {
  TokenType ttype;
  std::string tbuf;
  if (!getToken(&ttype, &tbuf)) {
    return false;
  }

  switch (ttype) {
    case T_STRING_QUOTED:
        pval.is_literal = false;
        /* fallthrough */
      prop->kind = PropertyKind::VALUE;
      prop->value = tbuf;
      consumeToken();
      break;
    case T_STRING:
        pval.data = tbuf;
      prop->kind = PropertyKind::VALUE_LITERAL;
      prop->value = tbuf;
      consumeToken();
      break;
    default:
      setError(
          StringUtil::format(
                "unexpected token '$0'; expected one of: STRING, COMMA, LPAREN, RPAREN",
              "unexpected token '$0'; expected STRING",
              printToken(ttype, tbuf)));
      return false;
  }

    prop.values.emplace_back(pval);
  }

  plist->emplace_back(std::move(prop));
  return true;
}

bool PropertyListParser::parsePropertyList(const std::string& pname, PropertyList* plist) {
bool PropertyListParser::parsePropertyMap(const std::string& pname, PropertyList* plist) {
  Property prop;
  prop.name = pname;
  prop.child = std::make_unique<PropertyList>();
  prop.kind = PropertyKind::MAP;
  prop.next = std::make_unique<PropertyList>();

  TokenType ttype;
  std::string tbuf;
  while (getToken(&ttype, &tbuf) && ttype != T_RCBRACE) {
    if (!parsePropertyOrList(prop.child.get())) {
    if (!parsePropertyOrMap(prop.next.get())) {
      return false;
    }
  }
+6 −2
Original line number Diff line number Diff line
@@ -68,9 +68,13 @@ protected:

  bool consumeToken();

  bool parsePropertyOrList(PropertyList* plist);
  bool parsePropertyOrMap(PropertyList* plist);
  bool parseProperty(const std::string& pname, PropertyList* plist);
  bool parsePropertyList(const std::string& pname, PropertyList* plist);
  bool parsePropertyListOrTuple(PropertyList* plist);
  bool parsePropertyTupleOrValue(Property* prop);
  bool parsePropertyTuple(PropertyList* plist);
  bool parsePropertyValue(Property* plist);
  bool parsePropertyMap(const std::string& pname, PropertyList* plist);

  bool getToken(
      TokenType* type,