1(* 2 Copyright (c) 2013, 2016 David C.J. Matthews 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Lesser General Public 6 License version 2.1 as published by the Free Software Foundation. 7 8 This library is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 Lesser General Public License for more details. 12 13 You should have received a copy of the GNU Lesser General Public 14 License along with this library; if not, write to the Free Software 15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 16*) 17 18(* 19 Derived from the original parse-tree 20 21 Copyright (c) 2000 22 Cambridge University Technical Services Limited 23 24 Further development: 25 Copyright (c) 2000-13 David C.J. Matthews 26 27 Title: Parse Tree Structure and Operations. 28 Author: Dave Matthews, Cambridge University Computer Laboratory 29 Copyright Cambridge University 1985 30 31*) 32 33functor EXPORT_PARSETREE ( 34 35 structure BASEPARSETREE : BaseParseTreeSig 36 structure PRINTTREE: PrintParsetreeSig 37 structure LEX : LEXSIG 38 structure STRUCTVALS : STRUCTVALSIG 39 structure EXPORTTREE: EXPORTTREESIG 40 structure TYPETREE : TYPETREESIG 41 structure DEBUGGER : DEBUGGER 42 43 sharing LEX.Sharing = TYPETREE.Sharing = STRUCTVALS.Sharing 44 = EXPORTTREE.Sharing = BASEPARSETREE.Sharing = PRINTTREE.Sharing 45 = DEBUGGER.Sharing 46 47): ExportParsetreeSig 48= 49struct 50 open LEX 51 open STRUCTVALS 52 open EXPORTTREE 53 open TYPETREE 54 open BASEPARSETREE 55 open PRINTTREE 56 57 fun getExportTree(navigation, p: parsetree) = 58 let 59 (* Common properties for navigation and printing. *) 60 val commonProps = exportNavigationProps navigation @ [PTprint(fn d => displayParsetree(p, d))] 61 62 fun asParent () = getExportTree(navigation, p) 63 64 (* Put all these into a common list. That simplifies navigation between 65 the various groups in abstypes and datatypes. *) 66 datatype lType = DataT of datatypebind | TypeB of typebind | Decl of parsetree * breakPoint option ref 67 68 (* Common code for datatypes, abstypes and type bindings. *) 69 fun exportTypeBinding(navigation, this as DataT(DatatypeBind{name, nameLoc, fullLoc, constrs, tcon=ref(TypeConstrSet(tcon, _)), ...})) = 70 let 71 fun asParent () = exportTypeBinding(navigation, this) 72 (* Ignore any type variables before the type name. *) 73 fun getName () = 74 getStringAsTree({parent=SOME asParent, previous=NONE, next=SOME getConstrs}, name, nameLoc, 75 definingLocationProps(tcLocations tcon)) 76 and getConstrs () = 77 let 78 fun exportConstrs(navigation, {constrName, idLocn, constrVal=ref(Value{locations, ...}), ... }) = 79 (* TODO: the constructor type. *) 80 getStringAsTree(navigation, constrName, idLocn, definingLocationProps locations) 81 in 82 (fullLoc, (* TODO: We need a separate location for the constrs. *) 83 exportList(exportConstrs, SOME asParent) constrs @ 84 exportNavigationProps {parent=SOME asParent, previous=SOME getName, next=NONE}) 85 end 86 in 87 (fullLoc, PTfirstChild getName :: exportNavigationProps navigation) 88 end 89 90 | exportTypeBinding(navigation, 91 this as TypeB(TypeBind{name, nameLoc, decType = SOME decType, fullLoc, tcon=ref(TypeConstrSet(tcon, _)), ...})) = 92 let 93 fun asParent () = exportTypeBinding(navigation, this) 94 (* Ignore any type variables before the type name. *) 95 fun getName () = 96 getStringAsTree({parent=SOME asParent, previous=NONE, next=SOME getType}, name, nameLoc, 97 definingLocationProps(tcLocations tcon)) 98 and getType () = 99 typeExportTree({parent=SOME asParent, previous=SOME getName, next=NONE}, decType) 100 in 101 (fullLoc, PTfirstChild getName :: exportNavigationProps navigation) 102 end 103 104 (* TypeBind is also used in a signature in which case decType could be NONE. *) 105 | exportTypeBinding(navigation, 106 this as TypeB(TypeBind{name, nameLoc, decType = NONE, fullLoc, tcon=ref(TypeConstrSet(tcon, _)), ...})) = 107 let 108 fun asParent () = exportTypeBinding(navigation, this) 109 (* Ignore any type variables before the type name. *) 110 (* Retain this as a child entry in case we decide to add the type vars later. *) 111 fun getName () = 112 getStringAsTree({parent=SOME asParent, previous=NONE, next=NONE}, name, nameLoc, 113 definingLocationProps(tcLocations tcon)) 114 in 115 (fullLoc, PTfirstChild getName :: exportNavigationProps navigation) 116 end 117 118 | exportTypeBinding(navigation, Decl dec) = 119 (* Value declarations in an abstype. *) exportTreeWithBpt(navigation, dec) 120 121 (* In a couple of cases we can have a breakpoint associated with an entry. *) 122 and exportTreeWithBpt(nav, (p, ref NONE)) = getExportTree (nav, p) 123 | exportTreeWithBpt(nav, (p, ref (SOME bpt))) = 124 let 125 val (loc, props) = getExportTree (nav, p) 126 in 127 (loc, PTbreakPoint bpt :: props) 128 end 129 130 fun exportMatch(navigation, 131 p as MatchTree{location, vars, exp, resType = ref rtype, argType = ref atype, breakPoint = ref bpt, ...}) = 132 let 133 fun asParent () = exportMatch(navigation, p) 134 val debugProp = 135 case bpt of 136 NONE => [] 137 | SOME bpt => [PTbreakPoint bpt] 138 in 139 (location, 140 [PTprint(fn d => displayMatch(p, d)), PTtype (mkFunctionType (atype, rtype))] @ 141 exportList(getExportTree, SOME asParent) [vars, exp] @ 142 exportNavigationProps navigation @ debugProp 143 ) 144 end 145 in 146 case p of 147 Ident{location, expType=ref expType, value, possible, name, ...} => 148 let 149 (* Include the type and declaration properties if these 150 have been set. *) 151 val (decProp, references, possProp) = 152 case value of 153 ref (Value{name = "<undefined>", ...}) => 154 let 155 (* Generate possible completions. For the moment just consider 156 simple prefixes. *) 157 val completions = List.filter (String.isPrefix name) (! possible ()) 158 in 159 ([], NONE, [PTcompletions completions]) 160 end 161 | ref (Value{locations, references, ...}) => 162 let 163 (* If this is in a pattern it could be the defining location of the id. 164 It's complicated trying to find out exactly which is the defining location 165 so we check to see if this is the DeclaredAt location. *) 166 val locProps = 167 case List.find (fn DeclaredAt l => l = location | _ => false) locations of 168 SOME _ => definingLocationProps locations 169 | NONE => mapLocationProps locations 170 in 171 (locProps, references, []) 172 end 173 val refProp = 174 case references of 175 NONE => [] 176 | SOME {exportedRef=ref exp, localRef=ref locals, recursiveRef=ref recs} => 177 [PTreferences(exp, List.map #1 recs @ locals)] 178 in 179 (location, PTtype expType :: decProp @ commonProps @ refProp @ possProp) 180 end 181 182 | Literal {location, expType=ref expType, ...} => (location, PTtype expType :: commonProps) 183 184 (* Infixed application. For the purposes of navigation we treat this as 185 three entries in order. *) 186 | Applic{location, f, arg = TupleTree{fields=[left, right], ...}, isInfix = true, expType=ref expType, ...} => 187 (location, 188 PTtype expType :: exportList(getExportTree, SOME asParent) [left, f, right] @ commonProps) 189 190 (* Non-infixed application. *) 191 | Applic{location, f, arg, expType=ref expType, ...} => 192 (location, PTtype expType :: exportList(getExportTree, SOME asParent) [f, arg] @ commonProps) 193 194 | Cond{location, test, thenpt, elsept, thenBreak, elseBreak, ...} => 195 (location, 196 exportList(exportTreeWithBpt, SOME asParent) 197 [(test, ref NONE), (thenpt, thenBreak), (elsept, elseBreak)] @ commonProps) 198 199 | TupleTree{fields, location, expType=ref expType, ...}=> 200 (location, PTtype expType :: exportList(getExportTree, SOME asParent) fields @ commonProps) 201 202 | ValDeclaration{location, dec, ...} => 203 let 204 fun exportVB(navigation, vb as ValBind{dec, exp, line, ...}) = 205 let 206 val vbProps = exportNavigationProps navigation 207 (* First child should give the pattern *) 208 (* Second child should give the expression *) 209 fun exportThis () = exportVB(navigation, vb) 210 val asChild = exportList(getExportTree, SOME exportThis) [dec, exp] 211 in 212 (line, asChild @ vbProps) 213 end 214 215 val expChild = exportList(exportVB, SOME asParent) dec 216 in 217 (* We need a special case for a top-level expression. This has been converted 218 by the parser into val it = exp but the "val it = " takes up no space. 219 We need to go directly to the expression in that case. *) 220 case dec of 221 [ValBind{dec=Ident{name="it", location=itLoc, ...}, exp, ...}] 222 => if #startPosition itLoc = #endPosition itLoc andalso 223 #startLine itLoc = #endLine itLoc 224 then getExportTree(navigation, exp) 225 else (location, expChild @ commonProps) 226 | _ => (location, expChild @ commonProps) 227 end 228 229 | FunDeclaration{location, dec, ...} => 230 let 231 (* It's easiest to put these all together into a single list. *) 232 datatype funEntry = 233 FunIdent of { name: string, expType: types ref, location: location } * values 234 | FunPtree of parsetree 235 | FunConstraint of typeParsetree 236 | FunInfixed of funEntry list * location 237 238 fun exportFunEntry(navigation, FunIdent({expType=ref expType, location, ...}, Value{references, locations, ...})) = 239 let 240 val refProp = 241 case references of 242 NONE => [] 243 | SOME {exportedRef=ref exp, localRef=ref locals, recursiveRef=ref recs} => 244 [PTreferences(exp, List.map #1 recs @ locals)] 245 in 246 (location, refProp @ definingLocationProps locations @ (PTtype expType :: exportNavigationProps navigation)) 247 end 248 | exportFunEntry(navigation, FunPtree pt) = getExportTree(navigation, pt) 249 | exportFunEntry(navigation, FunConstraint typ) = typeExportTree(navigation, typ) 250 251 | exportFunEntry(navigation, this as FunInfixed(inf, location)) = 252 let 253 fun asParent () = exportFunEntry(navigation, this) 254 val expChild = exportList(exportFunEntry, SOME asParent) inf 255 in 256 (location, expChild @ exportNavigationProps navigation) 257 end 258 259 fun exportAClause( 260 FValClause{dec = {ident, isInfix, args, constraint}, exp, breakPoint = ref bpt, ...}, idVal, exportThis) = 261 let 262 (* The effect of this is to have all the elements of the clause as 263 a single level except that if we have an infixed application of 264 the function (e.g. fun f o g = ...) then this is a subnode. *) 265 val funAndArgs = 266 case (isInfix, args) of 267 (true, TupleTree{fields=[left, right], location, ...} :: otherArgs) => (* Infixed. *) 268 FunInfixed([FunPtree left, FunIdent(ident, idVal), FunPtree right], location) 269 :: map FunPtree otherArgs 270 | (_, args) => (* Normal prefixed form. *) 271 FunIdent(ident, idVal) :: map FunPtree args 272 273 val constraint = case constraint of NONE => [] |SOME typ => [FunConstraint typ] 274 275 val debugProp = 276 case bpt of 277 NONE => [] 278 | SOME bpt => [PTbreakPoint bpt] 279 in 280 exportList(exportFunEntry, SOME exportThis) (funAndArgs @ constraint @ [FunPtree exp]) @ debugProp 281 end 282 283 fun exportFB(navigation, 284 fb as FValBind{clauses=[clause], location, functVar = ref idVal, ...}) = 285 (* If there's just one clause go straight to it. Otherwise we have an 286 unnecessary level of navigation. *) 287 let 288 val fbProps = exportNavigationProps navigation 289 val asChild = exportAClause(clause, idVal, fn () => exportFB(navigation, fb)) 290 in 291 (location, asChild @ fbProps) 292 end 293 294 | exportFB(navigation, fb as FValBind{clauses, location, functVar = ref idVal, ...}) = 295 let 296 val fbProps = exportNavigationProps navigation 297 (* Each child gives a clause. *) 298 (* First child should give the pattern *) 299 (* Second child should give the expression *) 300 fun exportThis () = exportFB(navigation, fb) 301 302 fun exportClause(navigation, clause as FValClause{ line, ...}) = 303 let 304 val clProps = exportNavigationProps navigation 305 val asChild = exportAClause(clause, idVal, fn () => exportClause(navigation, clause)) 306 in 307 (line, asChild @ clProps) 308 end 309 310 val asChild = exportList(exportClause, SOME exportThis) clauses 311 in 312 (location, asChild @ fbProps) 313 end 314 315 val expChild = exportList(exportFB, SOME asParent) dec 316 in 317 (location, expChild @ commonProps) 318 end 319 320 | OpenDec{location, decs, ...} => 321 let 322 fun exportStructIdent(navigation, { value, location, ...} ) = 323 let 324 (* Include the declaration properties if it has been set. *) 325 val locProps = 326 case !value of 327 SOME(Struct{locations, ...}) => mapLocationProps locations 328 | NONE => [] 329 val siProps = exportNavigationProps navigation @ locProps 330 in 331 (location, siProps) 332 end 333 334 val expChild = exportList(exportStructIdent, SOME asParent) decs 335 in 336 (location, expChild @ commonProps) 337 end 338 339 | Constraint{location, value, given, ...} => 340 let 341 (* The first position is the expression, the second the type *) 342 fun getExpr () = 343 getExportTree({parent=SOME asParent, previous=NONE, next=SOME getType}, value) 344 and getType () = 345 typeExportTree({parent=SOME asParent, previous=SOME getExpr, next=NONE}, given) 346 in 347 (location, PTfirstChild getExpr :: commonProps) 348 end 349 350 | Layered{location, var, pattern, ...} => 351 (location, exportList(getExportTree, SOME asParent) [var, pattern] @ commonProps) 352 353 | Fn {matches, location, expType = ref expType, ...} => 354 (location, PTtype expType :: exportList(exportMatch, SOME asParent) matches @ commonProps) 355 356 | Localdec{location, decs, body, ...} => 357 (location, exportList(exportTreeWithBpt, SOME asParent) (decs @ body) @ commonProps) 358 359 | TypeDeclaration(tbl, location) => 360 let 361 val allItems = List.map TypeB tbl 362 in 363 (location, exportList(exportTypeBinding, SOME asParent) allItems @ commonProps) 364 end 365 366 | AbsDatatypeDeclaration { location, typelist, withtypes, declist, ... } => 367 let 368 val allItems = 369 List.map DataT typelist @ List.map TypeB withtypes @ List.map Decl declist 370 in 371 (location, exportList(exportTypeBinding, SOME asParent) allItems @ commonProps) 372 end 373 374 | DatatypeReplication{location, ...} => (* TODO *) (location, commonProps) 375 376 | ExpSeq(ptl, location) => 377 (location, exportList(exportTreeWithBpt, SOME asParent) ptl @ commonProps) 378 379 | Directive{location, ...} => 380 (* No need to process the individual identifiers. *) 381 (location, commonProps) 382 383 | ExDeclaration(exbinds, location) => 384 let 385 (* There are three possibilities here. exception exc; exception exc of ty; exception exc = exc' *) 386 fun exportExdec(navigation, ExBind{name, previous=EmptyTree, ofType=NONE, nameLoc, value=ref(Value{locations, ...}), ...}) = 387 (* Simple, generative exception with no type. *) 388 getStringAsTree(navigation, name, nameLoc, PTtype exnType :: definingLocationProps locations) 389 390 | exportExdec(navigation, 391 eb as ExBind{name, previous=EmptyTree, ofType=SOME ofType, nameLoc, fullLoc, 392 value=ref(Value{locations, ...}), ...}) = 393 (* exception exc of type. *) 394 let 395 fun asParent () = exportExdec (navigation, eb) 396 fun getName () = 397 getStringAsTree({parent=SOME asParent, next=SOME getOfType, previous=NONE}, 398 name, nameLoc, (* Type could be in here? *)definingLocationProps locations) 399 and getOfType () = 400 typeExportTree({parent=SOME asParent, previous=SOME getName, next=NONE}, ofType) 401 in 402 (fullLoc, PTfirstChild getName :: exportNavigationProps navigation) 403 end 404 405 | exportExdec(navigation, 406 eb as ExBind{name, previous, (* ofType=NONE, *) nameLoc, fullLoc, value=ref(Value{locations, ...}), ...}) = 407 let 408 fun asParent () = exportExdec (navigation, eb) 409 fun getName () = 410 getStringAsTree({parent=SOME asParent, next=SOME getPreviousExc, previous=NONE}, 411 name, nameLoc, (* Type could be in here? *)definingLocationProps locations) 412 and getPreviousExc () = 413 getExportTree({parent=SOME asParent, previous=SOME getName, next=NONE}, previous) 414 in 415 (fullLoc, PTfirstChild getName :: exportNavigationProps navigation) 416 end 417 418 val expChild = exportList(exportExdec, SOME asParent) exbinds 419 in 420 (location, expChild @ commonProps) 421 end 422 423 | Raise(raiseExp, location) => 424 let 425 fun getExp () = getExportTree({parent=SOME asParent, next=NONE, previous=NONE}, raiseExp) 426 in 427 (location, [PTfirstChild getExp] @ commonProps) 428 end 429 430 | HandleTree{location, exp, hrules, listLocation, ...} => 431 let 432 (* The first position is the expression, the second the matches *) 433 fun getExpr () = getExportTree({parent=SOME asParent, previous=NONE, next=SOME getMatches}, exp) 434 and getMatches () = 435 (listLocation, 436 exportList(exportMatch, SOME getMatches) hrules @ 437 exportNavigationProps{parent=SOME asParent, previous=SOME getExpr, next=NONE}) 438 in 439 (location, [PTfirstChild getExpr] @ commonProps) 440 end 441 442 | While{location, test, body, breakPoint, ...} => 443 (location, 444 exportList(exportTreeWithBpt, SOME asParent) 445 [(test, ref NONE), (body, breakPoint)] @ commonProps) 446 447 | Case{location, test, match, listLocation, expType=ref expType, ...} => 448 let 449 (* The first position is the expression, the second the matches *) 450 fun getExpr () = getExportTree({parent=SOME asParent, previous=NONE, next=SOME getMatches}, test) 451 and getMatches () = 452 (listLocation, 453 exportList(exportMatch, SOME getMatches) match @ 454 exportNavigationProps{parent=SOME asParent, previous=SOME getExpr, next=NONE}) 455 in 456 (location, [PTfirstChild getExpr, PTtype expType] @ commonProps) 457 end 458 459 | Andalso {location, first, second, ...} => 460 (location, exportList(getExportTree, SOME asParent) [first, second] @ commonProps) 461 462 | Orelse{location, first, second, ...} => 463 (location, exportList(getExportTree, SOME asParent) [first, second] @ commonProps) 464 465 | Labelled{location, expType=ref expType, recList, ...} => 466 let 467 (* It's convenient to be able to click on the label part and get 468 the type of the expression or pattern on the right of the '='. *) 469 fun exportField(navigation, 470 label as {name, nameLoc, valOrPat, expType=ref expType, fullLocation, ...}) = 471 let 472 val patTree as (patLocation, _) = getExportTree(navigation, valOrPat) 473 in 474 if patLocation = fullLocation 475 then 476 (* The parser rewrites { name, ...} as { name=name, ... } (more generally 477 { name: ty as pat, ...} as { name = name: ty as pat). 478 To avoid having nodes that overlap we return only the pattern part here. *) 479 patTree 480 else 481 let 482 (* The first position is the label, the second the type *) 483 fun asParent () = exportField (navigation, label) 484 fun getLab () = 485 getStringAsTree({parent=SOME asParent, next=SOME getExp, previous=NONE}, 486 name, nameLoc, [PTtype expType]) 487 and getExp () = 488 getExportTree({parent=SOME asParent, previous=SOME getLab, next=NONE}, valOrPat) 489 in 490 (fullLocation, PTfirstChild getLab :: exportNavigationProps navigation) 491 end 492 end 493 494 val expChild = exportList(exportField, SOME asParent) recList 495 in 496 (location, PTtype expType :: (expChild @ commonProps)) 497 end 498 499 | Selector{location, typeof, ...} => (location, PTtype typeof :: commonProps) 500 501 | List{elements, location, expType = ref expType, ...} => 502 (location, 503 PTtype expType :: exportList(getExportTree, SOME asParent) elements @ commonProps) 504 505 | EmptyTree => (nullLocation, commonProps) 506 507 | WildCard location => (location, commonProps) 508 509 | Unit location => (location, PTtype unitType :: commonProps) 510 511 | Parenthesised(p, _) => getExportTree(navigation, p) 512 end 513 514 fun getLocation c = #1 (getExportTree({parent=NONE, next=NONE, previous=NONE}, c)) 515 516 (* Extract the declaration location from the location list. *) 517 fun declaredAt [] = LEX.nullLocation 518 | declaredAt (DeclaredAt loc :: _) = loc 519 | declaredAt (_::l) = declaredAt l 520 521 (* Types that can be shared. *) 522 structure Sharing = 523 struct 524 type lexan = lexan 525 and parsetree = parsetree 526 and matchtree = matchtree 527 and locationProp = locationProp 528 and pretty = pretty 529 and ptProperties = ptProperties 530 end 531 532end; 533 534