###
Basic structures used by compiler, diagnostics etc
Follows the interfaces specified in the language-server-protocol
###

const DOCMAP = new WeakMap

export class Position
	prop line # zero based line position
	prop character # zero based offset on line
	prop offset # zero based offset in whole document

	def constructor l,c,o,v = null
		line = l
		character = c
		offset = o
		#version = v

	def toString
		"{line}:{character}"

	def valueOf
		offset

###
A range in a text document expressed as (zero-based) start and end positions. A range is comparable to a selection in an editor. Therefore the end position is exclusive. If you want to specify a range that contains a line including the line ending character(s) then use an end position denoting the start of the next line.
###
export class Range
	prop start
	prop end

	def constructor start, end
		self.start = start
		self.end = end

	get offset
		start.offset

	get length
		end.offset - start.offset

	get ['0']
		start.offset

	get ['1']
		end.offset

	def getText str
		str.slice(start,end)

	def equals other
		other.offset == offset and other.length == length

export const DiagnosticSeverity = {
	Error: 1
	Warning: 2
	Information: 3
	Hint: 4
	error: 1
	warning: 2
	warn: 2
	info: 3
	hint: 4
}

export class Diagnostic

	def constructor data,doc = null
		self.range = data.range
		self.severity = DiagnosticSeverity[data.severity] or data.severity
		self.code = data.code
		self.source	= data.source
		self.message = data.message
		DOCMAP.set(self,doc)

	get #source
		DOCMAP.get(self)

	get #lineText
		#source.doc.getLineText(range.start.line)

	def toSnippet
		let start = range.start
		let end = range.end
		let msg = "{#source.sourcePath}:{start.line + 1}:{start.character + 1}: {message}"
		let line = #source.doc.getLineText(start.line)
		let stack = [msg,line]
		stack.push line.replace(/[^\t]/g,' ').slice(0,start.character) + "^".repeat(end.character - start.character)
		return stack.join('\n').replace(/\t/g,'    ') + "\n"

	def toError
		let start = range.start
		let end = range.end
		let msg = "{#source.sourcePath}:{start.line + 1}:{start.character + 1}: {message}"
		let err = new SyntaxError(msg)
		let line = #source.doc.getLineText(start.line)
		let stack = [msg,line]
		stack.push line.replace(/[^\t]/g,' ').slice(0,start.character) + "^".repeat(end.character - start.character)
		err.stack = "\n" + stack.join('\n').replace(/\t/g,'    ') + "\n"
		return err

	def raise
		throw toError!