Пример #1
1
  /**
   * Break on commas, except those inside quotes, e.g.: size(300, 200, PDF, "output,weirdname.pdf");
   * No special handling implemented for escaped (\") quotes.
   */
  private static StringList breakCommas(String contents) {
    StringList outgoing = new StringList();

    boolean insideQuote = false;
    // The current word being read
    StringBuilder current = new StringBuilder();
    char[] chars = contents.toCharArray();
    for (int i = 0; i < chars.length; i++) {
      char c = chars[i];
      if (insideQuote) {
        current.append(c);
        if (c == '\"') {
          insideQuote = false;
        }
      } else {
        if (c == ',') {
          if (current.length() != 0) {
            outgoing.append(current.toString());
            current.setLength(0);
          }
        } else {
          current.append(c);
          if (c == '\"') {
            insideQuote = true;
          }
        }
      }
    }
    if (current.length() != 0) {
      outgoing.append(current.toString());
    }
    return outgoing;
  }
Пример #2
0
  /**
   * Parse a chunk of code and extract the size() command and its contents. Also goes after
   * fullScreen(), smooth(), and noSmooth().
   *
   * @param code The code from the main tab in the sketch
   * @param fussy true if it should show an error message if bad size()
   * @return null if there was an error, otherwise an array (might contain some/all nulls)
   */
  public static SurfaceInfo parseSketchSizeCustom(String code, boolean fussy)
      throws SketchException {
    // This matches against any uses of the size() function, whether numbers
    // or variables or whatever. This way, no warning is shown if size() isn't
    // actually used in the applet, which is the case especially for anyone
    // who is cutting/pasting from the reference.

    //    String scrubbed = scrubComments(sketch.getCode(0).getProgram());
    //    String[] matches = PApplet.match(scrubbed, SIZE_REGEX);
    //    String[] matches = PApplet.match(scrubComments(code), SIZE_REGEX);

    /*
    1. no size() or fullScreen() method at all
       will use the non-overridden settings() method in PApplet
    2. size() or fullScreen() found inside setup() (static mode sketch or otherwise)
       make sure that it uses numbers (or displayWidth/Height), copy into settings
    3. size() or fullScreen() already in settings()
       don't mess with the sketch, don't insert any defaults
    really only need to deal with situation #2.. nothing to be done for 1 and 3
    */
    // if static mode sketch, all we need is regex
    // easy proxy for static in this case is whether [^\s]void\s is present

    String uncommented = scrubComments(code);

    Mode mode = parseMode(uncommented);

    String searchArea = null;

    switch (mode) {
      case JAVA:
        // it's up to the user
        searchArea = null;
        break;
      case ACTIVE:
        // active mode, limit scope to setup

        // Find setup() in global scope
        MatchResult setupMatch = findInCurrentScope(VOID_SETUP_REGEX, uncommented);
        if (setupMatch != null) {
          int start = uncommented.indexOf("{", setupMatch.end());
          if (start >= 0) {
            // Find a closing brace
            MatchResult match = findInCurrentScope(CLOSING_BRACE, uncommented, start);
            if (match != null) {
              searchArea = uncommented.substring(start + 1, match.end() - 1);
            } else {
              throw new SketchException("Found a { that's missing a matching }", false);
            }
          }
        }
        break;
      case STATIC:
        // static mode, look everywhere
        searchArea = uncommented;
        break;
    }

    if (searchArea == null) {
      return new SurfaceInfo();
    }

    StringList extraStatements = new StringList();

    // First look for noSmooth() or smooth(N) so we can hoist it into settings.
    String[] smoothContents = matchMethod("smooth", searchArea);
    if (smoothContents != null) {
      extraStatements.append(smoothContents[0]);
    }
    String[] noContents = matchMethod("noSmooth", searchArea);
    if (noContents != null) {
      if (extraStatements.size() != 0) {
        throw new SketchException("smooth() and noSmooth() cannot be used in the same sketch");
      } else {
        extraStatements.append(noContents[0]);
      }
    }
    String[] pixelDensityContents = matchMethod("pixelDensity", searchArea);
    if (pixelDensityContents != null) {
      extraStatements.append(pixelDensityContents[0]);
    } else {
      pixelDensityContents = matchDensityMess(searchArea);
      if (pixelDensityContents != null) {
        extraStatements.append(pixelDensityContents[0]);
      }
    }

    String[] sizeContents = matchMethod("size", searchArea);
    String[] fullContents = matchMethod("fullScreen", searchArea);
    // First check and make sure they aren't both being used, otherwise it'll
    // throw a confusing state exception error that one "can't be used here".
    if (sizeContents != null && fullContents != null) {
      throw new SketchException("size() and fullScreen() cannot be used in the same sketch", false);
    }

    // Get everything inside the parens for the size() method
    // String[] contents = PApplet.match(searchArea, SIZE_CONTENTS_REGEX);
    if (sizeContents != null) {
      StringList args = breakCommas(sizeContents[1]);
      SurfaceInfo info = new SurfaceInfo();
      //      info.statement = sizeContents[0];
      info.addStatement(sizeContents[0]);
      //			info.width = args.get(0).trim();
      //			info.height = args.get(1).trim();
      //			info.renderer = (args.size() >= 3) ? args.get(2).trim() : null;
      //			info.path = (args.size() >= 4) ? args.get(3).trim() : null;
      setPrivateSurfaceInfoField(info, "width", (args.size() >= 1) ? args.get(0).trim() : null);
      setPrivateSurfaceInfoField(info, "height", (args.size() >= 2) ? args.get(1).trim() : null);
      setPrivateSurfaceInfoField(info, "renderer", (args.size() >= 3) ? args.get(2).trim() : null);
      setPrivateSurfaceInfoField(info, "path", (args.size() >= 4) ? args.get(3).trim() : null);

      // Trying to remember why we wanted to allow people to use displayWidth
      // as the height or displayHeight as the width, but maybe it's for
      // making a square sketch window? Not going to

      //			if (info.hasOldSyntax()) {
      if (hasOldSyntax(info)) {
        //        return null;
        throw new SketchException("Please update your code to continue.", false);
      }

      //			if (info.hasBadSize() && fussy) {
      if (hasBadSize(info) && fussy) {
        // found a reference to size, but it didn't seem to contain numbers
        final String message =
            "The size of this sketch could not be determined from your code.\n"
                + "Use only numbers (not variables) for the size() command.\n"
                + "Read the size() reference for more details.";
        //				Messages.showWarning("Could not find sketch size", message, null);
        showWarning("Could not find sketch size", message);
        //        new Exception().printStackTrace(System.out);
        //        return null;
        throw new SketchException("Please fix the size() line to continue.", false);
      }

      info.addStatements(extraStatements);
      //			info.checkEmpty();
      invokePrivateSurfaceInfoMethod(info, "checkEmpty", null);
      return info;
      // return new String[] { contents[0], width, height, renderer, path };
    }
    // if no size() found, check for fullScreen()
    // contents = PApplet.match(searchArea, FULL_SCREEN_CONTENTS_REGEX);
    if (fullContents != null) {
      SurfaceInfo info = new SurfaceInfo();
      //      info.statement = fullContents[0];
      info.addStatement(fullContents[0]);
      StringList args = breakCommas(fullContents[1]);
      if (args.size() > 0) { // might have no args
        String args0 = args.get(0).trim();
        if (args.size() == 1) {
          // could be either fullScreen(1) or fullScreen(P2D), figure out which
          if (args0.equals("SPAN") || PApplet.parseInt(args0, -1) != -1) {
            // it's the display parameter, not the renderer
            //						info.display = args0;
            setPrivateSurfaceInfoField(info, "display", args0);
          } else {
            //						info.renderer = args0;
            setPrivateSurfaceInfoField(info, "renderer", args0);
          }
        } else if (args.size() == 2) {
          //					info.renderer = args0;
          //					info.display = args.get(1).trim();
          setPrivateSurfaceInfoField(info, "renderer", args0);
          setPrivateSurfaceInfoField(info, "display", args.get(1).trim());
        } else {
          throw new SketchException("That's too many parameters for fullScreen()");
        }
      }
      //			info.width = "displayWidth";
      //			info.height = "displayHeight";
      setPrivateSurfaceInfoField(info, "width", "displayWidth");
      setPrivateSurfaceInfoField(info, "height", "displayHeight");
      //      if (extraStatements.size() != 0) {
      //        info.statement += extraStatements.join(" ");
      //      }
      info.addStatements(extraStatements);
      //			info.checkEmpty();
      invokePrivateSurfaceInfoMethod(info, "checkEmpty", null);

      return info;
    }

    // Lint is telling me that this statement is never true... but I beg to differ
    if (sizeContents == null && fullContents == null) {
      /*
       * Default to fullscreen
       *
       * This isn't in Processing's implementation, but for some reason the prior version
       * of APDE also defaulted to fullscreen, so include this to keep it the same
       *
       * Plus, it makes more sense to default to fullscreen - who wants a 100 x 100 sketch
       * display area on a mobile device?
       */

      SurfaceInfo info = new SurfaceInfo();

      info.addStatement("fullScreen();");

      setPrivateSurfaceInfoField(info, "width", "displayWidth");
      setPrivateSurfaceInfoField(info, "height", "displayHeight");

      info.addStatements(extraStatements);
      invokePrivateSurfaceInfoMethod(info, "checkEmpty", null);

      return info;
    }

    // Made it this far, but no size() or fullScreen(), and still
    // need to pull out the noSmooth() and smooth(N) methods.
    if (extraStatements.size() != 0) {
      SurfaceInfo info = new SurfaceInfo();
      //      info.statement = extraStatements.join(" ");
      info.addStatements(extraStatements);
      return info;
    }

    // not an error, just no size() specified
    // return new String[] { null, null, null, null, null };
    return new SurfaceInfo();
  }
Пример #3
0
  /**
   * Parse a chunk of code and extract the size() command and its contents. Also goes after
   * fullScreen(), smooth(), and noSmooth().
   *
   * @param code The code from the main tab in the sketch
   * @param fussy true if it should show an error message if bad size()
   * @return null if there was an error, otherwise an array (might contain some/all nulls)
   */
  public static SurfaceInfo parseSketchSize(String code, boolean fussy) throws SketchException {
    // This matches against any uses of the size() function, whether numbers
    // or variables or whatever. This way, no warning is shown if size() isn't
    // actually used in the applet, which is the case especially for anyone
    // who is cutting/pasting from the reference.

    //    String scrubbed = scrubComments(sketch.getCode(0).getProgram());
    //    String[] matches = PApplet.match(scrubbed, SIZE_REGEX);
    //    String[] matches = PApplet.match(scrubComments(code), SIZE_REGEX);

    /*
    1. no size() or fullScreen() method at all
       will use the non-overridden settings() method in PApplet
    2. size() or fullScreen() found inside setup() (static mode sketch or otherwise)
       make sure that it uses numbers (or displayWidth/Height), copy into settings
    3. size() or fullScreen() already in settings()
       don't mess with the sketch, don't insert any defaults

    really only need to deal with situation #2.. nothing to be done for 1 and 3
    */
    // if static mode sketch, all we need is regex
    // easy proxy for static in this case is whether [^\s]void\s is present

    String searchArea = scrubComments(code);
    String[] setupMatch = PApplet.match(searchArea, VOID_SETUP_REGEX);
    if (setupMatch != null) {
      String found = setupMatch[0];
      int start = searchArea.indexOf(found) + found.length();
      int openBrace = searchArea.indexOf("{", start);
      char[] c = searchArea.toCharArray();
      int depth = 0;
      int closeBrace = -1;
      StringBuilder sb = new StringBuilder();
      for (int i = openBrace; i < c.length; i++) {
        if (c[i] == '{') {
          depth++;
        } else if (c[i] == '}') {
          depth--;
          if (depth == 0) {
            closeBrace = ++i;
            break;
          }
        } else {
          sb.append(c[i]);
        }
      }
      if (closeBrace == -1) {
        throw new SketchException("Found a { that's missing a matching }", false);
        //        return null;
      }
      searchArea = sb.toString();
    }

    StringList extraStatements = new StringList();

    // First look for noSmooth() or smooth(N) so we can hoist it into settings.
    String[] smoothContents = matchMethod("smooth", searchArea);
    if (smoothContents != null) {
      extraStatements.append(smoothContents[0]);
    }
    String[] noContents = matchMethod("noSmooth", searchArea);
    if (noContents != null) {
      if (extraStatements.size() != 0) {
        throw new SketchException("smooth() and noSmooth() cannot be used in the same sketch");
      } else {
        extraStatements.append(noContents[0]);
      }
    }
    String[] pixelDensityContents = matchMethod("pixelDensity", searchArea);
    if (pixelDensityContents != null) {
      extraStatements.append(pixelDensityContents[0]);
    }

    String[] sizeContents = matchMethod("size", searchArea);
    String[] fullContents = matchMethod("fullScreen", searchArea);
    // First check and make sure they aren't both being used, otherwise it'll
    // throw a confusing state exception error that one "can't be used here".
    if (sizeContents != null && fullContents != null) {
      throw new SketchException("size() and fullScreen() cannot be used in the same sketch", false);
    }

    // Get everything inside the parens for the size() method
    // String[] contents = PApplet.match(searchArea, SIZE_CONTENTS_REGEX);
    if (sizeContents != null) {
      StringList args = breakCommas(sizeContents[1]);
      SurfaceInfo info = new SurfaceInfo();
      info.statement = sizeContents[0];
      info.width = args.get(0).trim();
      info.height = args.get(1).trim();
      info.renderer = (args.size() >= 3) ? args.get(2).trim() : null;
      info.path = (args.size() >= 4) ? args.get(3).trim() : null;

      // Trying to remember why we wanted to allow people to use displayWidth
      // as the height or displayHeight as the width, but maybe it's for
      // making a square sketch window? Not going to

      if (info.hasOldSyntax()) {
        //        return null;
        throw new SketchException("Please update your code to continue.", false);
      }

      if (info.hasBadSize() && fussy) {
        // found a reference to size, but it didn't seem to contain numbers
        final String message =
            "The size of this sketch could not be determined from your code.\n"
                + "Use only numbers (not variables) for the size() command.\n"
                + "Read the size() reference for more details.";
        Base.showWarning("Could not find sketch size", message, null);
        //        new Exception().printStackTrace(System.out);
        //        return null;
        throw new SketchException("Please fix the size() line to continue.", false);
      }

      if (extraStatements.size() != 0) {
        info.statement += extraStatements.join(" ");
      }
      info.checkEmpty();
      return info;
      // return new String[] { contents[0], width, height, renderer, path };
    }
    // if no size() found, check for fullScreen()
    // contents = PApplet.match(searchArea, FULL_SCREEN_CONTENTS_REGEX);
    if (fullContents != null) {
      SurfaceInfo info = new SurfaceInfo();
      info.statement = fullContents[0];
      StringList args = breakCommas(fullContents[1]);
      if (args.size() > 0) { // might have no args
        String args0 = args.get(0).trim();
        if (args.size() == 1) {
          // could be either fullScreen(1) or fullScreen(P2D), figure out which
          if (args0.equals("SPAN") || PApplet.parseInt(args0, -1) != -1) {
            // it's the display parameter, not the renderer
            info.display = args0;
          } else {
            info.renderer = args0;
          }
        } else if (args.size() == 2) {
          info.renderer = args0;
          info.display = args.get(1).trim();
        } else {
          throw new SketchException("That's too many parameters for fullScreen()");
        }
      }
      info.width = "displayWidth";
      info.height = "displayHeight";
      if (extraStatements.size() != 0) {
        info.statement += extraStatements.join(" ");
      }
      info.checkEmpty();
      return info;
    }

    // Made it this far, but no size() or fullScreen(), and still
    // need to pull out the noSmooth() and smooth(N) methods.
    if (extraStatements.size() != 0) {
      SurfaceInfo info = new SurfaceInfo();
      info.statement = extraStatements.join(" ");
      return info;
    }

    // not an error, just no size() specified
    // return new String[] { null, null, null, null, null };
    return new SurfaceInfo();
  }