VSL - The prelude.locations Structure

# Copyright 2011  Petter Urkedal
#
# This file is part of the Viz Standard Library <http://www.vizlang.org/>.
#
# The Viz Standard Library (VSL) is free software: you can redistribute it
# and/or modify it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# The VSL is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
# more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with the VSL.  If not, see <http://www.gnu.org/licenses/>.

open prereq
open numeric.pervasive
open effect

sealed with

# 0.  References to Parts of Text Files
#
# 0.0.  Locations of Single Lines
#
in lineloc

    type t

    val init_full : string  int  int  t
    val init_bof : string  t
    val dummy : t

    val fpath : t  string
    val line_num : t  int
    val line_pos : t  int

    val skip_line : int  t  t

    val eq : t  t  bool
    val cmp : t  t  torder
    val min : t  t  t
    val max : t  t  t

    val show : t  string

# 0.0.  Locations to Single Characters or Positions
#
in charloc

    type t

    val init_full : string  int  int  int  int  t
    val init_bof : string  t
    val dummy : t

    val line_loc : t  lineloc.t
    val fpath : t  string
    val line_num : t  int
    val line_pos : t  int
    val column_num : t  int
    val char_pos : t  int

    val skip_n : int  t  t
    val skip_zerowidth : t  t
    val skip_Tab : t  t
    val skip_NL : t  t
    val skip_CR : t  t
    val skip_char : char  t  t

    val eq : t  t  bool
    val cmp : t  t  torder
    val min : t  t  t
    val max : t  t  t

    val show : t  string

# 0.0.  Locations of Continuous Text Fragments
#
in textloc

    type t

    val 0'at : charloc.t  t
    val between : charloc.t  charloc.t  t
    val around : list charloc.t  t

    val lower : t  charloc.t
    val upper : t  charloc.t

    val eq : t  t  bool
    val cmp : t  t  torder

    val show : t  string

end
# END OF INTERFACE

let line_origin, column_origin
    be __builtin_effect_run what!
    let origin_opt do libc.getenv "VIZ_LOCATION_ORIGIN"
    taken origin_opt
	at none% be (1, 0)
	at some s
	    taken string.split_on c"," s
	    at [sl; sc;]
		taken int.see sl, int.see sc
		at some l, some c be l, c
		at _, _ be 1, 0
	    at _ be 1, 0

in lineloc

    type t
     inj init_full : string  int  int  t

    let init_bof fp be init_full fp 0 0

    let dummy be init_full "" -1 -1

    let fpath    (init_full fp ln lp) be fp
    let line_num (init_full _  ln _ ) be ln
    let line_pos (init_full _  _  lp) be lp

    let skip_line n
	at init_full fp -1 -1 fail "Cannot skip_line on dummy location."
	at init_full fp ln lp be init_full fp (ln + 1) (lp + n)

    let eq (init_full fpA lnA lpA) (init_full fpB lnB lpB)
	be string.eq fpA fpB  int.eq lnA lnB  int.eq lpA lpB
    let cmp (init_full fpA lnA lpA) (init_full fpB lnB lpB)
	taken string.cmp fpA fpB
	at tcoin% be int.cmp lnA lnB
	at c be c

    let min be min_of_cmp cmp
    let max be max_of_cmp cmp

    let show (init_full fp ln lp)
	be string.cat_list [fp; ":"; int.show (ln + line_origin);]

in charloc

    type t
     inj init : lineloc.t  int  int  t

    let init_full fp ln lp cn cp be init (lineloc.init_full fp ln lp) cn cp

    let init_bof fp be init (lineloc.init_bof fp) 0 0
    let dummy be init lineloc.dummy -1 -1

    let line_loc   (init ll _ _) be ll
    let fpath      (init ll _ _) be lineloc.fpath ll
    let line_num   (init ll _ _) be lineloc.line_num ll
    let line_pos   (init ll _ _) be lineloc.line_pos ll
    let column_num (init _ cn _) be cn
    let char_pos   (init _ _ cp) be cp

    let skip_n n
	at init ll -1 -1 fail "Cannot skip_n on dummy location."
	at init ll cn cp be init ll (cn + n) (cp + n)
    let skip_zerowidth
	at init ll -1 -1 fail "Cannot skip_zerowidth on dummy location."
	at init ll cn cp be init ll cn (cp + 1)
    let skip_Tab
	at init ll -1 -1 fail "Cannot skip_Tab on dummy location."
	at init ll cn cp be init ll (8 * (cn div 8 + 1)) (cp + 1)
    let skip_NL
	at init ll -1 -1 fail "Cannot skip_NL on dummy location."
	at init (lineloc.init_full fp ln lp) cn cp
	    be init (lineloc.init_full fp (ln + 1) (cp + 1)) 0 (cp + 1)
    let skip_CR
	at init ll -1 -1 fail "Cannot skip_CR on dummy location."
	at init ll cn cp be init ll 0 (cp + 1)
    let skip_char
	at c"\t" be skip_Tab
	at c"\n" be skip_NL
	at c"\r" be skip_CR
	# FIXME: Use Unicode properties for the rest when implemented.
	at _ be skip_n 1

    let eq (init llA cnA cpA) (init llB cnB cpB)
	be lineloc.eq llA llB  int.eq cnA cnB  int.eq cpA cpB
    let cmp (init llA cnA cpA) (init llB cnB cpB)
	taken lineloc.cmp llA llB
	at tcoin% be int.cmp cpA cpB
	at c be c

    let min be min_of_cmp cmp
    let max be max_of_cmp cmp

    let show (init ll cn cp)
	be string.cat_list [lineloc.show ll; ",";
			    int.show (cn + column_origin);]

in textloc

    type t := charloc.t × charloc.t

    let dummy be (charloc.dummy, charloc.dummy)

    let 0'at ll be (ll, ll)

    let between lb ub
	if ¬ string.eq (charloc.fpath lb) (charloc.fpath ub)
	    fail "textloc.between expects positions from the same file."
	taken charloc.cmp lb ub
	at tsucc% fail "Arguments to textloc.between must be ordered."
	at _ be (lb, ub)

    let around
	at [] be dummy
	at [ll; lls]
	    let lb be list.fold charloc.min lls ll
	    let ub be list.fold charloc.max lls ll
	    be between lb ub

    let lower (lb, ub) be lb
    let upper (lb, ub) be ub

    let eq (lbA, ubA) (lbB, ubB) be charloc.eq lbA lbB  charloc.eq ubA ubB

    let cmp (lbA, ubA) (lbB, ubB)
	taken charloc.cmp lbA lbB
	at tcoin% be charloc.cmp ubA ubB
	at c be c

    let show (lb, ub)
	if charloc.eq lb ub be charloc.show lb
	if lineloc.eq (charloc.line_loc lb) (charloc.line_loc ub)
	    be string.cat_list
		[charloc.show lb; "-";
		 int.show (charloc.column_num ub + column_origin);]
	else
	    be string.cat_list
		[charloc.show lb; "-";
		 int.show (charloc.line_num ub + line_origin); ",";
		 int.show (charloc.column_num ub + column_origin);]