MODULE; IMPORT Buf, Text, Text2, M3Sym, Marker; CONST Start_Impls = "<A HREF=\"" & Intf_to_Impl_Mark & "/"; Start_Intfs = "<A HREF=\"" & Impl_to_Intf_Mark & "/"; Start_Defn = "<A NAME=\"" & ThisDecl & "\">"; Start_Use = "<A HREF=\""; Start_Type = "<A HREF=\"/type/"; Start_EM = "<B><EM><FONT SIZE=+1>"; End_EM = "</FONT></EM></B>"; End_Ref = "\">"; End_DeclRef = "#_DECL_\">"; End_Anchor = "</A>"; CONST HasDecl = ARRAY M3Sym.Kind OF BOOLEAN { FALSE, (* IntfName *) FALSE, (* ImplName *) FALSE, (* GIntfName *) FALSE, (* GImplName *) FALSE, (* GIntfUse *) FALSE, (* GImplUse *) TRUE, (* GFormal *) FALSE, (* GActual *) FALSE, (* Export *) FALSE, (* Import *) FALSE, (* FromImport *) TRUE, (* SymImport *) FALSE, (* ImportXX *) FALSE, (* ImportAs *) TRUE, (* ConstDecl *) TRUE, (* VarDecl *) TRUE, (* ExceptDecl *) TRUE, (* ProcDecl *) TRUE, (* TypeDecl *) TRUE, (* TypeUse *) TRUE, (* ExceptUse *) TRUE, (* ProcUse *) TRUE, (* MiscUse *) FALSE, (* Keyword *) FALSE, (* BuiltinOp *) FALSE, (* BuiltinType *) FALSE (* BuiltinConst *) }; CONST IgnoreSyms = M3Sym.KindSet { M3Sym.Kind.BuiltinOp, M3Sym.Kind.BuiltinConst }; CONST EndRef = ARRAY BOOLEAN(*has_decl*) OF TEXT { End_Ref, End_DeclRef }; StartOther = ARRAY BOOLEAN(*is_intf*) OF TEXT { Start_Intfs, Start_Impls }; TYPE Insertion = Marker.CharInsertion; TYPE State = M3Sym.CallBack OBJECT buf : Buf.T; target : TEXT; target_len : INTEGER; ins : Insertion; is_interface : BOOLEAN; is_generic : BOOLEAN; unit_name : M3Sym.Id; OVERRIDES note_sym := NoteSym; note_qid := NoteQID; END; PROCEDURE M3MarkUp Get (buf: Buf.T; target: TEXT): Insertion = VAR s := NEW (State); head := NEW (Insertion, next := NIL); BEGIN s.buf := buf; s.target := target; s.target_len := 0; s.ins := head; s.is_interface := TRUE; s.is_generic := FALSE; IF (target # NIL) THEN s.target_len := Text.Length (target); END; M3Sym.Scan (buf, s, IgnoreSyms); RETURN head; END Get; PROCEDURENoteSym (s : State; READONLY sym : M3Sym.Id; kind : M3Sym.Kind; <*UNUSED*> intf : TEXT): BOOLEAN = VAR decl_hit := FALSE; BEGIN CASE kind OF | M3Sym.Kind.IntfName => s.is_interface := TRUE; s.is_generic := FALSE; s.unit_name := sym; Add (s, sym.start, Start_Impls); Add (s, sym.start, End_Ref); Add (s, sym.start + sym.len, End_Anchor); | M3Sym.Kind.ImplName => s.is_interface := FALSE; s.is_generic := FALSE; s.unit_name := sym; (* don't mark the name, it might be the link to the exported interface *) | M3Sym.Kind.GIntfName => s.is_interface := TRUE; s.is_generic := TRUE; s.unit_name := sym; NoteUse (s, sym, kind); | M3Sym.Kind.GImplName => s.is_interface := FALSE; s.is_generic := TRUE; s.unit_name := sym; NoteUse (s, sym, kind); | M3Sym.Kind.GFormal, M3Sym.Kind.ConstDecl, M3Sym.Kind.VarDecl, M3Sym.Kind.ExceptDecl => (* mark this definition, if it matches the one we're looking for *) IF TargetMatch (s, sym) THEN Add (s, sym.start, Start_Defn); Add (s, sym.start, Start_EM); Add (s, sym.start + sym.len, End_EM); Add (s, sym.start + sym.len, End_Anchor); END; | M3Sym.Kind.ProcDecl => IF TargetMatch (s, sym) THEN (* we want to find this procedure => mark it *) Add (s, sym.start-1, Start_Defn); Add (s, sym.start, End_Anchor); decl_hit := TRUE; END; (* now, make the procedure ID a link to the corresponding impl/defn *) Add (s, sym.start, StartOther [s.is_interface]); AddToken (s, sym); Add (s, sym.start, End_DeclRef); IF decl_hit THEN Add (s, sym.start, Start_EM); Add (s, sym.start + sym.len, End_EM); END; Add (s, sym.start + sym.len, End_Anchor); | M3Sym.Kind.TypeDecl => IF TargetMatch (s, sym) THEN (* we want to find this type declaration => mark it *) Add (s, sym.start-1, Start_Defn); Add (s, sym.start, End_Anchor); decl_hit := TRUE; END; IF NOT s.is_generic THEN (* build a link to the "/type" part of the name space *) Add (s, sym.start, Start_Type); AddToken (s, s.unit_name); Add (s, sym.start, "."); AddToken (s, sym); Add (s, sym.start, End_Ref); IF decl_hit THEN Add (s, sym.start, Start_EM); Add (s, sym.start + sym.len, End_EM); END; Add (s, sym.start + sym.len, End_Anchor); ELSE (* generic types can still be decl hits... *) IF decl_hit THEN Add (s, sym.start, Start_EM); Add (s, sym.start + sym.len, End_EM); END; END; | M3Sym.Kind.GIntfUse, M3Sym.Kind.GImplUse, M3Sym.Kind.GActual, M3Sym.Kind.Export, M3Sym.Kind.Import, M3Sym.Kind.FromImport, M3Sym.Kind.SymImport, M3Sym.Kind.ImportXX, M3Sym.Kind.ImportAs, M3Sym.Kind.TypeUse, M3Sym.Kind.ExceptUse, M3Sym.Kind.ProcUse, M3Sym.Kind.MiscUse => NoteUse (s, sym, kind); | M3Sym.Kind.Keyword => Add (s, sym.start, "<B>"); Add (s, sym.start + sym.len, "</B>"); | M3Sym.Kind.BuiltinType => Add (s, sym.start, Start_Type); AddToken (s, sym); Add (s, sym.start, End_Ref); Add (s, sym.start + sym.len, End_Anchor); | M3Sym.Kind.BuiltinOp, M3Sym.Kind.BuiltinConst => (* ignore *) END; (* CASE *) RETURN FALSE; END NoteSym; PROCEDURENoteUse (s: State; READONLY sym: M3Sym.Id; kind: M3Sym.Kind) = BEGIN Add (s, sym.start, Start_Use); AddToken (s, sym); Add (s, sym.start, EndRef [HasDecl [kind]]); Add (s, sym.start + sym.len, End_Anchor); END NoteUse; PROCEDURENoteQID (s: State; READONLY qid: M3Sym.QId; kind: M3Sym.Kind): BOOLEAN = VAR markup := Start_Use; start := qid[0].start; BEGIN FOR i := FIRST (qid) TO LAST (qid) DO Add (s, start, markup); AddToken (s, qid[i]); markup := "/"; END; Add (s, start, EndRef [HasDecl [kind]]); WITH z = qid [LAST (qid)] DO Add (s, z.start + z.len, End_Anchor); END; RETURN FALSE; END NoteQID; PROCEDURETargetMatch (s: State; READONLY sym: M3Sym.Id): BOOLEAN = BEGIN IF (s.target # NIL) AND (sym.len = s.target_len) AND Text2.EqualSub (s.target, SUBARRAY (s.buf^, sym.start, sym.len)) THEN s.target := NIL; (* prevent further matches. *) RETURN TRUE; END; RETURN FALSE; END TargetMatch; PROCEDUREAddToken (s: State; READONLY sym: M3Sym.Id) = BEGIN WITH z = s.ins.insert [s.ins.count-1] DO z.start := sym.start; z.length := sym.len; END; END AddToken; PROCEDUREAdd (s: State; offs: INTEGER; txt: TEXT) = BEGIN IF (s.ins.count >= NUMBER (s.ins.insert)) THEN s.ins.next := NEW (Insertion, next := NIL, count := 0); s.ins := s.ins.next; END; WITH z = s.ins.insert [s.ins.count] DO z.offset := offs; z.txt := txt; END; INC (s.ins.count); END Add; BEGIN END M3MarkUp.