a query-based code browser
 
Home
Download
Papers
Screen Shots
Contact
 

More Examples

< ^ >

This section contains more advanced examples on how to extend JQuery's functionality with new rules and menu items. Make sure that you have read the TyRuBa tutorial and understand how predicates, rules, and modes work.


Example 3 - Writing Rules

In this example, we will write several new TyRuBa rules and load them into JQuery using a rules file. The starting point for this example will be having a query tab for JHotDraw open and the code parsed.

  • First, we will create the rules file itself by creating a file called example3.rub and opening it in a text editor. The first rule we will write is a simple rule that is true whenever a method is static.

  • Write the following predicate declaration in the example3.rub file:

    staticMethod :: Method
    MODES
    (F) IS NONDET
    END

    This lets TyRuBa know that there is a predicate called staticMethod whose argument is a Method, and when the argument is unbound, zero or more results can occur.

    Then write the actual rule after the predicate declaration.

    staticMethod(?M) :- method(?M),modifier(?M,static).

    This rule says that "staticMethod is true if its argument is a method and the argument has a static modifier".

  • Finally, save the example3.rub file.

We will now write a more complicated rule that is recursive in nature. It will retrieve all of the methods that a given method calls, and all the methods that that method calls, etc. sort of like a "Call Hierarchy".

Note: this implementation of "Call Hierarchy" will only work for code in which there is no recursion (direct or indirect). An implementation of the rule could be constructed that checks for recursion, but it would be more complicated. This rule is just an example of writing a recursive rule in JQuery.
  • Put the following predicate declaration in the example3.rub file:

    callHierarchy :: Block, [Callable]
    MODES
    (B,F) IS NONDET
    END

    This tells TyRuBa that callHierarchy has two arguments: a Block (method, constructor, or initializer), and a list of Callables. We want a list so that we can construct a hierarchical view (JQuery will display nested lists as a tree). Recursive rules do not have to use lists, we could just as easily used a normal variable and had all the results displayed with no hierarchy. The mode information tells the mode checker that we only want to allow execution if the first argument is bound and the second argument is either free or bound. We also tell it to expect 0 or more results.

  • Now we write the actual rule. There will be two rules this time, one for the base of the recursion, and one for the recursion.

    callHierarchy(?Caller, []) :- Callable(?Caller), NOT(calls(?Caller,?,?)).
    callHierarchy(?Caller, [?Called | ?CalledHierarchy]) :- polyCalls(?Caller,?Called,?), callHierarchy(?Called,?CalledHierarchy).

    The first rule says that callHierarchy is true when the second argument is an empty list and ?Caller is a callable and no calls are made from ?Caller to anyone, anywhere (the single "?" is an ignored variable).

    The second rule says that callHierarchy is true when ?Caller calls (polymorphically) ?Called (which is the first element of the list) somewhere, and the callHierarchy ?CalledHierarchy (the rest of the list) exists for ?Called as well.

  • Save the example3.rub file.

Finally, we will load the rules file into JQuery and run a query using the new rules that finds the Call Hierarchy for all of the static methods in JHotDraw. To do this we:

  1. Select Manage Rules Files -> Working Set Rules Files from the drop-down menu ().

  2. Add example3.rub to the list by clicking on the Add... button and selecting it from the file chooser dialog.

  3. Click OK.

  4. Now reload the working set's rules by clicking on the icon.

  5. Right-click in the tree subtab of the query tab and select New Top-Level Query...

  6. Write the following query in the query box:

    staticMethod(?M),callHierarchy(?M,?H)
  7. Make sure the order of the variables is ?M then ?H.

  8. Click OK. Now we can navigate the call hierarchies of all the static methods.


Example 4 - Extending JQuery with new Menu Items

JQuery's menu system is constructed by querying on menu facts that are in the factbase and is therefore extensible by asserting new menu facts into JQuery using a rules file. You can add new menu items, remove ones that you don't want, or change existing ones. If you want to change the built-in JQuery menus, edit the menu.rub file that is in the plugins/ca.ubc.jquery/rules directory in Eclipse. It is recommended that you make a backup of this file before editing it though. It is not necessary to edit this file to add additional menu items, just to change old ones.

In this example, we will add new menu items for the rules that we wrote in the previous example.

  • Load up example3.rub in a text editor.

  • First we will assert two "pasteSnippet" facts into JQuery's factbase which are used to populate the pop-up menu that you get when you right-click on the query text field while you are editing a query. Add the following to your example3.rub file:

    pasteSnippet("staticMethod(?M)","?M is a static method").
    pasteSnippet("callHierarchy(?M,?Hierarcy)","?Hierarchy is a representation of all of the calls that can occur as a result of calling ?M").

    This will add 2 new entries to the pop-up menu that will display as "staticMethod(?M)" and "callHierarchy(?M,?Hierarchy)". The format of the pasteSnippet predicate is as follows:

    • The first argument is the name that will show up in the pop-up menu as well as what will be pasted into the query text field when you select it.

    • The second argument is a description of the entry.

    Try reloading the rules file (), creating a query, and right-clicking on the query text field. The two new entries will be in the menu.

  • Next, we will assert a "topQuery" fact that will add a new Static Method Browser to the available top-level queries. Add the following to your example3.rub file.

    topQuery("Static Method Browser", "staticMethod(?M), method(?C,?M), package(?C,?P)", ["?P","?C","?M"]).

    This will add a new "Static Method Browser" entry to the "Available Top Level Queries" menu. The format of the topQuery predicate is as follows:

    • The first argument is the name that will be displayed in the menu for the query

    • The second argument is the actual query that will be performed.

    • The final argument is a list that is similar to the "Order of Variables" section in the query editor. Put the variables as they appear in the query, in the order that you want them to show up in the results. If you want to ignore a variable, omit it from this list.

    Try reloading the rules file (), right-clicking in the tree subtab of the query tab, and going to Available Top-Level Queries. The new "Static Method Browser" will be there now. Try running the query and see that a browser containing all the static methods appears.

  • Finally, we will assert two "menuItem" rules that will add new entries into the context sensitve menu for querying for static methods of a type, or getting the call hierarchy of a callable. Add the following to your example3.rub file:

    menuItem(?this,["Members","Static Methods"], "staticMethod(?M),child(?this,?M)", ["?M"]) :- Type(?this).
    menuItem(?this,["Calls","Call Hierarchy"], "callHierarchy(?this,?hierarchy)",["?hierarchy"]) :- Callable(?this).

    This will add a "Static Methods" entry to the "Members" menu for types, and a "Call Hierarchy" entry to the "Calls" menu for callables. To format of the menuItem rule is as follows:

    • The first argument is always ?this

    • The second argument is a list that defines the menu structure. For example, ["Calls","Call Hierarchy"] defines the Calls -> Call Hierarchy menu item.

    • The third argument is the actual query. Remeber that ?this is a special variable that is bound to whatever you run the sub-query on.

    • The final argument is a list that is similar to the "Order of Variables" section in the query editor. Put the variables as they appear in the query, in the order that you want them to show up in the results. If you want to ignore a variable, omit it from this list.

    • The "rule" part of the rule defines when this menu item will appear. For example, the Calls -> Call Hierarchy is only applicable for callables, so we write Callable(?this) to enforce this.

    Try reloading the rules file () and right-clicking on a method or a type. The new menu items will appear.

 

< ^ >