Cyclic token precedence

Hello, i get following error when trying to specify token precendence.

Cyclic token precedence relation between
"for", "from", "in", "let", "fn", "if", "else", "try",
"catch", "while", "loop", "break", "continue", "import",
"return", Type, Boolean, Identifier 

My complete grammar attempt looks like this:

@top Program { (Statement ";")* }

@skip { space | LineComment }


Statement {
    LetStmt      |
    ImportStmt   |
    BreakStmt    |
    ContinueStmt |
    ReturnStmt   |
    Expression
}

@precedence {
    Expression @left,
    As @left,
    AssignOp @left,
    InfixOp @left
}

LetStmt         { "let" Identifier "=" Expression }
ImportStmt      { "import" Identifier ("as" Identifier)? "from" Identifier }
BreakStmt       { "break" (Expression)? }
ContinueStmt    { "continue" }
ReturnStmt      { "return" (Expression)? }
Expression {
    Number
    | String
    | Identifier
    | Boolean
    | FnExpr
    | IfExpr
    | ForExpr
    | WhileExpr
    | LoopExpr
    | TryExpr
//    | "null"
    | "(" Expression ")"
    //| PrefixExpr
    | InfixExpr
    //| AssignExpr
    | CastExpr
}


InfixExpr {
    !Expression
    !InfixOp
    !Expression
}

PrefixExpr { ( "+" | "-" | "!" ) Expression }

AssignExpr {
    !Expression
    !AssignOp
    !Expression
}
CastExpr { !Expression !As Type }
FnExpr      { "fn" Identifier "(" (Identifier ("," Identifier)* (",")? )? }
IfExpr      { "if" Expression Block "else" ( Block | IfExpr )}
ForExpr     { "for" Identifier "in" Expression ".." Expression Block}
WhileExpr   { "while" Expression Block }
LoopExpr    { "loop" Block }
TryExpr     { "try" Block "catch" Identifier Block }
Block  { "{" (Statement ";")* "}" }


@tokens {
    @precedence {
        "for",
        "from",
        "in",
        "let",
        "fn",
        "if",
        "else",
        "try",
        "catch",
        "for",
        "while",
        "loop",
        "break",
        "continue",
        "import",
        "return",
        Type,
        Boolean,
        Identifier
    }

    Boolean { "true" | "false" | "on" | "off" }
    Identifier {
        (@asciiLetter) + (@asciiLetter|@digit|"_")*
    }
    String {
        "'" "a" "'"
    }
    Number  { @digit+ }

    'import'
    As {'as'}
    'from'
    'in'
    'let'
    'fn'
    'if'
    'else'
    'try'
    'catch'
    'for'
    'while'
    'loop'
    'break'
    'continue'
    'return'

    Type { "str" | "num" | "bool" | "null" }

    InfixOp {
        '+'
        | '-'
        | '*'
        | '/'
        | '% '
        | '**'
        | '||'
        | '&&'
        | '!='
        | '=='
        | '<'
        | '<='
        | '>'
        | '>='
    }

    AssignOp {
         '='
        | '+='
        | '-='
        | '*='
        | '/='
        | '**='
        | '%='
    }

    '(' ')'
    '{' '}'
    ';' ','
    '.' '..'
    '=>'
    '||' '&&'
    '=='  '!=' '!'
    '+' '-' '*' '/' '**' '%'
    '<' '<='
    '>' '>='

  LineComment { '#' ![\n]* }
  space { $[ \t\n\r]+ }
}

Your token precedence list has "for" twice.

You really don’t want to use plain strings like this for keywords, since it will cause identifiers that start with the keyword (say, forever) to be tokenized as first the keyword and then the rest of the identifier. Use @specialize instead.

Okay.
Thank you very much.
I’ve used your Treesitter to Lezer generator tool and now have a working grammar :slightly_smiling_face: