grammar DataMetaUrl
# DataMeta URL definition, a part of a URL definition
include DataMetaCommonsRoot rule dataMetaUri proto:urlProtocol '://' userPwd:userSpec? host:hostName port:portSpec? uTail:urlTail? { def user? !userPwd.text_value.empty? && userPwd.name && !userPwd.name.empty? end def pwd? !userPwd.text_value.empty? && userPwd.password && !userPwd.password.empty? end def port? !port.text_value.empty? end def tail? !uTail.text_value.empty? end def path? !uTail.text_value.empty? && uTail.path end def path uTail.path end def query? !uTail.text_value.empty? && uTail.query end def query uTail.query end } end
# Order is important, if you put “http” in front of the “https”, https match will fail
rule urlProtocol 'https' / 'http' / 'ftp' / 'hdfs' / 'mysql' / 'oracle' end rule urlTail '/' uPath:urlPath? uQuery:urlQuery? { def path uPath.text_value.empty? ? nil : uPath.text_value end def query uQuery.text_value.empty? ? nil : uQuery.query end } end rule urlPath (urlPathChar+) end rule urlPathChar wordChar / '-' / '/' / '.' #!'?' # - this causes infinite loop end rule urlQuery '?' queryText:(notBlanks+) { def query queryText.text_value.empty? ? nil : queryText.text_value end } end rule hostChar wordChar / '-' / '.' end rule hostName hostChar+ end rule portSpec ':' portNumber:(digit+) { def number # port number or nil if none, can not default it here because it depends on the protocol text_value.empty? ? nil : portNumber.text_value.to_i end } end rule notAtSymbol !'@' . end rule pwdSpec ':' pwd:(notAtSymbol+) { def empty? text_value.empty? end } end rule userSpec user:(wordChar+) pwdOpt:pwdSpec? '@' { def name user.text_value.empty? ? nil : user.text_value end def password pwdOpt.text_value.empty? ? nil : pwdOpt.pwd.text_value end } end
end