; Copyright Glen Knowles 2016 - 2018.
; Distributed under the Boost Software License, Version 1.0.
;
; json.abnf - dim json
;
; rules to parse json
%root = JSON-text
%api.prefix = Json
%api.namespace = Dim::Detail
%api.parser.file.h = jsonparseint.h
%api.base.file.h = jsonparsebaseint.h

; JSON Grammar
JSON-text = ws value ws
begin-array = ws "[" ws
begin-object = ws "{" ws
end-array = ws "]" ws
end-object = ws "}" ws
name-separator = ws ":" ws
value-separator = ws "," ws
ws = *(WSP / CR / LF / comment)
comment = single-line-comment / multiline-comment
single-line-comment = "//" *Char-not-CR-LF (CR / LF)
multiline-comment = "/*" *(Char-not-BLOT / 1*"*" Char-not-BLOT-SLASH) 1*"*" "/"

; Characters
mbchar = %s"Z" { MinRules }
mbchar = ; multibyte utf-8 characters
    ; 2 byte: 0080-07ff
    (%xc2-df %x80-bf)                       ; 0080 - 07ff
    ; 3 byte: 0800 - d7ff
    / (%xe0 %xa0-bf %x80-bf)                ; 0800 - 0fff
        / (%xe1-ec %x80-bf %x80-bf)         ; 1000 - cfff
        / (%xed %x80-9f %x80-bf)            ; d000 - d7ff
    ; 3 byte: e000 - ffff
    / (%xee-ef %x80-bf %x80-bf)             ; e000 - ffff
    ; 4 byte: 01'0000 - 10'ffff
    / (%xf0 %x90-bf %x80-bf %x80-bf)        ; 01'0000 - 03'ffff
        / (%xf1-f3 %x80-bf %x80-bf %x80-bf) ; 04'0000 - 0f'ffff
        / (%xf4 %x80-8f %x80-bf %x80-bf)    ; 10'0000 - 10'ffff
    { NoMinRules }

Char = WSP / CR / LF / %x20-7f / mbchar
Char-not-CR-LF = WSP / %x20-7f / mbchar
Char-not-BLOT = WSP / %x20-29 / %x2b-7f / mbchar
Char-not-BLOT-SLASH = WSP / %x20-29 / %x2b-2e / %x30-7f / mbchar

; Values
value = false / null / true / object / array / nval / sval
false = %s"false" { End }
null = %s"null" { End }
true = %s"true" { End }
nval = number { End }
sval = string { End }

; Objects
object = begin-object object-tail { Start, End }
object-tail = [ member *(value-separator member) ] end-object { Function }
member = member-name name-separator value
member-name = string { End }

; Arrays
array = begin-array array-tail { Start, End }
array-tail = [ value *(value-separator value) ] end-array { Function }

; Numbers
number = int [frac] [exp]
decimal-point = "."
digit1-9 = %x31-39 ; 1-9
e = "e" ; e E
exp = e [exp-minus / exp-plus] exp-num
exp-minus = "-" { End }
exp-plus = "+"
exp-num = 1*DIGIT { Char+ }
frac = decimal-point frac-num
frac-num = 1*DIGIT { Char+ }
int = [int-minus] int-num
int-minus = "-" { End }
int-num = zero / digit1-9 *DIGIT { Char+ }
zero = "0"

; Strings
string = DQUOTE str-text DQUOTE
str-text = *char { Start+ }
char = unescaped / escape-single / escape-number
escape-single = escape (e-dquote / e-bslash / e-slash / e-bksp / e-feed
    / e-nl / e-cr / e-tab)
e-dquote = DQUOTE { End } ; "
e-bslash = "\" { End }
e-slash = "/" { End }
e-bksp = "b" { End }
e-feed = "f" { End }
e-nl = "n" { End }
e-cr = "r" { End }
e-tab = "t" { End }
escape-number = escape %x75 escape-num-hex { End }
escape-num-hex = 4HEXDIG { Char+ }
escape = %x5c ; \
unescaped = %x20-21 / %x23-2e / %x30-5b / %x5d-7f / mbchar { Char+ }
