I am working on creating a regex parser for a class project, and I've run into a problem I can't figure out how to fix. Whenever it encounters a parenthesized group, it is supposed to add a placeholder to the groups ArrayList where a group can then be captured from a String. The problem is that it throws a NullPointerException whenever it attempts to add to this ArrayList. Here is the Segment constructor, where this occurs:
public Segment(String value, boolean capture) throws ParseException {
    values = new ArrayList<>();
    parse(value);
    minimum = 1;
    maximum = 1;
    matchNot = false;
    captureGroup = capture;
    if (capture) {
        RegexGUI.input.groups.add(""); //error occurs on this line
    }
}
Note that RegexGUI.input refers to the relevant instance of Regex, which the constructor for is here:
public Regex(String value) throws ParseException {
    this.value = value;
    segments = new ArrayList<>();
    groups = new ArrayList<>();
    anchorStart = false;
    anchorEnd = false;
    tokenize(value, true, false);
}
As you can see, groups is clearly initialized in the constructor. Also, the Segment constructor is only called in the tokenize() method in the Regex class, and that method is only called by the Regex constructor, so there is no possible way I could see that the problem would simply be that groups has not been initialized.
The entire stacktrace is here:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at regexparser.Segment.<init>(Segment.java:39)
    at regexparser.Regex.tokenize(Regex.java:57)
    at regexparser.Regex.<init>(Regex.java:27)
    at regexparser.RegexGUI.actionPerformed(RegexGUI.java:80)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
    at java.awt.Component.processMouseEvent(Component.java:6535)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
    at java.awt.Component.processEvent(Component.java:6300)
    at java.awt.Container.processEvent(Container.java:2236)
    at java.awt.Component.dispatchEventImpl(Component.java:4891)
    at java.awt.Container.dispatchEventImpl(Container.java:2294)
    at java.awt.Component.dispatchEvent(Component.java:4713)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
    at java.awt.Container.dispatchEventImpl(Container.java:2280)
    at java.awt.Window.dispatchEventImpl(Window.java:2750)
    at java.awt.Component.dispatchEvent(Component.java:4713)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.awt.EventQueue$4.run(EventQueue.java:731)
    at java.awt.EventQueue$4.run(EventQueue.java:729)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
This is the line of code in tokenize() mentioned in the stacktrace:
segments.add(new Segment(value.substring(0, value.indexOf(")")+1), true));
This is the line of code in actionPerformed() mentioned in the stacktrace:
input = new Regex(regexInput.getText());
I don't know if this is necessary to post or not, but here are my instance and class variables for each class:
Regex class:
String value;
ArrayList<Segment> segments;
ArrayList<String> groups;
boolean anchorStart;
boolean anchorEnd;
Segment class:
ArrayList<String> values;
int minimum;
int maximum;
boolean matchNot;
boolean captureGroup;
final static String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
final static String LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
final static String DIGITS = "0123456789";
final static String[] SETS = {UPPERCASE, LOWERCASE, DIGITS};
final static String WORD = UPPERCASE + LOWERCASE + DIGITS + "_";
final static String WHITESPACE = " \r\n\t\f";
RegexGUI class:
Container contentPane;
JPanel panel;
GridBagLayout gridbag;
GridBagConstraints c;
JLabel regexPrompt, stringPrompt, result;
JTextField regexInput;
JTextArea stringInput;
JButton test;
static Regex input;
boolean match;
I would appreciate any help you guys can give me. I've tried looking up what might be causing this exception, but the only answer I can find is that groups is not initialized. I've searched through my code to try to figure out any way that the Segment constructor may be called before groups is initialized, but I can't see any way that would be possible.
 
    