Skip to content

ends with / starts with operators are swallowed as multi-word identifiers at statement level #566

Description

@logbie

Summary

X ends with "…" and X starts with "…" do not work reliably in a check if
condition at statement level. The parser's multi-word–identifier rule absorbs the
operator keyword, lexing path ends with ".css" as the identifier path ends
followed by with ".css". The program then fails semantic analysis with
Variable 'path ends' is not defined (and analogously for starts).

There is no dedicated lexer token for these operators — the lexer only defines
KeywordContains (src/lexer/token.rs), not ends/starts — so they are not
parsed as operators at all in this position.

Reproduction (release build)

store path as "/style.css"
check if path ends with ".css":
    display "css"
otherwise:
    display "no"
end check
error[ANALYZE-SEMANTIC]: Variable 'path ends' is not defined

Same failure for check if path starts with "/style":Variable 'path starts' is not defined.

contains works correctly as contains of X and Y, and the 3-argument
substring of X and 1 and length of X works; only the starts with / ends with
infix forms are affected.

Why this is easy to miss

Several existing programs contain these forms — e.g.
TestPrograms/comprehensive_web_server_demo.wfl uses both
request_path starts with "/static/" and file_path ends with ".css". They pass
--parse and survive --analyze (which is lenient here), so they look supported,
but they fault under the full pipeline. The forms also appear in user-facing docs.

Impact

  • Prefix/suffix string matching — a very common need, especially for web-server
    request routing — silently breaks or misleads users.
  • Docs and demo programs imply these operators work when they do not end-to-end.

Suggested fix

Give starts with / ends with real operator support — either dedicated
KeywordStartsWith / KeywordEndsWith tokens, or a proper infix parse that binds
before multi-word identifier accumulation — mirroring how contains is handled.
Add TestPrograms covering both operators under the full pipeline so regressions are
caught (the current demo usages only exercise --analyze).

Notes

Found while drafting the route construct design (PR #565), where prefix/suffix
when heads depend on these operators. Context and validated interim workarounds
are documented in Docs/development/route-construct-design.md.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions