/*
*  Error definitions for the LibreSignage markup transpiler.
*/

module.exports.ECODES = {
	'EEOL': {
		code: 0,
		msg: 'Unexpected End Of File'
	},
	'ETOK': {
		code: 1,
		msg: 'Unexpected token'
	},
	'ESYN': {
		code: 2,
		msg: 'Invalid syntax'
	},
	'EEXP': {
		code: 3,
		msg: 'Invalid expression'
	},
	'ETAG': {
		code: 4,
		msg: 'Unknown tag'
	},
	'ETYPE': {
		code: 5,
		msg: 'Type error'
	},
	'EARG': {
		code: 6,
		msg: 'Argument error'
	},
	'EVAL': {
		code: 7,
		msg: 'Value error'
	}
};

module.exports.MarkupError = class MarkupError extends Error {};

module.exports.MarkupSyntaxError =
	class MarkupSyntaxError
	extends module.exports.MarkupError {
	/*
	*  Markup syntax error class.
	*
	*  'code' is one of the error code names in the ECODES object.
	*  'lexeme' is the lexeme where the syntax error occured.
	*  'message' is a human-readable error message.
	*  'file' and 'line' are arguments passed to the Error constructor.
	*/
	constructor(code, lexeme, message, file, line) {
		super(message, file, line);
		if (Error.captureStackTrace) {
			Error.captureStackTrace(this, MarkupSyntaxError);
		}

		let ecodes = module.exports.ECODES;
		this.code = ecodes[code];
		this.message = message;
		this.lexeme = lexeme;
	}

	line() { return this.lexeme.ln_num; } // Get error line num.
	char() { return this.lexeme.ln_pos; } // Get error char pos.

	toString(ln_base) {
		let base = (!ln_base) ? 0: ln_base;
		let ret = `${this.code.msg}: ${this.message}`;

		if (this.lexeme) {
			ret += ` (@ ${base + this.lexeme.ln_num}:` +
					`${this.lexeme.ln_pos})`;
		}
		return ret;
	}
}

module.exports.LexerError =
	class LexerError
	extends module.exports.MarkupError {
	/*
	*  Lexer error class.
	*
	*  'code' is one of the error codes in the ECODES object.
	*  'message' is a message string.
	*  'ln_num' is the line number where the error occured.
	*  'ln_pos' is the line position where the error occured.
	*  'file' is passed to the Error constructor.
	*/
	constructor(code, message, ln_num, ln_pos, file) {
		super(message, file, ln_num);
		if (Error.captureStackTrace) {
			Error.captureStackTrace(this, LexerError);
		}

		let ecodes = module.exports.ECODES;
		this.code = ecodes[code];
		this.ln_num = ln_num;
		this.ln_pos = ln_pos;
		this.message = message;
	}

	toString(ln_base) {
		let base = (!ln_base) ? 0 : ln_base;
		let ret =  `${this.code.msg}: ${this.message}`;
		if (this.ln_num != null && this.ln_pos != null) {
			ret += ` (@ ${base + this.ln_num}:${this.ln_pos})`;
		}
		return ret;
	}
}
