Module: dfmc-reader Synopsis: Range source locations Author: Keith Playford Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND // TODO: PERFORMANCE: We can almost certainly save a slot in many source // locations by having a special representation of a small, single-line // range - e.g. for a short name, or a bit of single-character puntuation. //// Range location source offsets. // Small line/column numbers are encoded with shifts and masks into an // integer. I'd expect 99.9% of source locations to fit into this // compressed representation. A real object is created if the numbers // overflow this rep. define constant = ; define constant $column-bits :: = 12; define constant $column-max :: = 2 ^ $column-bits - 1; define constant $column-mask :: = $column-max; define constant $line-bits :: = 16; define constant $line-max :: = 2 ^ $line-bits - 1; define constant $line-mask :: = ash($line-max, $column-bits); define inline function small-source-offset? (line :: , column :: ) => (small? :: ) column <= $column-max & line <= $line-max end function; define inline function make-small-source-offset (char :: , line :: , column :: ) logior(ash(line, $column-bits), column); end function; // These method are sideways because of the integer packed representation. define inline sealed sideways method source-offset-line (loc :: ) => (line :: ) ash(logand(loc, $line-mask), -$column-bits); end method; define inline sealed sideways method source-offset-column (loc :: ) => (line :: ) logand(loc, $column-mask) end method; define class () constant slot source-offset-line :: , required-init-keyword: line:; constant slot source-offset-column :: , required-init-keyword: column:; end class; define compiler-sideways sealed domain make (subclass()); define compiler-sideways sealed domain initialize (); define sealed method \< (x :: , y :: ) => (well? :: ) // if the line of big offset is same as line of small offset, then the // column of the big offset must be larger than a maximum small offset // column, so don't need to check the equal line case. source-offset-line(x) < source-offset-line(y) end; define sealed method \= (x :: , y :: ) => (well? :: singleton(#f)) #f end; define sealed method \< (x :: , y :: ) => (well? :: ) // if the line of big offset is same as line of small offset, then the // column of the big offset must be larger than a maximum small offset // column, so don't need to check the equal line case. source-offset-line(x) <= source-offset-line(y) end; define sealed method \= (x :: , y :: ) => (well? :: singleton(#f)) #f end; define sealed method \< (x :: , y :: ) => (well? :: ) let x-line = source-offset-line(x); let y-line = source-offset-line(y); x-line < y-line | (x-line == y-line & source-offset-column(x) < source-offset-column(y)) end; define sealed method \= (x :: , y :: ) => (well? :: ) source-offset-line(x) == source-offset-line(y) & source-offset-column(x) == source-offset-column(y) end; // Note that < and = on integers has the right behavior for both arguments // being 's. define constant = type-union(, ); define method range-source-offset-greater-than? (x :: , y :: ) => (well? :: ) // TODO: compare source-offset-character source-offset-line(x) > source-offset-line(y) | (source-offset-line(x) = source-offset-line(y) & source-offset-column(x) > source-offset-column(y)) end method; define function make-big-source-offset (char :: , line :: , column :: ) => (offset :: ) ignore(char); make(, line: line, column: column); end function; // Install as the default. define inline sealed sideways method make-source-offset (char :: , line :: , column :: ) => (offset :: ) if (small-source-offset?(line, column)) make-small-source-offset(char, line, column); else make-big-source-offset(char, line, column); end; end method; //// Range positions define class () constant slot source-position-start-offset, required-init-keyword: start-offset:; constant slot source-position-end-offset, required-init-keyword: end-offset:; end class; define sealed domain make (subclass()); define sealed domain initialize (); define constant = ; define constant range$v-start-col :: = 0; define constant range$s-start-col :: = 7; define constant range$m-start-col :: = 2 ^ range$s-start-col - 1; define constant range$v-start-line :: = range$v-start-col + range$s-start-col; define constant range$s-start-line :: = 11; define constant range$m-start-line :: = 2 ^ range$s-start-line - 1; define constant range$v-delta-col :: = range$v-start-line + range$s-start-line; define constant range$s-delta-col :: = 7; define constant range$m-delta-col :: = 2 ^ range$s-delta-col - 1; define constant range$v-delta-line :: = range$v-delta-col + range$s-delta-col; define constant range$s-delta-line :: = 3; define constant range$m-delta-line :: = 2 ^ range$s-delta-line - 1; define method source-position-start-offset (pos :: ) => (res :: ) let col = logand(ash(pos, - range$v-start-col), range$m-start-col); let line = logand(ash(pos, - range$v-start-line), range$m-start-line); make-small-source-offset(0, line, col) end method; define method source-position-end-offset (pos :: ) => (res :: ) let sline = logand(ash(pos, - range$v-start-line), range$m-start-line); let dline = logand(ash(pos, - range$v-delta-line), range$m-delta-line); let dcol = logand(ash(pos, - range$v-delta-col), range$m-delta-col); let ecol = if (dline == 0) dcol + logand(ash(pos, - range$v-start-col), range$m-start-col) else dcol end; make-small-source-offset(0, sline + dline, ecol) end method; define inline method range-source-offset-greater-than? (x :: , y :: ) => (well? :: ) x > y end method; // COPY DOWN FOR SPEED define method compute-position-between (p1 :: , p2 :: ) compute-position-between*(p1, p2) end method; define constant = type-union(, ); define generic make-range-position (start-offset :: , end-offset :: ) => (r :: ); define method make-range-position (start-offset :: , end-offset :: ) => (r :: ) make(, start-offset: start-offset, end-offset: end-offset) end method; define method make-range-position (start-offset :: , end-offset :: ) => (r :: ) let sline = source-offset-line(start-offset); if (sline <= range$m-start-line) let dline = source-offset-line(end-offset) - sline; if (dline <= range$m-delta-line) let scol = source-offset-column(start-offset); if (scol <= range$m-start-col) let ecol = source-offset-column(end-offset); let dcol = if (dline == 0) ecol - scol else ecol end; if (0 <= dcol & dcol <= range$m-delta-col) logior(ash(sline, range$v-start-line), ash(dline, range$v-delta-line), ash(scol, range$v-start-col), ash(dcol, range$v-delta-col)) end end end end | make(, start-offset: start-offset, end-offset: end-offset) end method; //// Range source locations. define class () constant slot source-location-record :: , required-init-keyword: source-record:; slot source-location-start-offset :: , required-init-keyword: start-offset:; slot source-location-end-offset :: , required-init-keyword: end-offset:; end; define sealed domain make (subclass()); define sealed domain initialize (); define method source-location-source-record (loc :: ) => (sr :: ) compilation-record-source-record(source-location-record(loc)) end method; define method object-source-location-lines (loc :: ) => (start-line :: , end-line :: ); let cr = loc.source-location-record; let sr = cr.compilation-record-source-record; let offset = cr.compilation-record-preceeding-line-count + sr.source-record-start-line; let start-line = loc.source-location-start-offset.source-offset-line; let end-line = loc.source-location-end-offset.source-offset-line; values(offset + start-line, offset + end-line) end; define method source-location-source-position (loc :: ) make-range-position(source-location-start-offset(loc), source-location-end-offset(loc)) end method; define function record-position-as-location (record :: false-or(), position) if (record) make(, source-record: record, start-offset: source-position-start-offset(position), end-offset: source-position-end-offset(position)) end end function; // Install as the default. define sideways method make-source-location (record :: , start-char :: , start-line :: , start-col :: , end-char :: , end-line :: , end-col :: ) => (loc :: ) make(, source-record: record, start-offset: make-source-offset(start-char, start-line, start-col), end-offset: make-source-offset(end-char, end-line, end-col)); end method; // eof