antlr/antlr4 · error · UnsupportedOperationException

Cannot handle relative paths containing '..'

Error message

Cannot handle relative paths containing '..'

What it means

split(pattern) scans for start/stop delimiter positions; if it finds more start delimiters than stop delimiters, at least one tag was never closed, and chunk extraction cannot proceed, so IllegalArgumentException 'unterminated tag' is thrown. The message echoes the whole pattern to show the offending input.

Source

Thrown at antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4Mojo.java:480

		SourceMapping mapping = new SuffixMapping("g4", Collections.<String>emptySet());

		// What are the sets of includes (defaulted or otherwise).
		Set<String> includes = getIncludesPatterns();

		// Now, to the excludes, we need to add the imports directory
		// as this is autoscanned for imported grammars and so is auto-excluded from the
		// set of grammar fields we should be analyzing.
		excludes.add("imports/**");

		SourceInclusionScanner scan = new SimpleSourceInclusionScanner(includes, excludes);
		scan.addSourceMapping(mapping);

		return scan.getIncludedSources(sourceDirectory, null);
	}

	private static String getPackageName(String relativeFolderPath) {
		if (relativeFolderPath.contains("..")) {
			throw new UnsupportedOperationException("Cannot handle relative paths containing '..'");
		}

		List<String> parts = new ArrayList<String>(Arrays.asList(relativeFolderPath.split("[/\\\\\\.]+")));
		while (parts.remove("")) {
			// intentionally blank
		}

		return Utils.join(parts.iterator(), ".");
	}

    public Set<String> getIncludesPatterns() {
        if (includes == null || includes.isEmpty()) {
            return Collections.singleton("**/*.g4");
        }
        return includes;
    }

    private File getDependenciesStatusFile() {

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Balance every tag: each '<' needs a matching '>'.
  2. Escape literal delimiters in text chunks with the configured escape sequence (default '\\' passed as escapeLeft).
  3. If the target language is full of '<', switch delimiters via setDelimiters to something rare like %% %%.

Example fix

// before
ParseTreePattern p = m.compile("a < <ID>", R.expr); // first '<' unterminated

// after
ParseTreePattern p = m.compile("a \\< <ID>", R.expr); // escaped literal '<'
Defensive patterns

Strategy: try-catch

Validate before calling

long starts = pattern.chars().filter(c -> c == '<').count();
long stops  = pattern.chars().filter(c -> c == '>').count();
if (starts > stops) throw new IllegalArgumentException("unterminated tag: " + pattern);

Type guard

boolean hasBalancedTags(String p) {
    return p.chars().filter(c -> c=='<').count() == p.chars().filter(c -> c=='>').count();
}

Try / catch

try {
    pattern = matcher.compile(patternText, ruleIndex);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("unterminated tag")) {
        patternText = fixUnescapedDelimiters(patternText);
        pattern = matcher.compile(patternText, ruleIndex);
    } else throw e;
}

Prevention

When it happens

Trigger: Patterns like "<ID + <INT>" (first '<' unclosed), or custom delimiters where an escape sequence was forgotten; also a stop delimiter accidentally written with different characters than configured.

Common situations: Hand-written patterns in tests; patterns built by string concatenation that drop a closing delimiter; languages whose literal text contains the start delimiter (e.g. HTML/XML-like syntaxes with '<'), requiring the escape sequence.

Related errors


AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14). Data as JSON: /api/errors/76628e5362947197. Report an issue: GitHub.