Skip to content

Parser upcases all symbols, so case-distinct function symbols collapse (e.g. T and t become the same symbol) #21

Description

@moratori

Summary

The MKBTT/TRS parser interns every symbol after applying string-upcase. As a result, function symbols that differ only in letter case (e.g. T and t) are folded into a single symbol. Inputs that rely on case to distinguish function symbols are silently mis-parsed, and completion can report a "success" for a degenerate system that is not the one given.

This is not caused by the Common Lisp reader's default case conversion; it is an explicit string-upcase call in the parser.

Facts

1. All parsed symbols (function symbols, constants, variables) are interned through a single helper that upcases the name.

src/parser.lisp:30-33

(defun %intern-symbol-to-specified-package (string)
  (intern
    (string-upcase string)
    *parsed-symbol-intern-package*))

2. The lexer itself preserves case.

The MKBTT rules lexer accepts both cases as a single token class, so the original case is present in the token string and is only lost at intern time.

src/parser.lisp:108-112 (mkbtt-rules-lexer)

("[a-zA-Z0-9_%+%*%.%-/@&\\]+" (values :rules-symbol $$))

3. The printer additionally lowercases names on output, which hides the collapse.

  • src/types.lisp:179 — variable: (string-downcase (symbol-name ...))
  • src/types.lisp:197-198 — fterm: 0-arity printed with string-upcase, application printed with string-downcase
  • src/types.lisp:260 — predicate: (string-downcase (symbol-name ...))

So source T -> interned |T| -> printed t and source t -> interned |T| -> printed t: both render as t.

4. Empirical reproduction.

Using tests/resources/eq_systems/Sim91_sims2.trs, whose source uses 6 function symbols (T t S s R r):

(let ((eqs (clover.parser:parse-mkbtt-expression <Sim91_sims2 source>)))
  (multiple-value-bind (consts funs) (clover.multicompletion::collect-symbol eqs)
    (print funs)))                       ; => (R T S)  ;
  • Collected function symbols: (R T S) — 3 instead of 6.
  • The first two rules T(t(x)) -> x and t(T(x)) -> x both become the same rule t(t(x)) = x (i.e. duplicates).
  • Completion then reports success with a trivial system (x) => x), which is **not** a completion of the intended Sim91_sims2`.

5. Blast radius in the bundled JAIST completion corpus.

4 of 115 files use function symbols that collide under upcasing:

File Colliding symbols
ASK93_5.trs A/a, E/e, H/h, Q/q, W/w
LS94_G1.trs A/a, B/b, C/c
LS94_P1.trs R/r, S/s, T/t
Sim91_sims2.trs R/r, S/s, T/t

These are group/monoid presentations where the uppercaseenerator (e.g. T = t^-1); the presence of both T(t(x))-> x and t(T(x)) -> x confirms the two are intended t

Impact

  • Any input that distinguishes function symbols by case is mis-parsed.
  • Completion may report a spurious "success" for a collahe affected inputs are not trustworthy.

Notes / possible directions (not yet decided)

  • Primary locus is the string-upcase in %intern-symbo/parser.lisp:30). Preserving case there would require acoordinated change to the printer (src/types.lisp:179,it of:
    • hardcoded literal interns such as "NIL" / "CONS" (src/parser.lisp:193,197-198,306,310-311),
    • the premise/conseq grammars where case is used at the lexer level to classify [A-Z]+ as constants vs [a-z]+ as symbols,
    • any symbol-name comparisons that assume upper case.
  • Alternatively, case-insensitivity could be documented as an intentional limitation, in which case the affected inputs should be marked out of scope.
  • Suggested regression tests: parse->print->parse round-trip stability, and an assertion that T and t parse to distinct symbols.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions