diff --git a/pfftt.bnf b/pfftt.bnf new file mode 100644 index 0000000..a349ccf --- /dev/null +++ b/pfftt.bnf @@ -0,0 +1,154 @@ +; A grammar for the Procedure interchange Format For Transferring Techniques. +; This format is carefully defined to simplify parsing. Whitespace only +; appears when defined. +; +; This is written in the style of a Backus–Naur Form with a few augmentations. +; When specified, character classes are in the style of those accepted by +; regular expressions, such as [a-z]. Explicitly required characters such as +; spaces are marked with [ ]; a [.] represents a period and not any character. +; Otherwise special characters in regular expressions are not shown escaped. +; +; The convention adopted here is that names that represent actual types in the +; parser are in Proper Case whereas other definitions (often +; representing variants in enumerations in the implementation) are written in +; snake_case. + +NEWLINE := "\n" | "\r\n" + +; A single space character is the separator between fields +SPACE := " " + +; Specially defined as any characters but matching lazily, such that whatever +; token or pattern that follows is excluded. +ANY + +; A PFFTT file is a series of record lines. + +File := Record* + +Record := + Timestamp + SPACE + RunId + SPACE + Path + SPACE + State + NEWLINE + +; ISO 8601 timestamp +Timestamp := year '-' month '-' day 'T' hour ':' minute ':' second ('.' fraction)? 'Z' + +year := [12][0-9][0-9][0-9] +month := [0-1][0-9] +day := [0-9][0-9] + +hour := [0-2][0-9] +minute := [0-5][0-9] +second := [0-5][0-9] + +; Optional fractions of a second can be to arbitrary precision, but in +; practice this is either milliseconds (three digits) or nanoseconds (nine +; digits). +fraction := [0-9]* + +Identifier := [a-z][a-z0-9_]* + +uri := ("https://" | "file:///") [a-zA-Z0-9.,?&#%=:/+-~_]+ + +; the "fully qualified" path of a step. There are implicit nodes (when no +; top-level procedure is defined, for example, and for the case where actions +; are defined in the description of a procedure). The following are all valid +; paths: +; +; / +; /2 +; /2/a/-1 +; /local_network: +; /local_network:2 +; /local_network:2/a/-1 + +Path := "/" procedure? ( component ( "/" component )* )? + +procedure := Identifier ":" + +component := section | step | substep | subsubstep | attribute + +section := [IVX]+ + +step := dependent_step | parallel_step +dependent_step := [1-9][0-9]* +parallel_step := [-]([0-9]|[1-9][0-9]) + +substep := dependent_substep | parallel_substep +dependent_substep := [a-hj-km-uwyz] +parallel_substep := [-]([0-9]|[1-9][0-9]) + +subsubstep := dependent_subsubstep | parallel_subsubstep +dependent_subsubstep := [ivxl]+ +parallel_subsubstep := [-]([0-9]|[1-9][0-9]) + +attribute := role_attribute | place_attribute +role_attribute := "@" Identifier | "@*" +place_attribute := "^" Identifier | "^*" + +; Activity verbs and payloads, collectively the event being observed. Done is +; the most important, recording an outcome of a step. Begin marks the start +; of work on a step (paired with the eventual Done/Skip/Fail); duration is +; derived from the pair. Invoke marks dispatch from the current procedure +; into another (the return is implicit — the next event's Path reveals the +; resumed procedure). Execute records a function call out to the host +; environment. + +State := + "Start" SPACE uri | + "Stop" | + "Resume" | + "Finish" | + "Invoke" SPACE invocable | + "Execute" SPACE executable | + "Return" SPACE Value | + "Input" SPACE supplied | + "Begin" | + "Done" SPACE Value | + "Skip" | + "Fail" (SPACE Value)? + +RunId := [0-9]+ + +invocable := procedure | uri + +executable := Identifier "()" + +; The values supplied to a procedure as parameters. Each value is shown +; bound to its parameter name with `~` if one was declared, otherwise is +; left bare when the parameter is unnamed. +supplied := "(" ( " " binding ( ", " binding )* " " )? ")" +binding := Value ( " ~ " Identifier )? + +Value := unit | literal | numeric | list | tuple | tablet + +unit := "()" + +; A string literal — the form a chosen response or any text value records as. +; Backslash escapes keep a value on a single record line: \" for a quote, \\ +; for a backslash, and \n / \r for the line breaks of a multi-line value. +literal := "\"" literal_char* "\"" +literal_char := [^"\\] | "\\" ("\"" | "\\" | "n" | "r") + +; An integer or a Quantity, written exactly as the Technique language number +; literal it came from (integral and Quantity are defined in technique.bnf). +numeric := integral | Quantity + +; An inline, comma-separated list of values. The empty list is "[]". +list := "[]" | "[ " Value ( ", " Value )* " ]" + +; An inline, comma-separated tuple of values. +tuple := "( " Value ( ", " Value )* " )" + +; A tablet: a series of "label" = value pairs, matching the Technique language +; (the label is quoted). The empty tablet is "[=]", which distinguishes it from +; the empty list. A bracketed value is a tablet when it carries a top-level +; " = " and a list otherwise. Tablets, lists, and their values nest arbitrarily. +tablet := "[=]" | "[ " pair ( ", " pair )* " ]" +pair := "\"" literal_char* "\"" " = " Value diff --git a/technique.bnf b/technique.bnf index da95e4f..133f7f0 100644 --- a/technique.bnf +++ b/technique.bnf @@ -100,7 +100,7 @@ Invocation := "<" invocation_target ">" ("(" arguments? ")")? invocation_target := local_target | external_target local_target := Identifier -external_target := "https://" [a-zA-Z0-9.,?&#%=:/-_]+ +external_target := ("https" | "http" | "file") ":" [a-zA-Z0-9.,?&#%=:/-_]+ ; A function call, usually to a built-in. Application := function_name "(" arguments? ")"