%% Note: this SDF grammar is no longer used in the Nix expression
%% parser and may not be up to date.

definition


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Top level syntax.

module Main
imports Nix-Exprs Nix-Layout


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Expressions.

module Nix-Exprs
imports Nix-Lexicals
exports
  sorts Expr Formal Bind ExprList
  context-free start-symbols Expr
  context-free syntax

    Id -> Expr {cons("Var")}
    Int -> Expr {cons("Int")}
    Str -> Expr {cons("Str")}
    Uri -> Expr {cons("Uri")}
    Path -> Expr {cons("Path")}

    "(" Expr ")" -> Expr {bracket}

    Expr Expr -> Expr {cons("Call"), left}

    Id ":" Expr -> Expr {cons("Function1")}
    "{" {Formal ","}* "}" ":" Expr -> Expr {cons("Function")}
    Id -> Formal {cons("NoDefFormal")}
    Id "?" Expr -> Formal {cons("DefFormal")}

    "assert" Expr ";" Expr -> Expr {cons("Assert")}

    "with" Expr ";" Expr -> Expr {cons("With")}

    "rec" "{" Bind* "}" -> Expr {cons("Rec")}
    "let" Bind* "in" Expr -> Expr {cons("Let")}
    "let" "{" Bind* "}" -> Expr {cons("LetRec")}
    "{" Bind* "}" -> Expr {cons("Attrs")}

    Id "=" Expr ";" -> Bind {cons("Bind")}
    "inherit" ("(" Expr ")")? Id* ";" -> Bind {cons("Inherit")}

    "[" ExprList "]" -> Expr {cons("List")}
    -> ExprList {cons("ExprNil")}
    Expr ExprList -> ExprList {cons("ExprCons")}

    Expr "." Id -> Expr {cons("Select")}

    "if" Expr "then" Expr "else" Expr -> Expr {cons("If")}

    Expr "==" Expr -> Expr {cons("OpEq"), non-assoc}
    Expr "!=" Expr -> Expr {cons("OpNEq"), non-assoc}

    "!" Expr -> Expr {cons("OpNot")}
    Expr "&&" Expr -> Expr {cons("OpAnd"), right}
    Expr "||" Expr -> Expr {cons("OpOr"), right}
    Expr "->" Expr -> Expr {cons("OpImpl"), right}

    Expr "//" Expr -> Expr {cons("OpUpdate"), right}
    Expr "~" Expr -> Expr {cons("SubPath"), non-assoc}
    Expr "?" Id -> Expr {cons("OpHasAttr")}
    Expr "+" Expr -> Expr {cons("OpPlus"), left}
    Expr "++" Expr -> Expr {cons("OpConcat"), right}

  context-free priorities

    Expr "." Id -> Expr
  > Expr ExprList -> ExprList
  > Expr Expr -> Expr
  > Expr "~" Expr -> Expr
  > Expr "?" Id -> Expr
  > Expr "++" Expr -> Expr
  > Expr "+" Expr -> Expr
  > "!" Expr -> Expr
  > Expr "//" Expr -> Expr
  > { Expr "==" Expr -> Expr
      Expr "!=" Expr -> Expr
    }
  > Expr "&&" Expr -> Expr
  > Expr "||" Expr -> Expr
  > Expr "->" Expr -> Expr
  > "if" Expr "then" Expr "else" Expr -> Expr
  > "assert" Expr ";" Expr -> Expr
  > "with" Expr ";" Expr -> Expr
  > Id ":" Expr -> Expr
  > "{" {Formal ","}* "}" ":" Expr -> Expr


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Lexical syntax.

module Nix-Lexicals
exports
  sorts Id Int Str Path Uri
  lexical syntax
    [a-zA-Z\_][a-zA-Z0-9\_\']* -> Id
    "rec" | "let" | "if" | "then" | "else" | "assert" | "with" | "inherit" -> Id {reject}

    [0-9]+ -> Int

    "\"" (~[\"\\] | ("\\" ~[]) )* "\"" -> Str
    "''" (~[\"\\] | ("\\" ~[]) )* "''" -> Str

    [a-zA-Z0-9\.\_\-\+]* ("/"[a-zA-Z0-9\.\_\-\+]+)+ -> Path

    [a-zA-Z] [a-zA-Z0-9\+\-\.]* ":" [a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+ -> Uri

  lexical restrictions
    Id -/- [a-zA-Z0-9\_\']
    Int -/- [0-9]
    Path -/- [a-zA-Z0-9\.\_\-\+\/]
    Uri -/- [a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']
    "rec" "let" "if" "then" "else" "assert" "with" "inherit" -/- [A-Za-z0-9\_\']


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Layout.

module Nix-Layout
exports
  sorts HashComment Asterisk Comment
  lexical syntax
    [\ \t\n] -> LAYOUT
    HashComment -> LAYOUT
    Comment -> LAYOUT
    "#" ~[\n]* -> HashComment
    "/*" ( ~[\*] | Asterisk )* "*/" -> Comment
    [\*] ~[\/] -> Asterisk
  lexical restrictions
    HashComment -/- ~[\n]
  context-free restrictions
    LAYOUT? -/- [\ \t\n\#]
    LAYOUT? -/- [\/].[\*]