urn.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package urn
  2. import (
  3. "strconv"
  4. "github.com/antlr/antlr4/runtime/Go/antlr"
  5. "github.com/leodido/go-urn/grammar"
  6. )
  7. // URN represents an Uniform Resource Name.
  8. //
  9. // The general form represented is:
  10. //
  11. // urn:<id>:<ss>
  12. //
  13. // Details at https://tools.ietf.org/html/rfc2141
  14. type URN struct {
  15. ID string // Namespace identifier
  16. SS string // Namespace specific string
  17. tree string
  18. }
  19. // Error describes an error and the input that caused it.
  20. type Error struct {
  21. Source string
  22. Column int
  23. Detail string
  24. }
  25. func (e *Error) Error() string {
  26. return "\"" + e.Source + "\" causes syntax error at character " + strconv.Itoa(e.Column) + ", " + e.Detail
  27. }
  28. type errorListener struct {
  29. *antlr.DefaultErrorListener
  30. input string
  31. }
  32. func (l *errorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
  33. panic(&Error{
  34. Source: l.input,
  35. Column: column,
  36. Detail: msg,
  37. })
  38. }
  39. // Parse is ...
  40. func Parse(u string) (*URN, error) {
  41. urn, err := parse(u)
  42. if err != nil {
  43. return nil, err
  44. }
  45. return urn, err
  46. }
  47. func parse(u string) (urn *URN, err error) {
  48. errl := new(errorListener)
  49. errl.DefaultErrorListener = new(antlr.DefaultErrorListener)
  50. errl.input = u
  51. stream := antlr.NewInputStream(u)
  52. lexer := grammar.NewUrnLexer(stream)
  53. tokens := antlr.NewCommonTokenStream(lexer, 0)
  54. parser := grammar.NewUrnParser(tokens)
  55. parser.RemoveErrorListeners()
  56. parser.AddErrorListener(errl)
  57. // parser.BuildParseTrees = false // (todo) > ?
  58. defer func() {
  59. if r := recover(); r != nil {
  60. urn = nil
  61. err = r.(error)
  62. }
  63. }()
  64. urn = &URN{}
  65. parser.AddParseListener(NewListener(urn))
  66. parser.Urn()
  67. return
  68. }
  69. // String reassembles the URN into a valid URN string.
  70. //
  71. // This requires both ID and SS fields to be non-empty.
  72. // Otherwise it returns an empty string.
  73. func (u *URN) String() string {
  74. var res string
  75. if u.ID != "" && u.SS != "" {
  76. res = "urn:" + u.ID + ":" + u.SS
  77. }
  78. return res
  79. }
  80. // Tree returns a string representation of the resulting concrete syntax tree.
  81. func (u *URN) Tree() string {
  82. return u.tree
  83. }