justfile grammar

Justfiles are processed by a mildly context-sensitive tokenizer and a recursive descent parser. The grammar is mostly LL(1), although an extra token of lookahead is used to distinguish between export assignments and recipes with parameters.

tokens

  1. BACKTICK = `[^`\n\r]*`
  2. COMMENT = #([^!].*)?$
  3. DEDENT = emitted when indentation decreases
  4. EOF = emitted at the end of the file
  5. INDENT = emitted when indentation increases
  6. LINE = emitted before a recipe line
  7. NAME = [a-zA-Z_][a-zA-Z0-9_-]*
  8. NEWLINE = \n|\r\n
  9. RAW_STRING = '[^'\r\n]*'
  10. STRING = "[^"]*" # also processes \n \r \t \" \\ escapes
  11. TEXT = recipe text, only matches in a recipe body

grammar syntax

  1. | alternation
  2. () grouping
  3. _? option (0 or 1 times)
  4. _* repetition (0 or more times)
  5. _+ repetition (1 or more times)

grammar

  1. justfile : item* EOF
  2. item : recipe
  3. | alias
  4. | assignment
  5. | export
  6. | eol
  7. eol : NEWLINE
  8. | COMMENT NEWLINE
  9. alias : 'alias' NAME ':=' NAME
  10. assignment : NAME ':=' expression eol
  11. export : 'export' assignment
  12. expression : value '+' expression
  13. | value
  14. value : NAME '(' sequence? ')'
  15. | STRING
  16. | RAW_STRING
  17. | BACKTICK
  18. | NAME
  19. | '(' expression ')'
  20. sequence : expression ',' sequence
  21. | expression ','?
  22. recipe : '@'? NAME parameter* ('+' parameter)? ':' dependencies? body?
  23. parameter : NAME
  24. | NAME '=' value
  25. dependencies : NAME+
  26. body : INDENT line+ DEDENT
  27. line : LINE (TEXT | interpolation)+ NEWLINE
  28. | NEWLINE
  29. interpolation : '{{' expression '}}'