-- ExecuteImpl.mesa
-- written by Bill Paxton, May 1981
-- last edit by Bill Paxton, 21-May-81 14:44:54

-- This package implements the Execute command in Tioga

DIRECTORY
Execute,
RopeReader,
TextEdit,
TreeEdit,
TextNode,
TreeEdit,
TiogaAlloc,
TiogaJaM;

ExecuteImpl: PROGRAM
	IMPORTS TextEdit, TreeEdit, jamI:TiogaJaM, rdrI:RopeReader, allocI:TiogaAlloc,
		treeI:TreeEdit
	EXPORTS Execute =
BEGIN
OPEN Execute, nodeI:TextNode;


-- ***** Execute

Exec: PUBLIC PROC [keyNode: RefTextNode, keyStart, keyLen: Card, dictList: NodeList]
	RETURNS [foundIt: BOOLEAN, exec: Rope] = {
	
	DoAbbreviation: PROC = {
		looks: looksI.Looks;
		allcaps, initialcap: BOOLEAN ← FALSE;
		child: RefTextNode ← nodeI.NarrowToTextNode[nodeI.FirstChild[node]];
		childSize: Card;
		IF AllCaps[] THEN allcaps ← TRUE
		ELSE IF editI.FetchChar[keyNode,keyStart] IN ['A..'Z] THEN initialcap ← TRUE;
		editI.ReplaceText[keyNode,keyStart,keyLen,child];
		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
			treeI.CopyNodes[keyNode,nodeI.FirstChild[child],nodeI.LastChild[child]];
		IF nodeI.Next[child] # NIL THEN -- insert as siblings of keyNode
			treeI.CopyNodes[keyNode,nodeI.Next[child],nodeI.LastSibling[child],FALSE];
		};
		
	AllCaps: PROC RETURNS [upper:BOOLEAN] = {
		rdr1 ← rdr3; -- set for start of key
		upper ← FALSE;
		THROUGH [0..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]];
		childSize: Card;
		IF child=NIL THEN RETURN;
		exec ← child.rope };
					
	rdr1, rdr2, rdr3: rdrI.Ref;
	keyRope: Rope ← keyNode.rope;
	node: RefTextNode;
	rope: Rope;
	size: Card;
	foundIt ← FALSE;
	rdr1 ← allocI.GetRopeReader[];
	rdr2 ← allocI.GetRopeReader[];
	rdr3 ← allocI.GetRopeReader[];
	rdrI.SetPosition[rdr3,keyRope,keyStart]; -- leave this one permanently set at key
	[] ← rdrI.Peek[rdr3]; 
	FOR dict:Ref ← dictList, dict.next UNTIL dict=NIL DO
		FOR entry:Ref ← dict.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, abbrevTypeName => DoAbbreviation[];
					commandTypeName => DoCommand[];
					ENDCASE;
				GOTO Finis };
			ENDLOOP;
		REPEAT Finis => NULL;
		ENDLOOP;
	
	allocI.FreeRopeReader[rdr1];
	allocI.FreeRopeReader[rdr2];
	allocI.FreeRopeReader[rdr3] };


-- ***** Initialization

abbrevTypeName, commandTypeName: nodeI.TypeName;

Start: PUBLIC PROC = { -- for initialization only
	abbrevTypeName ← jamI.MakeTypeName["abbrev"];
	commandTypeName ← jamI.MakeTypeName["command"];
	};
	
END.