TextReplaceImpl.Mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Spreitzer, January 10, 1986 10:16:52 pm PST
DIRECTORY Rope, TextFind, TextReplace;
TextReplaceImpl: CEDAR PROGRAM IMPORTS Rope, TextFind EXPORTS TextReplace = {
OPEN TextReplace;
SyntaxError: PUBLIC ERROR = CODE;
NoMapping: PUBLIC SIGNAL [rm: RopeMap, from: ROPE] RETURNS [to: ROPE] = CODE;
Apply: PUBLIC PROC [s: RopeMap, r: ROPE] RETURNS [mapped: ROPE] =
{mapped ← s.Map[s.data, r]};
id: PUBLIC RopeMap ← NEW [RopeMapRep ← [Id, NIL]];
Id: PROC [data: REF ANY, name: ROPE] RETURNS [value: ROPE] =
{value ← name};
addBrackets: PUBLIC RopeMap ← NEW [RopeMapRep ← [AddBrackets, NIL]];
AddBrackets: PROC [data: REF ANY, name: ROPE] RETURNS [value: ROPE] =
{value ← Rope.Cat["<", name, ">"]};
Constant: PUBLIC PROC [result: ROPE] RETURNS [rm: RopeMap] = {
rm ← NEW [RopeMapRep ← [MapToConstant, result]];
};
MapToConstant: PROC [data: REF ANY, arg: ROPE] RETURNS [result: ROPE] = {
constant: ROPE = NARROW[data];
result ← constant;
};
Catted: TYPE = REF CattedRep;
CattedRep: TYPE = RECORD [first, second: RopeMap];
Cat: PUBLIC PROC [first, second: RopeMap] RETURNS [catted: RopeMap] = {
catted ← NEW [RopeMapRep ← [
MapCatted,
NEW [CattedRep ← [first, second]] ]];
};
MapCatted: PROC [data: REF ANY, name: ROPE] RETURNS [value: ROPE] = {
c: Catted ← NARROW[data];
mid: ROPE ← c.first.Map[c.first.data, name];
value ← c.second.Map[c.second.data, mid];
};
Layered: TYPE = REF LayeredRep;
LayeredRep: TYPE = RECORD [first, later: RopeMap];
Layer: PUBLIC PROC [first, later: RopeMap] RETURNS [layered: RopeMap] = {
layered ← NEW [RopeMapRep ← [
MapLayered,
NEW [LayeredRep ← [first, later]] ]];
};
MapLayered: PROC [data: REF ANY, name: ROPE] RETURNS [value: ROPE] = {
l: Layered ← NARROW[data];
value ← l.first.Map[l.first.data, name];
IF value = NIL THEN value ← l.later.Map[l.later.data, name];
};
ProcessedPairList: TYPE = LIST OF ProcessedPair;
ProcessedPair: TYPE = RECORD [finder: TextFind.Finder, replace: ROPE, literal: BOOL];
RopeMapFromPairs: PUBLIC PROC [pl: PairList] RETURNS [s: RopeMap] = {
ppl: ProcessedPairList ← Process[pl];
s ← NEW [RopeMapRep ← [MapPairs, ppl]];
};
Process: PROC [pl: PairList] RETURNS [ppl: ProcessedPairList] = {
IF pl = NIL THEN RETURN [NIL];
ppl ← CONS[
[
finder: TextFind.CreateFromRope[
pattern: pl.first.match,
literal: pl.first.literal,
addBounds: pl.first.addBounds],
replace: pl.first.replace, literal: pl.first.literal],
Process[pl.rest]];
};
MapPairs: PROC [data: REF ANY, name: ROPE] RETURNS [value: ROPE] = {
ppl: ProcessedPairList ← NARROW[data];
pp: ProcessedPair;
MapFinder: PROC [data: REF ANY, name: ROPE] RETURNS [value: ROPE] = {
start, after: INT;
[at: start, atEnd: after] ← TextFind.NameLoc[pp.finder, name];
value ← value.Substr[start: start, len: after - start];
};
s: RopeMap;
TRUSTED {s ← NEW [RopeMapRep ← [MapFinder, NIL]]};
s ← Nest[s];
value ← name;
FOR ppl ← ppl, ppl.rest WHILE ppl # NIL DO
start: INT ← 0;
pp ← ppl.first;
WHILE start < value.Length[] DO
at, atEnd, before, after: INT;
found: BOOL;
[found, at, atEnd, before, after] ← TextFind.SearchRope[finder: pp.finder, rope: value, start: start];
IF found THEN {
newPiece: ROPEIF pp.literal
THEN pp.replace
ELSE Apply[s, pp.replace];
value ← value.Substr[start: 0, len: at].Cat[newPiece, value.Substr[start: atEnd]];
start ← at + newPiece.Length[];
}
ELSE EXIT;
ENDLOOP;
ENDLOOP;
};
FinderMapping: TYPE = REF FinderMappingRep;
FinderMappingRep: TYPE = RECORD [
finder: TextFind.Finder,
lastMatchedRope: ROPE];
MapNamedSubfieldToMatch: PUBLIC PROC [finder: TextFind.Finder, lastMatchedRope: ROPE] RETURNS [rm: RopeMap] = {
rm ← NEW [RopeMapRep ← [
MapNamedSubfield,
NEW [FinderMappingRep ← [finder, lastMatchedRope]] ]];
};
MapNamedSubfield: PROC [data: REF ANY, name: ROPE] RETURNS [value: ROPE] = {
fm: FinderMapping = NARROW[data];
start, after: INT;
[at: start, atEnd: after] ← TextFind.NameLoc[fm.finder, name];
IF start = 0 AND after = 0 THEN RETURN [NIL];
value ← fm.lastMatchedRope.Substr[start: start, len: after - start];
};
MatchToTemplate: TYPE = REF MatchToTemplatePrivate;
MatchToTemplatePrivate: TYPE = RECORD [
finder: TextFind.Finder,
template: ROPE];
MapByMatchToTemplate: PUBLIC PROC [finder: TextFind.Finder, template: ROPE] RETURNS [rm: RopeMap] = {
mtt: MatchToTemplate = NEW [MatchToTemplatePrivate ← [finder, template]];
rm ← NEW [RopeMapRep ← [MapMatchToTemplate, mtt]];
};
MapMatchToTemplate: PROC [data: REF ANY, arg: ROPE] RETURNS [result: ROPE] = {
mtt: MatchToTemplate = NARROW[data];
found: BOOL = TextFind.SearchRope[mtt.finder, arg].found;
IF NOT found THEN RETURN [NIL];
result ← Apply[Nest[MapNamedSubfieldToMatch[mtt.finder, arg]], mtt.template];
};
Nest: PUBLIC PROC [rm: RopeMap] RETURNS [nested: RopeMap] =
{nested ← NEW [RopeMapRep ← [MapNested, rm]]};
MapNested: PROC [data: REF ANY, old: ROPE] RETURNS [new: ROPE] = {
rm: RopeMap ← NARROW[data];
i: INT ← 0;
oldLen: INT ← old.Length[];
new ← NIL;
WHILE i < oldLen DO
c: CHAR ← old.Fetch[i];
SELECT c FROM
'' => {
IF i+1 = oldLen THEN SyntaxError[];
new ← new.Concat[Rope.FromChar[old.Fetch[i+1]]];
i ← i + 2};
'< => {j: INT ← i+1;
name, value: ROPE;
DO
IF j >= oldLen THEN SyntaxError[];
SELECT old.Fetch[j] FROM
'> => EXIT;
'<, '' => SyntaxError[]; --No metachars in field name
ENDCASE;
j ← j + 1;
ENDLOOP;
name ← old.Substr[start: i+1, len: j - i - 1];
value ← rm.Map[rm.data, name];
IF value = NIL THEN value ← NoMapping[rm, name];
new ← new.Concat[value];
i ← j + 1};
ENDCASE => {
new ← new.Concat[Rope.FromChar[c]];
i ← i + 1};
ENDLOOP;
};
MatchAndSubstitute: PUBLIC PROC [pattern, against, template: ROPE] RETURNS [new: ROPE] = {
f: TextFind.Finder = TextFind.CreateFromRope[pattern];
found: BOOL = TextFind.SearchRope[f, against].found;
IF NOT found THEN RETURN [template];
new ← Apply[Nest[MapNamedSubfieldToMatch[f, against]], template];
};
}.