error.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package parser
  2. import (
  3. "fmt"
  4. "sort"
  5. "github.com/robertkrimen/otto/file"
  6. "github.com/robertkrimen/otto/token"
  7. )
  8. const (
  9. errUnexpectedToken = "Unexpected token %v"
  10. errUnexpectedEndOfInput = "Unexpected end of input"
  11. )
  12. // UnexpectedNumber: 'Unexpected number',
  13. // UnexpectedString: 'Unexpected string',
  14. // UnexpectedIdentifier: 'Unexpected identifier',
  15. // UnexpectedReserved: 'Unexpected reserved word',
  16. // NewlineAfterThrow: 'Illegal newline after throw',
  17. // InvalidRegExp: 'Invalid regular expression',
  18. // UnterminatedRegExp: 'Invalid regular expression: missing /',
  19. // InvalidLHSInAssignment: 'invalid left-hand side in assignment',
  20. // InvalidLHSInForIn: 'Invalid left-hand side in for-in',
  21. // MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
  22. // NoCatchOrFinally: 'Missing catch or finally after try',
  23. // UnknownLabel: 'Undefined label \'%0\'',
  24. // Redeclaration: '%0 \'%1\' has already been declared',
  25. // IllegalContinue: 'Illegal continue statement',
  26. // IllegalBreak: 'Illegal break statement',
  27. // IllegalReturn: 'Illegal return statement',
  28. // StrictModeWith: 'Strict mode code may not include a with statement',
  29. // StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
  30. // StrictVarName: 'Variable name may not be eval or arguments in strict mode',
  31. // StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
  32. // StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
  33. // StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
  34. // StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
  35. // StrictDelete: 'Delete of an unqualified identifier in strict mode.',
  36. // StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
  37. // AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
  38. // AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
  39. // StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
  40. // StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
  41. // StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
  42. // StrictReservedWord: 'Use of future reserved word in strict mode'
  43. // A SyntaxError is a description of an ECMAScript syntax error.
  44. // An Error represents a parsing error. It includes the position where the error occurred and a message/description.
  45. type Error struct {
  46. Message string
  47. Position file.Position
  48. }
  49. // FIXME Should this be "SyntaxError"?
  50. func (e Error) Error() string {
  51. filename := e.Position.Filename
  52. if filename == "" {
  53. filename = "(anonymous)"
  54. }
  55. return fmt.Sprintf("%s: Line %d:%d %s",
  56. filename,
  57. e.Position.Line,
  58. e.Position.Column,
  59. e.Message,
  60. )
  61. }
  62. func (p *parser) error(place interface{}, msg string, msgValues ...interface{}) {
  63. var idx file.Idx
  64. switch place := place.(type) {
  65. case int:
  66. idx = p.idxOf(place)
  67. case file.Idx:
  68. if place == 0 {
  69. idx = p.idxOf(p.chrOffset)
  70. } else {
  71. idx = place
  72. }
  73. default:
  74. panic(fmt.Errorf("error(%T, ...)", place))
  75. }
  76. position := p.position(idx)
  77. msg = fmt.Sprintf(msg, msgValues...)
  78. p.errors.Add(position, msg)
  79. }
  80. func (p *parser) errorUnexpected(idx file.Idx, chr rune) {
  81. if chr == -1 {
  82. p.error(idx, errUnexpectedEndOfInput)
  83. return
  84. }
  85. p.error(idx, errUnexpectedToken, token.ILLEGAL)
  86. }
  87. func (p *parser) errorUnexpectedToken(tkn token.Token) {
  88. if tkn == token.EOF {
  89. p.error(file.Idx(0), errUnexpectedEndOfInput)
  90. return
  91. }
  92. value := tkn.String()
  93. switch tkn {
  94. case token.BOOLEAN, token.NULL:
  95. p.error(p.idx, errUnexpectedToken, p.literal)
  96. case token.IDENTIFIER:
  97. p.error(p.idx, "Unexpected identifier")
  98. case token.KEYWORD:
  99. // TODO Might be a future reserved word
  100. p.error(p.idx, "Unexpected reserved word")
  101. case token.NUMBER:
  102. p.error(p.idx, "Unexpected number")
  103. case token.STRING:
  104. p.error(p.idx, "Unexpected string")
  105. default:
  106. p.error(p.idx, errUnexpectedToken, value)
  107. }
  108. }
  109. // ErrorList is a list of *Errors.
  110. type ErrorList []*Error //nolint:errname
  111. // Add adds an Error with given position and message to an ErrorList.
  112. func (el *ErrorList) Add(position file.Position, msg string) {
  113. *el = append(*el, &Error{Position: position, Message: msg})
  114. }
  115. // Reset resets an ErrorList to no errors.
  116. func (el *ErrorList) Reset() {
  117. *el = (*el)[0:0]
  118. }
  119. // Len implement sort.Interface.
  120. func (el *ErrorList) Len() int {
  121. return len(*el)
  122. }
  123. // Swap implement sort.Interface.
  124. func (el *ErrorList) Swap(i, j int) {
  125. (*el)[i], (*el)[j] = (*el)[j], (*el)[i]
  126. }
  127. // Less implement sort.Interface.
  128. func (el *ErrorList) Less(i, j int) bool {
  129. x := (*el)[i].Position
  130. y := (*el)[j].Position
  131. if x.Filename < y.Filename {
  132. return true
  133. }
  134. if x.Filename == y.Filename {
  135. if x.Line < y.Line {
  136. return true
  137. }
  138. if x.Line == y.Line {
  139. return x.Column < y.Column
  140. }
  141. }
  142. return false
  143. }
  144. // Sort sorts el.
  145. func (el *ErrorList) Sort() {
  146. sort.Sort(el)
  147. }
  148. // Error implements the Error interface.
  149. func (el *ErrorList) Error() string {
  150. switch len(*el) {
  151. case 0:
  152. return "no errors"
  153. case 1:
  154. return (*el)[0].Error()
  155. default:
  156. return fmt.Sprintf("%s (and %d more errors)", (*el)[0].Error(), len(*el)-1)
  157. }
  158. }
  159. // Err returns an error equivalent to this ErrorList.
  160. // If the list is empty, Err returns nil.
  161. func (el *ErrorList) Err() error {
  162. if len(*el) == 0 {
  163. return nil
  164. }
  165. return el
  166. }