GoMod { @Nonnull public static GoMod from(@Nonnull final String str) { final List<GoModItem> foundItems = new ArrayList<>(); final Matcher matcher = TOKENIZER.matcher(str); ParserState state = ParserState.FIND; boolean findEol = false; boolean bracket = false; final List<String> tokenList = new ArrayList<>(); String customTokenName = null; while (matcher.find()) { final String token = matcher.group(1); if (findEol) { if (token.contains("\n")) { findEol = false; state = bracket ? state : ParserState.FIND; } } else { switch (state) { case FIND: { tokenList.clear(); switch (token) { case "module": { state = ParserState.MODULE; } break; case "exclude": { state = ParserState.EXCLUDE; } break; case "replace": { state = ParserState.REPLACE; } break; case "require": { state = ParserState.REQUIRE; } break; default: { if (" findEol = true; } else if (!token.trim().isEmpty()) { state = ParserState.CUSTOM; customTokenName = token; } } break; } } break; case CUSTOM: { if (" if (!bracket) { foundItems.add(new GoCustom(customTokenName, tokenList.toArray(new String[0]))); foundItems.clear(); customTokenName = null; state = ParserState.FIND; } } else { if ("(".equals(token)) { if (bracket) { throw new IllegalArgumentException("Duplicated opening bracket in " + state); } bracket = true; } else if (")".equals(token)) { if (!bracket) { throw new IllegalArgumentException("Unexpected closing bracket in " + state); } bracket = false; foundItems.add(new GoCustom(customTokenName, tokenList.toArray(new String[0]))); foundItems.clear(); customTokenName = null; state = ParserState.FIND; } else if (token.contains("\n")) { if (!bracket) { state = ParserState.FIND; foundItems.add(new GoCustom(customTokenName, tokenList.toArray(new String[0]))); } } else { if (!token.trim().isEmpty()) { tokenList.add(token); } } } } break; case MODULE: case EXCLUDE: case REPLACE: case REQUIRE: { if ("(".equals(token)) { if (bracket) { throw new IllegalArgumentException("Duplicated opening bracket in " + state); } if (!tokenList.isEmpty()) { throw new IllegalArgumentException("Unexpected tokens " + tokenList + " before bracket in " + state); } bracket = true; } else { final boolean processTokenList; ParserState nextState = state; if (")".equals(token)) { if (!bracket) { throw new IllegalArgumentException("Unexpected closing bracket in " + state); } bracket = false; processTokenList = !tokenList.isEmpty(); nextState = ParserState.FIND; } else if (" findEol = true; processTokenList = !bracket || !tokenList.isEmpty(); nextState = bracket ? state : ParserState.FIND; } else if (token.contains("\n")) { processTokenList = !bracket || !tokenList.isEmpty(); nextState = bracket ? state : ParserState.FIND; } else { if (!token.trim().isEmpty()) { tokenList.add(ensureNoQuoting(token)); } processTokenList = false; } if (processTokenList) { switch (state) { case MODULE: { final List<ModuleInfo> moduleInfos = extractModuleInfo(tokenList); tokenList.clear(); while (!moduleInfos.isEmpty()) { foundItems.add(new GoModule(moduleInfos.remove(0))); } } break; case REQUIRE: { final List<ModuleInfo> moduleInfos = extractModuleInfo(tokenList); tokenList.clear(); while (!moduleInfos.isEmpty()) { foundItems.add(new GoRequire(moduleInfos.remove(0))); } } break; case EXCLUDE: { final List<ModuleInfo> moduleInfos = extractModuleInfo(tokenList); tokenList.clear(); while (!moduleInfos.isEmpty()) { foundItems.add(new GoExclude(moduleInfos.remove(0))); } } break; case REPLACE: { final List<ModuleInfo> moduleInfos = extractModuleInfo(tokenList, "=>"); tokenList.clear(); while (!moduleInfos.isEmpty()) { final ModuleInfo from = moduleInfos.remove(0); if (moduleInfos.isEmpty()) { throw new IllegalArgumentException("Can't find target in replace"); } final ModuleInfo to = moduleInfos.remove(0); foundItems.add(new GoReplace(from, to)); } } break; default: throw new Error("Unexpected: " + state); } } state = nextState; } } break; } } } if (!tokenList.isEmpty()) { switch (state) { case MODULE: { final List<ModuleInfo> moduleInfos = extractModuleInfo(tokenList); tokenList.clear(); while (!moduleInfos.isEmpty()) { foundItems.add(new GoModule(moduleInfos.remove(0))); } } break; case REQUIRE: { final List<ModuleInfo> moduleInfos = extractModuleInfo(tokenList); tokenList.clear(); while (!moduleInfos.isEmpty()) { foundItems.add(new GoRequire(moduleInfos.remove(0))); } } break; case EXCLUDE: { final List<ModuleInfo> moduleInfos = extractModuleInfo(tokenList); tokenList.clear(); while (!moduleInfos.isEmpty()) { foundItems.add(new GoExclude(moduleInfos.remove(0))); } } break; case REPLACE: { final List<ModuleInfo> moduleInfos = extractModuleInfo(tokenList, "=>"); tokenList.clear(); while (!moduleInfos.isEmpty()) { final ModuleInfo from = moduleInfos.remove(0); if (moduleInfos.isEmpty()) { throw new IllegalArgumentException("Can't find target in replace"); } final ModuleInfo to = moduleInfos.remove(0); foundItems.add(new GoReplace(from, to)); } } break; case CUSTOM: { foundItems.add(new GoCustom(customTokenName, tokenList.toArray(new String[0]))); } break; default:break; } } return new GoMod(foundItems); } private  GoMod(@Nonnull @MustNotContainNull final List<GoModItem> items); @Override boolean equals(@Nullable final Object that); @Override int hashCode(); @Nonnull static GoMod from(@Nonnull final String str); @Nonnull GoMod addItem(@Nonnull final GoModItem item); @Nonnull @MustNotContainNull List<T> find(@Nonnull final Class<T> klass); int size(); @Nonnull @Override String toString(); boolean hasReplaceFor(@Nonnull final String moduleName, @Nullable final String version); boolean hasRequireFor(@Nonnull final String moduleName, @Nullable final String version); @Nullable String getModule();  }
@Test public void testModule() { assertModules(GoMod.from("module (example.com/hello) assertModules(GoMod.from("module (\n" + "example.com/hello + " \"sss.gid/fsdsd\" \n" + ") assertModules(GoMod.from("module (example.com/hello) assertModules(GoMod.from("module example.com/hello"), "example.com/hello"); assertModules(GoMod.from("module example.com/hello\n"), "example.com/hello"); assertModules(GoMod.from("module example.com/hello assertModules(GoMod.from("\n \n module \"example.com/hello\" assertModules(GoMod.from("module \"example.com/hello\""), "example.com/hello"); assertModules(GoMod.from("module \"example.com/hello\"\n"), "example.com/hello"); assertModules(GoMod.from("module \"example.com/hello\" }