--* From IGLIO%WATSON.vnet.ibm.com@yktvmv.watson.ibm.com  Thu Jun  9 16:18:50 1994
--* Received: from yktvmv-ob.watson.ibm.com by asharp.watson.ibm.com (AIX 3.2/UCB 5.64/930311)
--*           id AA28805; Thu, 9 Jun 1994 16:18:50 -0400
--* Received: from watson.vnet.ibm.com by yktvmv.watson.ibm.com (IBM VM SMTP V2R3)
--*    with BSMTP id 1271; Thu, 09 Jun 94 16:18:51 EDT
--* Received: from YKTVMV by watson.vnet.ibm.com with "VAGENT.V1.0"
--*           id <A.IGLIO.NOTE.VAGENT2.5007.Jun.09.16:18:50.-0400>
--*           for asbugs@watson; Thu, 09 Jun 94 16:18:50 -0400
--* Received: from YKTVMV by watson.vnet.ibm.com with "VAGENT.V1.0"
--*           id 5003; Thu, 9 Jun 1994 16:18:50 EDT
--* Received: from leonardo.watson.ibm.com by yktvmv.watson.ibm.com
--*    (IBM VM SMTP V2R3) with TCP; Thu, 09 Jun 94 16:18:49 EDT
--* Received: by leonardo.watson.ibm.com (AIX 3.2/UCB 5.64/920123)
--*           id AA21109; Thu, 9 Jun 1994 16:14:00 -0400
--* Date: Thu, 9 Jun 1994 16:14:00 -0400
--* From: iglio@leonardo.watson.ibm.com
--* X-External-Networks: yes
--* Message-Id: <9406092014.AA21109@leonardo.watson.ibm.com>
--* To: asbugs@watson.ibm.com
--* Subject: [1] -Qno-... is not working. I'm not sure 100%, I had problems with Qno-jflow (accepted!) and -Qno-flow not working. [string.as][0.35.7]

--@ Fixed  by:  PAB   Tue Jun 21 17:00:07 EDT 1994 
--@ Tested by:  none 
--@ Summary:    fixed 


--
-- String.as
--

#assert InBasic
#include "aslib"

#library TupleLib    "tuple.aso"
#library SegmentLib  "segment.aso"
#library SIntegerLib "sinteger.aso"
#library CharLib     "char.aso"
#library BooleanLib  "boolean.aso"

import from  TupleLib, SegmentLib, SIntegerLib, CharLib, BooleanLib;

+++ String is the type of character strings for natural language text.
+++
+++ Author: A# library
+++ Date Created: 1992-93
+++ Keywords: string, text

extend String: BasicType with {
	new:	   (SingleInteger, fill: Character == space) -> %;
	copy:	   % -> %;
	concat:    Tuple(%) -> %;
	#:	   (%) -> SingleInteger;
	apply:	   (%, SingleInteger) -> Character;
	apply:	   (%, OpenSegment   SingleInteger) -> %;
	apply:	   (%, ClosedSegment SingleInteger) -> %;
	generator: (%) -> Generator Character;
	map:       (f: Character -> Character, %) -> %;
	map!:      (f: Character -> Character, %) -> %;
	set!:	   (%, SingleInteger, Character) -> Character;
	fill!:	   (%, Segment SingleInteger, Character) -> %;
	replace!:  (%, SingleInteger, %) -> SingleInteger;
		++ replace!(s1, i0, s2) replaces characters in s1
		++ begining at position i0 with characters from s2.
		++ Returns the next available position in s1.

	substring: (%, SingleInteger, SingleInteger) -> %;
		++ substring(s, start, len)	returns the substring of s
		++ from position start of length len.

	data:      % -> BArr;
}
== add {
	Rep    ==> BArr;

	import from Boolean, SingleInteger, Segment SingleInteger;

	---- Representation ----

	EOS: Character == char 0;

#if BArrBChar
	--!! Use this version when builtin arrays can pack characters.
	import from Machine;

	empty(size: SingleInteger): % == {
		s := per array(BChar)(EOS::BChar, (size+1)::BSInt);
		set!(BChar)(rep s, 0::BSInt,    EOS::BChar);
		set!(BChar)(rep s, size::BSInt, EOS::BChar);
		s
	}
	apply(s: %, i: SingleInteger): Character ==
		get(BChar)(rep s, (i-1)::BSInt)::Character;
	set!(s: %, i: SingleInteger, c: Character): Character ==
		set!(BChar)(rep s, (i-1)::BSInt, c::BChar)::Character;
#else
	import {
		ArrNew:	(BChar, BSInt) -> BArr;
		ArrElt:	(BArr, BSInt) -> BChar;
		ArrSet:	(BArr, BSInt, BChar) -> BChar;
	} from Builtin;

	empty(size: SingleInteger): % == {
		s := per ArrNew(EOS::BChar, (size+1)::BSInt);
		ArrSet(rep s, 0::BSInt,    EOS::BChar);
		ArrSet(rep s, size::BSInt, EOS::BChar);
		s
	}
	apply(s: %, i: SingleInteger): Character ==
		ArrElt(rep s, (i-1)::BSInt)::Character;
	set!(s: %, i: SingleInteger, c: Character): Character ==
		ArrSet(rep s, (i-1)::BSInt, c::BChar)::Character;
#endif

	data(s: %): BArr == rep s;

	---- String operations ----

	sample: % == empty 0;

	new(size: SingleInteger, fill: Character == space): % == {
		s := empty size;
		for i in 1..size repeat s.i := fill;
		s
	}

	copy(s: %): % == {
		len := #s;
		r   := empty len;
		for i in 1..len repeat r.i := s.i;
		r
	}

	#(s: %): SingleInteger == {
		for i in 1.. repeat
			s.i = EOS => return (i-1);
		never
	}

	(s1: %) = (s2: %): Boolean == {
		for i in 1.. repeat {
			c := s1.i;
			c  = EOS => return s2.i = c;
			c ~= s2.i => return false;
		}
		true
	}

	replace!(s1: %, pos: SingleInteger, sub: %): SingleInteger == {
		for i in 1.. for ii in pos.. repeat {
			c := sub.i;
			c = EOS or s1.ii = EOS => return ii;
			s1.ii := c;
		}
		never
	}
	substring(s1: %, pos: SingleInteger, len: SingleInteger): % == {
		s2 := empty len;
		for i in 1..len for j in pos.. repeat
			s2.i := s1.j;
		s2
	}
	apply(s: %, seg: OpenSegment SingleInteger): % == {
		pos := low(seg::Segment SingleInteger);
		len := #s - pos + 1;
		substring(s, pos, len);
	}
	apply(s: %, seg: ClosedSegment SingleInteger): % == {
		pos := low (seg::Segment SingleInteger);
		len := high(seg::Segment SingleInteger) - pos + 1;
		substring(s, pos, len);
	}
	fill!(s: %, seg: Segment SingleInteger, c: Character): % == {
		len := #s;
		for i in seg while i <= len repeat s.i := c;
		s
	}
#if PercentOK
	--!! This code now compiles, but generates run time errors.
	concat(t: Tuple %): % == {
                n : SingleInteger := 0;
                for i in 1..length t repeat n := n + #element(t, i);
                r := new n;
                n := 1;
                for i in 1..length t repeat n := replace!(r, n, element(t, i));
                r
	}
#else
	concat(t: Tuple %): % == {
                tt := t pretend Tuple String;
                n  : SingleInteger := 0;
                for i in 1..length tt repeat
                        n := n + #(element(tt, i) pretend %);
                r: % := new n;
                n := 1;
                for i in 1..length tt repeat
                        n := replace!(r, n, (element(tt, i) pretend %));
                r
	}
#endif
	map!(f: Character -> Character, s: %): % == {
		for i in 1.. repeat {
			c := s.i;
			c = EOS => return s;
			s.i := f c;
		}
		s
	}
	map(f: Character -> Character, s: %): % == {
		s2 := empty(l := #s);
		for i in 1..l repeat s2.i := f s.i;
		s2
	}
	generator(s: %): Generator Character == generate
		for i in 1.. while (c := s.i) ~= EOS repeat yield c;
}
 
