aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/robertkrimen/otto/parser/error.go
blob: e0f74a5cfcd735b79886b225be6f6393cdd71470 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package parser

import (
    "fmt"
    "sort"

    "github.com/robertkrimen/otto/file"
    "github.com/robertkrimen/otto/token"
)

const (
    err_UnexpectedToken      = "Unexpected token %v"
    err_UnexpectedEndOfInput = "Unexpected end of input"
    err_UnexpectedEscape     = "Unexpected escape"
)

//    UnexpectedNumber:  'Unexpected number',
//    UnexpectedString:  'Unexpected string',
//    UnexpectedIdentifier:  'Unexpected identifier',
//    UnexpectedReserved:  'Unexpected reserved word',
//    NewlineAfterThrow:  'Illegal newline after throw',
//    InvalidRegExp: 'Invalid regular expression',
//    UnterminatedRegExp:  'Invalid regular expression: missing /',
//    InvalidLHSInAssignment:  'Invalid left-hand side in assignment',
//    InvalidLHSInForIn:  'Invalid left-hand side in for-in',
//    MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
//    NoCatchOrFinally:  'Missing catch or finally after try',
//    UnknownLabel: 'Undefined label \'%0\'',
//    Redeclaration: '%0 \'%1\' has already been declared',
//    IllegalContinue: 'Illegal continue statement',
//    IllegalBreak: 'Illegal break statement',
//    IllegalReturn: 'Illegal return statement',
//    StrictModeWith:  'Strict mode code may not include a with statement',
//    StrictCatchVariable:  'Catch variable may not be eval or arguments in strict mode',
//    StrictVarName:  'Variable name may not be eval or arguments in strict mode',
//    StrictParamName:  'Parameter name eval or arguments is not allowed in strict mode',
//    StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
//    StrictFunctionName:  'Function name may not be eval or arguments in strict mode',
//    StrictOctalLiteral:  'Octal literals are not allowed in strict mode.',
//    StrictDelete:  'Delete of an unqualified identifier in strict mode.',
//    StrictDuplicateProperty:  'Duplicate data property in object literal not allowed in strict mode',
//    AccessorDataProperty:  'Object literal may not have data and accessor property with the same name',
//    AccessorGetSet:  'Object literal may not have multiple get/set accessors with the same name',
//    StrictLHSAssignment:  'Assignment to eval or arguments is not allowed in strict mode',
//    StrictLHSPostfix:  'Postfix increment/decrement may not have eval or arguments operand in strict mode',
//    StrictLHSPrefix:  'Prefix increment/decrement may not have eval or arguments operand in strict mode',
//    StrictReservedWord:  'Use of future reserved word in strict mode'

// A SyntaxError is a description of an ECMAScript syntax error.

// An Error represents a parsing error. It includes the position where the error occurred and a message/description.
type Error struct {
    Position file.Position
    Message  string
}

// FIXME Should this be "SyntaxError"?

func (self Error) Error() string {
    filename := self.Position.Filename
    if filename == "" {
        filename = "(anonymous)"
    }
    return fmt.Sprintf("%s: Line %d:%d %s",
        filename,
        self.Position.Line,
        self.Position.Column,
        self.Message,
    )
}

func (self *_parser) error(place interface{}, msg string, msgValues ...interface{}) *Error {
    idx := file.Idx(0)
    switch place := place.(type) {
    case int:
        idx = self.idxOf(place)
    case file.Idx:
        if place == 0 {
            idx = self.idxOf(self.chrOffset)
        } else {
            idx = place
        }
    default:
        panic(fmt.Errorf("error(%T, ...)", place))
    }

    position := self.position(idx)
    msg = fmt.Sprintf(msg, msgValues...)
    self.errors.Add(position, msg)
    return self.errors[len(self.errors)-1]
}

func (self *_parser) errorUnexpected(idx file.Idx, chr rune) error {
    if chr == -1 {
        return self.error(idx, err_UnexpectedEndOfInput)
    }
    return self.error(idx, err_UnexpectedToken, token.ILLEGAL)
}

func (self *_parser) errorUnexpectedToken(tkn token.Token) error {
    switch tkn {
    case token.EOF:
        return self.error(file.Idx(0), err_UnexpectedEndOfInput)
    }
    value := tkn.String()
    switch tkn {
    case token.BOOLEAN, token.NULL:
        value = self.literal
    case token.IDENTIFIER:
        return self.error(self.idx, "Unexpected identifier")
    case token.KEYWORD:
        // TODO Might be a future reserved word
        return self.error(self.idx, "Unexpected reserved word")
    case token.NUMBER:
        return self.error(self.idx, "Unexpected number")
    case token.STRING:
        return self.error(self.idx, "Unexpected string")
    }
    return self.error(self.idx, err_UnexpectedToken, value)
}

// ErrorList is a list of *Errors.
//
type ErrorList []*Error

// Add adds an Error with given position and message to an ErrorList.
func (self *ErrorList) Add(position file.Position, msg string) {
    *self = append(*self, &Error{position, msg})
}

// Reset resets an ErrorList to no errors.
func (self *ErrorList) Reset() { *self = (*self)[0:0] }

func (self ErrorList) Len() int      { return len(self) }
func (self ErrorList) Swap(i, j int) { self[i], self[j] = self[j], self[i] }
func (self ErrorList) Less(i, j int) bool {
    x := &self[i].Position
    y := &self[j].Position
    if x.Filename < y.Filename {
        return true
    }
    if x.Filename == y.Filename {
        if x.Line < y.Line {
            return true
        }
        if x.Line == y.Line {
            return x.Column < y.Column
        }
    }
    return false
}

func (self ErrorList) Sort() {
    sort.Sort(self)
}

// Error implements the Error interface.
func (self ErrorList) Error() string {
    switch len(self) {
    case 0:
        return "no errors"
    case 1:
        return self[0].Error()
    }
    return fmt.Sprintf("%s (and %d more errors)", self[0].Error(), len(self)-1)
}

// Err returns an error equivalent to this ErrorList.
// If the list is empty, Err returns nil.
func (self ErrorList) Err() error {
    if len(self) == 0 {
        return nil
    }
    return self
}