-- TiogaExecuteImpl.mesa
-- written by Bill Paxton, May 1981
-- last edit by Bill Paxton, 14-Jul-81 10:16:19

-- This package implements the Execute command in Tioga

DIRECTORY
TiogaExecute,
RopeReader,
TextEdit,
EditSpan,
TextNode,
TextLooks,
RopeEdit,
NameSymbolTable;

TiogaExecuteImpl: PROGRAM
	IMPORTS nsI:NameSymbolTable, rdrI:RopeReader, spanI:EditSpan, nodeI:TextNode,
		ropeI:RopeEdit, editI:TextEdit
	EXPORTS TiogaExecute =
BEGIN
OPEN TiogaExecute, looksI:TextLooks;

Ref: TYPE = nodeI.Ref;

-- ***** Execute

Exec: PUBLIC PROC [keyNode: RefTextNode, keyStart, keyLen: Offset, dictList: NodeList,
	event: Event ← NIL]
	RETURNS [foundIt: BOOLEAN, exec: Rope, resultStart, resultLen: Offset] = {
	
	DoAbbreviation: PROC = {
		looks: looksI.Looks;
		allcaps, initialcap: BOOLEAN ← FALSE;
		child: RefTextNode ← nodeI.NarrowToTextNode[nodeI.FirstChild[node]];
		childSize: Offset;
		IF AllCaps[] THEN allcaps ← TRUE
		ELSE IF editI.FetchChar[keyNode,keyStart] IN ['A..'Z] THEN initialcap ← TRUE;
		[resultStart,resultLen] ←
			editI.ReplaceText[keyNode,keyStart,keyLen,child,0,editI.MaxLen,event];
		IF child=NIL THEN RETURN;
		childSize ← editI.Size[child];
		IF (looks ← editI.FetchLooks[keyNode,keyStart]) # looksI.noLooks THEN
			editI.AddLooks[keyNode,looks,keyStart,childSize];
		IF allcaps THEN editI.InitialCaps[keyNode,keyStart,childSize]
		ELSE IF initialcap AND childSize > 0 THEN editI.AllCaps[keyNode,keyStart,1];
		IF nodeI.FirstChild[child] # NIL THEN -- insert as children of keyNode
			[] ← spanI.Copy[nodeI.MakeNodeLoc[keyNode],
				nodeI.MakeNodeSpan[nodeI.FirstChild[child],
					nodeI.LastWithin[child]],
				FALSE,after,1,event];
		IF nodeI.Next[child] # NIL THEN -- insert as siblings of keyNode
			[] ← spanI.Copy[nodeI.MakeNodeLoc[keyNode],
				nodeI.MakeNodeSpan[nodeI.Next[child],
					nodeI.LastWithin[nodeI.LastSibling[child]]],
				FALSE,after,0,event];
		};
		
	AllCaps: PROC RETURNS [upper:BOOLEAN] = {
		rdr1 ← rdr3; -- set for start of key
		upper ← FALSE;
		FOR i:Offset ← 0, i+1 UNTIL i >= keyLen DO
			SELECT rdrI.Get[rdr1] FROM
				IN ['a..'z] => RETURN [FALSE];
				IN ['A..'Z] => upper ← TRUE; -- must have at least one uppercase
				ENDCASE;
			ENDLOOP };
	
	DoCommand: PROC = {
		child: RefTextNode ← nodeI.NarrowToTextNode[nodeI.FirstChild[node]];
		IF child=NIL THEN RETURN;
		exec ← child.rope };
					
	rdr1, rdr2, rdr3: rdrI.Ref;
	keyRope: Rope ← keyNode.rope;
	node: RefTextNode;
	rope: Rope;
	size: Offset;
	foundIt ← FALSE;
	rdr1 ← rdrI.GetRopeReader[];
	rdr2 ← rdrI.GetRopeReader[];
	rdr3 ← rdrI.GetRopeReader[];
	rdrI.SetPosition[rdr3,keyRope,keyStart]; -- leave this one permanently set at key
	[] ← rdrI.Peek[rdr3]; 
	FOR lst:NodeList ← dictList, lst.next UNTIL lst=NIL DO
		FOR entry:Ref ← lst.node.child, nodeI.Next[entry] UNTIL entry=NIL DO
			IF (node ← nodeI.NarrowToTextNode[entry])=NIL THEN LOOP;
			IF (size ← ropeI.Size[rope ← node.rope]) # keyLen THEN LOOP;
			rdr1 ← rdr3; -- already primed to read key
			IF rdrI.CompareSubstrs[keyRope,rope,keyStart,keyLen,0,size,rdr1,rdr2,FALSE] = 0 THEN {
				foundIt ← TRUE; -- have found a match
				SELECT node.typename FROM
				nodeI.nullTypeName, abbrev, abbreviation => DoAbbreviation[];
				command => DoCommand[];
				ENDCASE;
				GOTO Finis };
			ENDLOOP;
		REPEAT Finis => NULL;
		ENDLOOP;
	
	rdrI.FreeRopeReader[rdr1];
	rdrI.FreeRopeReader[rdr2];
	rdrI.FreeRopeReader[rdr3] };


-- ***** Initialization

abbrev, abbreviation, command: nodeI.TypeName;

Start: PUBLIC PROC = { -- for initialization only
	abbrev ← nsI.MakeName["abbrev"];
	abbreviation ← nsI.MakeName["abbreviation"];
	command ← nsI.MakeName["command"];
	};
	
END.