package parser

import (
	
	

	
	
)

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 ( Error) () string {
	 := .Position.Filename
	if  == "" {
		 = "(anonymous)"
	}
	return fmt.Sprintf("%s: Line %d:%d %s",
		,
		.Position.Line,
		.Position.Column,
		.Message,
	)
}

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

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

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

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

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

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

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

func ( ErrorList) () int      { return len() }
func ( ErrorList) (,  int) { [], [] = [], [] }
func ( ErrorList) (,  int) bool {
	 := &[].Position
	 := &[].Position
	if .Filename < .Filename {
		return true
	}
	if .Filename == .Filename {
		if .Line < .Line {
			return true
		}
		if .Line == .Line {
			return .Column < .Column
		}
	}
	return false
}

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

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

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