//
// Copyright (c) 2022, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 11 Aug 22 Brian Frank Creation
//
**
** FileLoc is a location within a text file or source string.
** It includes an optional one-base line number and column number.
** This class provides a standardized API for text based tools which
** need to report the line/column numbers of errors.
**
@Js
const class FileLoc
{
** Constant for an unknown location
static const FileLoc unknown := make("unknown", 0)
** Constant for tool input location
static const FileLoc inputs := make("inputs", 0)
** Constant for synthetic location
static const FileLoc synthetic := make("synthetic", 0)
** Constructor for file
static new makeFile(File file, Int line := 0, Int col := 0)
{
uri := file.uri
name := uri.scheme == "fan" ? "$uri.host::$uri.pathStr" : file.pathStr
return make(name, line, col)
}
** Constructor for filename string
new make(Str file, Int line := 0, Int col := 0)
{
this.file = file
this.line = line
this.col = col
}
** Parse location formatted from `toStr`
@NoDoc static FileLoc parse(Str s)
{
// by convention this should be called fromStr but that
// conflicts with the make(Str) constructor - so just leave
// as nodoc backdoor hook
file := s
line := 0
col := 0
if (s.endsWith(")"))
{
open := s.indexr("(")
if (open != null)
{
file = s[0..<open]
comma := s.index(",", open+2)
if (comma == null)
{
line = s[open+1..-2].trim.toInt(10, false) ?: 0
}
else
{
line = s[open+1..<comma].trim.toInt(10, false) ?: 0
col = s[comma+1..-2].trim.toInt(10, false) ?: 0
}
}
}
return make(file, line, col)
}
** Filename location
const Str file
** One based line number or zero if unknown
const Int line
** One based line column number or zero if unknown
const Int col
** Is this the unknown location
Bool isUnknown() { this === unknown }
** Hash code
override Int hash()
{
file.hash.xor(line.hash).xor(col.hash.shiftl(17))
}
** Equality operator
override Bool equals(Obj? that)
{
x := that as FileLoc
if (x == null) return false
return file == x.file && line == x.line && col == x.col
}
** Comparison operator
override Int compare(Obj that)
{
x := (FileLoc)that
if (file != x.file) return file <=> x.file
if (line != x.line) return line <=> x.line
return col <=> x.col
}
** Return string representation as "file", "file(line)", or "file(line,col)".
** This is the standard format used by the Fantom compiler.
override Str toStr()
{
if (line <= 0) return file
if (col <= 0) return "$file($line)"
return "$file($line,$col)"
}
}
**************************************************************************
** FileLocErr
**************************************************************************
**
** Exception with a file location
**
@Js
const class FileLocErr : Err
{
** Constructor with message, location, and optional cause
new make(Str msg, FileLoc loc, Err? cause := null) : super(msg, cause)
{
this.loc = loc
}
** File location
const FileLoc loc
** Return "loc: msg"
override Str toStr()
{
if (loc.isUnknown) return super.toStr
return "$loc.toStr: $msg"
}
}