#lang racket
(provide resolve add-implicit-resolver!)
(define DEFAULT-SCALAR-TAG "tag:yaml.org,2002:str")
(define DEFAULT-SEQUENCE-TAG "tag:yaml.org,2002:seq")
(define DEFAULT-MAPPING-TAG "tag:yaml.org,2002:map")
(define yaml-implicit-resolvers (make-hash))
(define yaml-path-resolvers (make-hash))
(define (resolve kind value implicit)
(call/cc
(λ (return)
(when (and (eq? kind 'scalar)
(car implicit))
(let* ([key (if (equal? "" value) "" (string-ref value 0))]
[resolvers (hash-ref yaml-implicit-resolvers key '())]
[none (hash-ref yaml-implicit-resolvers #f '())])
(for ([p (append resolvers none)])
(match-let ([(cons tag regexp) p])
(when (regexp-match regexp value)
(return tag))))
(set! implicit (cdr implicit))))
(case kind
[(scalar) DEFAULT-SCALAR-TAG]
[(sequence) DEFAULT-SEQUENCE-TAG]
[(mapping) DEFAULT-MAPPING-TAG]
[else #f]))))
(define (add-implicit-resolver! tag regexp first)
(let ([update (λ (v) (append v (list (cons tag regexp))))])
(for ([ch (if (list? first) first '(#f))])
(hash-update! yaml-implicit-resolvers ch update '()))))
(add-implicit-resolver!
"tag:yaml.org,2002:bool"
(regexp
(string-append
"^(?:yes|Yes|YES|no|No|NO"
"|true|True|TRUE|false|False|FALSE"
"|on|On|ON|off|Off|OFF)$"))
(string->list "yYnNtTfFoO"))
(add-implicit-resolver!
"tag:yaml.org,2002:float"
(regexp
(string-append
"^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?"
"|\\.[0-9_]+(?:[eE][-+][0-9]+)?"
"|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*"
"|[-+]?\\.(?:inf|Inf|INF)"
"|\\.(?:nan|NaN|NAN))$"))
(string->list "-+0123456789."))
(add-implicit-resolver!
"tag:yaml.org,2002:int"
(regexp
(string-append
"^(?:[-+]?0b[0-1_]+"
"|[-+]?0[0-7_]+"
"|[-+]?(?:0|[1-9][0-9_]*)"
"|[-+]?0x[0-9a-fA-F_]+"
"|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"))
(string->list "-+0123456789"))
(add-implicit-resolver!
"tag:yaml.org,2002:merge"
(regexp "^(?:<<)$")
(string->list "<"))
(add-implicit-resolver!
"tag:yaml.org,2002:null"
(regexp "^(?:~|null|Null|NULL|)$")
(append (string->list "~nN") (list "")))
(add-implicit-resolver!
"tag:yaml.org,2002:timestamp"
(regexp
(string-append
"^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"
"|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?"
"(?:[Tt]|[ \\t]+)[0-9][0-9]?"
":[0-9][0-9]:[0-9][0-9](?:\\.[0-9]*)?"
"(?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$"))
(string->list "0123456789"))
(add-implicit-resolver!
"tag:yaml.org,2002:value"
(regexp "^(?:=)$")
(string->list "="))
(add-implicit-resolver!
"tag:yaml.org,2002:yaml"
(regexp "^(?:!|&|\\*)$")
(string->list "!&*"))