GeeWhiz Prolog - Part Five - Adding The CompilerWednesday, May 21. 2008
This is Part Five, the sixth part of a series of entries describing an implementation of the Prolog language in the NetBeans IDE.
Part Zero, "About The Project," is here. Part One, "Before We Start," is here. Part Two, "Creating A File Type," is here. Part Three, "Adding Language Support," is here. Part Four, "A Visual Prolog Modeler" is here. What We'll Be DoingUp to this point we've created a Prolog editor within the NetBeans IDE with built-in syntax highlighting, navigation, a visual modeler, and some other stuff that I forget but that's probably pretty cool. Now we're going to add in-place compilation so we don't need to switch between NetBeans and whatever Prolog compiler we're using just to fix syntax errors and such. In this entry I'll be using SWI Prolog as my Prolog compiler. It's a free, robust open-source compiler that runs on multiple platforms including, probably, yours. One thing it does not have, however, is a feature-rich IDE -- hence this project. When we're done with this segment, we'll be able to compile our Prolog source code directly from the NetBeans IDE and hotlink (whatever that means) the error lines back to our source code. In other words, it will function much like the Java compilation process within NetBeans that we all know and love. By the way, if you currently use a different Prolog compiler, don't worry. Once we're done here it should be pretty obvious how to adapt this project to incorporate your favorite compiler as long as you can run it from a terminal command line. In fact part of the reason I'm writing this how-to is to allow you to adapt ANY language to the NetBeans IDE. I'm trying to assemble the knowledge that's scattered around the NetBeans universe in one place so that this series of articles gives you the ability to quickly and dirtily add your favorite language to the NetBeans IDE. We'll work on the "dirtily" part later; for now our goal is results, baby. Adding Compiler SupportAdding compiler support to GeeWhiz turns out to be surprisingly easy. It's easy if you know where to look for info, that is. It took me for-effing-ever to find the information I needed to do this, but once I did, implementing support for an external compiler turned out to be almost trivial. But I digress. The first thing we need to do is create an action in our project to invoke the compiler. Right-click on our GeeWhiz project and select "New" "Action". In the first screen of the New Action Wizard, once again select "Conditionally Enabled" and "User Selects One Node". Set the cookie class to "DataObject" since we want to only compile Prolog source files with our compiler. Hit the "Next" button.
On this screen, enter "CompileProlog" for a class name and "Compile Prolog Program" for a display name. For icons, you'll need both a 16x16 and 24x24 icon in the same directory, called (in our case) compile16.png and compile24.png, otherwise the wizard will grumpily issue error messages until you do. You can use these if you'd like, another modified Black Star of Prolog. Note: in the last screenshot ignore the GeeWhiz2 reference. I didn't make screenshots of this process the first time around, probably because I didn't expect it to work the first time! I thought I'd have to do 8 or 9 trials to get it right like I did for the other stuff in this project. Gee whiz, I must be learning something.... Once the wizard creates our new action, you can close the icon files in the editor and add the following lines to the CompileProlog class, where it says "TODO: use DataObject":
Save and close the file. Great. We have a toolbar action, now all we need to do is write a PrologCompiler class. So let's do that. Create a new Java class called "PrologCompiler" and replace the empty class with:
What we want this to do is invoke the SWI Prolog compiler with our source file, the name of which we retrieved from our trusty Prolog DataObject. We're using the IOProvider/OutputWriter we saw last time to write the output to the Output tab, just like a real adult language module does. We're also using ProcessBuilder to build a Process so we can execute an external command. Just a couple of other things worth mentioning about the above class: one is that I left in some comments showing how to access the environment and change the working directory, just in case you need the info to make your compiler work. Also, note that the command line I used is for the Linux version of SWI Prolog. If you run on another platform, you'll probably need to change this. For example, I believe Windows uses "plwin". See the SWI Prolog site for more information. Testing The First VersionSo let's try it: clean and build your main project and install to the target IDE. Open up the BraveNewWorld project. Wait until the excitement dies down. Open up sieve.pro. Add a line somewhere in the program that says:
This introduces an error in our otherwise nearly pristine Prolog program. Save sieve.pro. Find our new compiler button on the toolbar and click it.
The compiler also gives us a warning that there is a singleton variable in one of the clauses. This means that the variable "P" in the statement "remove(P,[],[])." isn't used. In Prolog, instead of using a named variable here you should use an anonymous variable, the underscore. If you want you can change the statement to read "remove(_,[],[])." and recompile it to see that the warning goes away. When you're done muttering "Gee whiz!" you can close the target IDE. Add Hotlinks (Whatever They Are)Now we're going to add hyperlinks to our compiler output so when you click an error line in the output you are magically transported to the source code at the point of the error. I know, you're saying "Gee whiz!" to yourself again. Just wait.... In trying to add this feature, I knew exactly what I wanted to do but I really wasn't sure how to accomplish it. Until, that is, I found an article called "Meet A NetBeans Module Writer: Jens Trapp". In the article is a code snippet that does exactly what I wanted to do in about three lines of code! Thank you Mr. Trapp; may the rest of your days be happy ones. Who knew there was a LineCookie that plunked you right down in the middle of the source code editor? Probably the people who RTFD, that's who.... But for the rest of us there's Hulles. So now we're going to change our PrologCompiler class to "hotlink" our compiler code to our source code. Open the class file and replace the class with this:
As you can see, we added an OutputListener that does the work of popping us into the editor at exactly the right place where the error is located. The parsing of the error / warning lines to get the line number and column number is ugly, but that's because A) I didn't want to have to relearn regular expression syntax for the umpteenth time, and B) I didn't have 244 Swiss Francs for the ISO Prolog error message standard so I was winging it from the SWI Prolog output. Actually, there are two ISO Prolog standards documents, so it would have been 488CHF. As if. I suppose I should also mention the StatusDisplayer line. This is one of those things that I couldn't resist putting in but that gets obnoxious very quickly. When you go to an error line, it displays "Fix me!" on the status line at the bottom of the IDE. Hah hah. So take it out, you don't like it. Testing The Final VersionOkay, let's give 'er a spin. Clean and build your project then install it to the target IDE as before. Open up the BraveNewWorld project. Wait. Open up sieve.pro. Unfix the error and the warning if you fixed them last time so we have something to work with. Click our "Compile Prolog" button on the toolbar.
So now we can compile our little Prolog hearts out in the NetBeans IDE. We still need to open SWI Prolog to run the stuff, but that's not so bad. It should be possible to connect up a Reader in the same way we did with the OutputWriter to allow the interaction, however. Hmmm.... You're welcome to do that if you want. I haven't yet, but I'm sure it's only a matter of time before I have to try it. If you do, let me know how it comes out. We now have a pretty decent Prolog IDE embedded within the NetBeans architecture. What's next? We're going to create a Prolog project template so we don't have to stick our lovely, elegant and erudite nonprocedural Prolog source code into an icky stinky Java class library, that's what's next. Stay tuned. Files From This EntryGeeWhiz Prolog - Part Four - A Visual Prolog ModelerTuesday, May 20. 2008
This is Part Four, the fifth part of a series of entries describing an implementation of the Prolog language in the NetBeans IDE.
Part Zero is here. Part One is here. Part Two is here. Part Three is here. What We'll Be DoingSo far we've created an editor for Prolog source code within the NetBeans IDE that supports navigation and syntax highlighting. Most of the previous stuff we've done can be found in other tutorials, but now we're going to branch out from there and explore some unknown territory. Specifically, we're going to build a visual predicate mapper for Prolog that will look like this when it's done: ![]() Frankly, I'm not sure how useful the mapper really is in actual Prolog programming, but so far I have used it to find missing references in Prolog code I wrote and to get an overview of code others have written. For these use cases the diagram thing really does come in handy. My starting point for this segment of the project was the excellent tutorial, "A Visual Database Explorer for NetBeans". Thanks to Toni Epple for providing a lot of useful information. I should also confess here that I'm far from an expert in the NetBeans Visual Library, but learning more about it is high on my to-do list. The library so far seems easy to use, featureful and well worth investigating further. Creating A First-Cut DiagramThe first thing we'll do is create a static sample diagram in GeeWhiz using techniques described in the Visual Database Explorer tutorial, so let's create a new action in the project. This action will add an item to the main menu that opens our diagram window. Right-click on GeeWhiz in the Projects tab and select "New" "Action".
In the next screen of the wizard,
Next we need to create a TopComponent, which is essentially a top-level window in the NetBeans IDE. Right-click the project again and select "New" "Window Component". This starts the New Window Wizard, as you might expect.
Now we need to edit some files, but first we need to add the Visual Library to our project. Right-click on the GeeWhiz project, select "Properties", and select "Libraries" as the category. To the right of the Module Dependencies window click the "Add" button to bring up the Add Module Dependencies window.
Notice that the last line is commented out. We'll add this back in later. Right-click in the class and select "Fix Imports" to fix up the import statements. Save and close the file. Now we'll edit the top component. Open VPrologTopComponent.java. In the design view, click on "Scroll Pane" in the Swing Containers palette and drop it onto the frame. Make it fill the frame. Then click "Panel" in the palette and drop it onto the JScrollPane you just created. Right-click the JPanel and change the layout to BorderLayout. Now you should have a design view that looks like this.
Now we're going to create a class to render the diagram. Create a new Java class called "VPrologGraphScene" and replace the empty class with the following code:
Fix imports (I love that thing!) then save and close the file. Next we need to add some icons to our project. The easiest way to do this is to download one of the project files at the end of this article and unzip / untar the archive to get the icons. Copy them directly into your project's /src/org/myorg/geewhiz directory. As a final step, we're going to go into Bundle.properties in our project then right-click on one of the properties and select "Edit". This file is where descriptions and such are kept. Edit the descriptions of the properties as follows (or make up your own):
Testing The First-Cut DiagramNow it's time to test our changes. Clean and build the main project then install it into the target IDE (see earlier steps for instructions on doing this). When the installation completes and your personal domain is created, open the BraveNewWorld project. Let it index its little heart out then open fib1.pro. As a first step in testing, make sure everything that worked before still works. Click in fib1.pro and make sure the Navigator syncs with the editor pane and that the syntax is colored as it was before. Now go up to the menu and click "View". Our new menu item, "Show Prolog Diagram" should be there and be enabled, complete with icon.
Adding Prolog Structure Analysis To The DiagramNow that we can display a sample visual model, let's add Prolog support to the project. First we're going to create a Java data structure class to represent a Prolog clause and its attributes. Create a new Java class off your package node in the project and call it PrologClause. Replace the empty class with this:
Fix imports and save it. The class we just created is pretty straightforward. A Prolog clause is identified by its name and its arity. Arity is a Prolog term that means argument count. All clauses with the same name and same arity are considered part of a single predicate, traditionally denoted as name/arity. Thus, all the clauses in our fib1.pro code are instances of a single predicate, fib/2. In our PrologClause class, we're storing the name, arity, text body, and a count of clauses that comprise the predicate in the source code. See what's wrong? I misnamed the class -- it should have been PrologPredicate, since we're not generating an instance for each clause, only for each predicate. I promise I'll go back and change it One Day Soon. But for now, let's go on. You will also see in this class a list of clauses mysteriously called body. This is another unfortunate name, but what it represents is a list of predicates that are "called" by this predicate in one or more of its clauses, either in the arguments to the clause or in the body of the clause itself. To give you an example, take the following nonsense Prolog source code file:
some_list_function(A,B,C) :- another_function(A,B), do_something_else(B,C). some_list_function(param_function(A,D),B,C) :- B is C. This would generate one PrologClause object, with a name "some_list_function", an arity of 3, an instance count of 2 (there are two clauses), the text that is typed above, and a body list consisting of another_function/2, do_something_else/2, and param_function/2. As you can see, the body list resembles a list of functions called by this predicate. Now we need some code that creates the PrologClause objects we just defined. Create a new Java class and call it PrologAST. Copy the following code into it:
This is a obtuse little class, but in general what it does is search the AST for Prolog clauses and deconstructs them into predicates, then builds PrologClauses for them if they don't exist yet or increments the count if they do. Text for each clause in a predicate is added to the PrologClause, and any foreign clauses called with the current clause are added to the body list. When we're done searching the AST we have a nice little group of predicates ready to diagram. Note: this AST is of course the same one that appears when you click "AST View" in "Window/Other" that we looked at earlier. If you want to compare the text output of PrologAST to the AST view of fib1.pro, the code makes a lot more sense. Plus you can see how I was able to write the class in the first place. A couple of things in PrologAST are worth examining more closely. The IOProvider/OutputWriter stuff has not been introduced yet in this series, but what it does is create a "Prolog" output tab and writes to it. Technically I shouldn't be hanging on to the OutputWriter by declaring it at the class level, but it works for now and I'll probably end up getting rid of the text output entirely anyway. When I'm sure it works correctly. Probably the same day I rename PrologClause to PrologPredicate. Another thing to note is the ParserManagerImpl class in getASTRoot. I needed to obtain the root AST node somehow, and the only way I could readily find is by using ParserManagerImpl, which unfortunately is not part of the API. This one line causes us to use an implementation version of the GLF, a process I have to describe below. If anyone knows of an API way to get the root AST node, please let me know so I can get rid of the versioning and use the public API. There is essentially no documentation for the whole GLF, so finding something like that is a non-trivial task. Trust me. To get rid of the red squiggles in the source code, we need to add some module dependencies to our project. Right-click on the project, select libraries, and click "Add Module Dependencies". Add the "Editor," "Editor Library," and "IO APIs" libraries. (You have to add them one at a time.) Now, as mentioned above, we need to change the Generic Library Framework to use an implementation version, as opposed to the public API. In your project, find "Generic Libary Framework" in "Libraries", right-click it and select "Edit".
Now we need to edit VPrologGraphScene to use our new predicate objects. Open it up and add the following code right below the first constructor:
The new constructor grabs the list of PrologClause (predicate) objects and constructs pretty little images on our diagram using the same createNode etc. methods as before. For the entire program, see the archive files at the bottom of the entry. Fix imports if necessary and save and close the file. Next, we have to change VPrologTopComponent to call the new constructor with a passed DataObject. Open it and add the following method to the class:
Notice that we still have the VPrologGraphScene constructor without arguments called in the top component constructor. Our old friend VPrologAction will still call that, so we can test the functionality of the modeling without invoking PrologAST if necessary. Now we need to edit ShowDiagram, so open it up and remove the slashes on the win.loadProlog line to uncomment it. Now we should be ready to rock and roll. Testing The Prolog ModelNow you should clean and build the main project then install it in the target IDE and open the BraveNewWorld project. Open up our old buddy fib1.pro and then go to the menu and select "View" "Show Prolog Diagram". You should see something like this.
Save the file and perform "Show Prolog DIagram" from the menu again. You should get this.
Well, we're done with this segment. We now have a Prolog IDE complete with fins and an automatic headlight dimmer. What we need next is in-place compilation so we don't have to continually switch between NetBeans and our Prolog compiler. You got it -- it's coming next. In the meantime, if you want you can alter PrologAST to not print the informative text, and you can delete VPrologAction.java. If you delete VPrologAction, be sure to also delete the actions in layer.xml ("this layer" then delete the instance in "Actions" "Window" and the shadow in "Menu" "Window"). Files From This EntryGeeWhiz Prolog - Part Three - Adding Language SupportMonday, May 19. 2008
This is Part Three, the fourth part of a series of entries describing an implementation of the Prolog language in the NetBeans IDE.
Part Zero is here. Part One is here. Part Two is here. What We'll Be DoingLast entry we constructed a simple text editor for Prolog source files in the NetBeans IDE. Now we're going to add "language support" for the Prolog editor, which means that the Navigator window works with the Prolog source and the Prolog syntax is colored and highlighted in our editor. Sounds simple, yes? Remember what Wittgenstein said: "Philosophische Probleme entstehen, wenn die Sprache feiert." ("Philosophical problems arise when language takes a vacation," loosely translated.) Once again, the procedures in this entry are mostly derived from two NetBeans tutorials, the NetBeans Platform Schliemann Tutorial and Quick Start: Creating Language Tools in NetBeans IDE, and once again, thanks to both authors for their articles. Add Language SupportThe first thing we're going to do is add the language support framework to our project. Right-click on "GeeWhiz" in the project tab and select "Properties."
Adapt Language Support to PrologNow we're going to create language support for Prolog using our new framework. Right-click "GeeWhiz" in the Project tab and select "New" "Language Support".
The Prolog syntax stuff we just put into our language.nbs file comes from the Schliemann tutorial, and I will be eternally grateful to the author that I did not have to research Prolog syntax and type out the grammar, particularly the list of built-in functions. See that tutorial for an explanation of what everything does.
Now we need to create a new Java class called PrologNBS.java. Right-click the "org.myorg.geewhiz" package in our project and select "New" "Java Class". In the New Java Class window, name the class "PrologNBS". Make sure the package line is filled in then click the "Finish" button. A new class will be created and opened in the editor. Replace the class definition with the following:
Your class file should now look something like this:
Now we are going to add an icon to our editor. Expand "layer.xml" and "this layer" and go to "Editors" "text" "x-prolog" and right-click "language.nbs" and select "Open Layer File(s)".
Note: you should replace "org/hulles..." with "org/myorg..." in the layer file addition above. (Thanks, Robert.) Your edited layer file should now look like this: Presto -- our editor has the dreaded Black Star of Prolog associated with it. Save and close the layer.xml file. Test Language SupportAt this point you should clean and build your main project (GeeWhiz) and install it to our target IDE. See the previous entry for instructions on doing this. Once the target IDE is up, open up our target project called BraveNewWorld and wait for all the indexing to die down. Once all is quiet in the target IDE, select the fib1.pro file in the BraveNewWorld project and open it. You will see (eventually) that the syntax is highlighted and colored in our little Prolog file.
Before we leave the target IDE, go to the main IDE menu bar and select "Window" "Other" "Token View".
Files From This EntryGeeWhiz Prolog - Part One - Before We StartSunday, May 18. 2008
This is Part One, the second part of a series of entries describing an implementation of the Prolog language in the NetBeans IDE. Part Zero is here.
Set Up Your Development EnvironmentThe first thing you should do if you haven't already is install NetBeans 6.1 IDE. Most of the stuff here will work with older versions of NetBeans, but much of it will look differently and some of it will function differently, so bite the bullet and upgrade if you haven't already. Once you have it installed, you should fire it up and install the latest upgrades to the plugins. NetBeans should tell you that there are updates available and will install them if you tell it to. It would also be a good idea to play around with it a little bit just to see how it works and maybe create a simple Java application or two. The world is waiting for you to say hello. Next you should install SWI Prolog on your machine. This step is optional, but if you want to follow along with the last part of this adventure, you'll need it. If you're running Debian or Ubuntu Linux, SWI Prolog is available in the repositories, otherwise you can download it from the SWI Prolog site. You might also play with this a bit. If you're new to SWI Prolog, you can start it from the Linux command line by typing "swipl". You can exit SWI Prolog by typing Ctrl-C then e. That tip right there just saved you about a half-hour of research, by the way. Pare Down The NetBeans IDENow you should make your installed NetBeans IDE leaner and meaner. Uninstall as many plugins from your version of NetBeans as you feel comfortable with, then uninstall a couple more. Pare it down as much as you possibly can, because for much of this how-to you will be running not one, but two instances of the IDE. We will be running both a development instance and a target instance of NetBeans as we are testing GeeWhiz, and unless you're developing on a Cray supercomputer you'll want to speed up the loading and unloading of the IDE as much as possible. Otherwise you'll end up eating many snacks while you're waiting for the IDE to start and put on unwanted pounds and actually start responding to the quick-weight-loss spam email you keep getting, and we don't want that, do we? No we bloody well don't. Check Out The GiantsAs I said in Part Zero, I stand on the shoulders of giants. If you want to check out the big guys, first go to the NetBeans Platform Learning Trail. This page is a good starting point for learning how to extend the NetBeans IDE, which is what we'll be doing. Just FYI, so-called "Rich Client Programming" applications are ones that use the NetBeans platform for a user interface on top of a stand-alone system that may or may not have anything to do with programming languages. We are not building a "Rich Client Programming" application in this how-to. Our application, GeeWhiz Prolog, will be incorporated into the IDE itself so we can use all the goodies that are laying around and switch back and forth between Prolog and other kinds of projects without restarting the IDE. See snack comment, above. This project initially began when I ran across an article called NetBeans Platform Schliemann Tutorial while searching for an existing Prolog IDE in NetBeans. In this tutorial the author laid much of the groundwork for GeeWhiz and provided the starting point for this project. You might want to hold off actually doing the tutorial, however, as we will be incorporating a modified version of much of the content into GeeWhiz. Another tutorial to take a look at is the article Quick Start: Creating Language Tools in NetBeans IDE. This is what I used to get my feet wet with adding a language to the NetBeans IDE. It's good and it's quick. Check it out, and go ahead and do it if you want. Yet another tutorial to which I owe a big debt of gratitude is the excellent A Visual Database Explorer For NetBeans. Take a look at it, but you might want to hold off on doing this one as well since we'll be hacking it later. You'll like it when we do -- "Gee whiz!" GeeWhiz Prolog - Part Zero - About the ProjectSaturday, May 17. 2008
WelcomeThis is the first entry in a (planned) series of blog posts about creating an integrated development environment (IDE) for Prolog programming using the NetBeans IDE. The purpose of these blog entries is primarily to show how to create a functional editor, diagrammer and compiler wrapper for the Prolog programming language, and secondarily to explore some of the very cool features of the NetBeans IDE. What's Prolog? What's NetBeans?Right off the bat, I want to define my terms so you know if you ended up in the right place via your search engine:
Prolog is a programming language commonly used in artificial intellligence applications, natural language processing and expert systems. This blog won't really be addressing Prolog as a programming language per se, although I'll be talking about the language in passing as it pertains to the implementation of the IDE. The Prolog implementation I'll be using for this project is SWI Prolog, a free product that I respect tremendously. If you're going to work along with me as I build the GeeWhiz IDE, you might consider downloading it, although this is not a requirement. Who Am Us, Anyway?I should at this point confess that I'm not an expert with the NetBeans IDE, nor am I an expert Prolog programmer. I used to do a great deal of programming in Prolog, back in the days when Borland released Turbo Prolog, a successor to their very popular Turbo Pascal product. Ah, those were the days. Now I've forgotten most of what I knew about Prolog; this project resulted in part from my desire to reacquaint myself with the language. It also resulted from a desire to experiment with the new NetBeans version 6.1. Some very interesting things resulted from this experimentation, as you will see. Why Prolog?One of the nice things about using Prolog as a language around which to build an IDE is that the syntax is pretty simple and straightforward, relatively speaking. In absolute terms, however, parsing the language can present a few challenges, which we will gracefully surmount in later installments. Actually, the surmounting wasn't graceful at all, to tell you the truth. Much hacking and swearing and throwing of hamsters went on while I tried to figure the stuff out, but when I present it here, it should look as if I knew what the hell I was doing all along. Heh heh. Is This A Tutorial? Can I Follow Along?Hell yes, you should follow along, but this blog series won't really be a tutorial on NetBeans language implementation because I want this to be accessible to the experienced programmer who isn't all that familiar with the NetBeans IDE. I have discovered that much of the official NetBeans documentation assumes that you already know what the hell is going on under the hood. I certainly didn't know much about how the IDE works, at least when I started this project, so I thought I'd pass along what I learned as a help to others in my position. To that end, I will be discussing my own experiences more than should really be the case in a tutorial, including revealing (some of) the many mistakes I made in hacking this creature called GeeWhiz Prolog. And yes, hacking is the right verb. I haven't studied (for example) the Visual stuff in NetBeans any more than I need to get GeeWhiz up and running. In other words, I know just enough to be dangerous. But if I had tried to become an expert, I'd still be studying months from now, and I have real work to do in the meantime. So I stand on the shoulders of giants (see tutorial references later) and only occasionally jump up and down on their heads. Even so, I think GeeWhiz came out pretty well. For hacking. Isn't This Just A Rehash Of Other Tutorials?I suppose in a way this is just a mashup of other information that's already out there. However, what I am bringing to the table is that I put all the information you need to start implementing a new language in NetBeans in one place. That be here, baby. If you don't believe me, do what I did and search NetBeans.org (and the rest of the Internet) for instructions on language support in NetBeans. Most of the pieces are there, but I haven't found anyplace where they are all assembled and integrated, especially in the form of the step-by-step how-to (or, sometimes, how-not-to) that I have tried to create here. You're welcome. See "donate" button. What Do I Need To Create GeeWhiz Prolog Myself?You should have an installed version of NetBeans 6.1, which you can get by following the link on the graphic above. You don't absolutely need SWI Prolog installed, but you should consider it as I mentioned above. You should also have had some experience in Java programming. While I am going to assume you know little about the NetBeans platform, I am going to bypass explaining a lot of the Java code I include. This is mostly because I imagine that you probably know more about Java than I do. I consider myself an intermediate-level Java programmer on a good day, and I haven't been having so many good days lately. I Run On A Linux/Mac/(shudder)Windows Platform. Can I Construct GeeWhiz Prolog?The platform I've been using to develop GeeWhiz is a creaky old Ubuntu Linux machine code-named Aspen. However, I'm happy to report that both NetBeans and SWI Prolog are multi-platform products. Windows users should be able to run the stuff you see in this GeeWhiz blog series just fine, and Mac users will probably be okay too. You should let me know if that isn't the case, just for future reference. I Have A Comment...Speaking of letting me know, I hope you'll pass along any comments you may have on the project. In fact, I'll be including a bunch of questions I have myself as we go, which perhaps some of you can answer. What Features Does GeeWhiz Prolog Have?Good question. Glad you're paying attention. When you're done with this series, you will have implemented an environment within NetBeans that includes:
Of cours |
In this article we will be creating a new NetBeans module for editing Prolog source code files. This module will eventually be part of our NetBeans IDE, just like any of the other modules for supporting languages like C/C++ or JavaScript. The procedures in this entry are mostly a mashup of two NetBeans tutorials, the NetBeans Platform Schliemann Tutorial and Quick Start: Creating Language Tools in NetBeans IDE. My heartfelt thanks go out to both authors for getting me started on this project. The adaptations I've made here are minor, and mostly just involve me getting my thumbprints on the stuff.
When we're done with this entry, we will have a functioning Prolog source code editor, albeit without navigator support and syntax highlighting. We'll add the language support in the next installment. Woohoo! No more Emacs for editing Prolog source!
First we're going to create a new project in NetBeans. If you don't already have a folder where you want to keep your NetBeans projects you should create one. Mine is called Java_Projects, as you will see in the screenshots. I recommend that it not be called NetBeansProjects in your home directory. This is the default project folder name for the NetBeans IDE, and later on we will let NetBeans create that folder where we will be storing projects that we create in the target instance of the IDE.
Start NetBeans and click "File / New Project" on the main menu bar.
![]()
In the "New Project" window, select the category "NetBeans Modules" and under Projects select "Module" and hit the "Next" button.
On the next screen, enter "GeeWhiz" for the project name and adjust the project folder as necessary.
![]()
Make sure "Standalone Module" and "Set as Main Project" are checked, and hit the "Next" button.
On the next screen, change the code name base to something like "org.myorg.geewhiz". For the module display name, enter "GeeWhiz Prolog".
![]()
(In the screenshot I just called it GeeWhiz but later I went back and changed it to GeeWhiz Prolog.) Leave the localizing bundle and XML layer fields alone and click "Finish".
Let NetBeans crank for a while and you should end up with something that looks like this:
![]()
Congratulations. You have a new module project. Now let's put stuff in it.
The first thing we will be adding to our new project is a new file type that describes our Prolog source code files. NetBeans will use this new file type to grok that a Prolog file you open should be associated with all the cool stuff we'll be adding to the IDE later. So right-click on "GeeWhiz" in the "Project..." tab
![]()
and select "New" and "File Type".
On the first screen of the new file type wizard, under "MIME Type" enter "text/x-prolog" and in the "Extensions" field type ".pro".
![]()
Technically, Prolog files ought to have ".pl" as a suffix but we don't want to confuse them with Perl files so we'll use ".pro" instead. Hit "Next".
On the next screen of the wizard enter "Prolog" for the "Class Name Prefix".
![]()
The wizard will use this as a prefix for all the files it is about to create. For an icon, you can either scrounge up a 16x16 icon on your own system or use the one I used:
Right-click the image here and save it on your own computer somewhere, then put the path and file name where you saved it into the wizard. Don't save it in your project folder; the wizard will copy it in there itself.
Now make sure in the "Project" field it says "GeeWhiz" and in the package field it says "org.myorg.geewhiz". Then hit "Finish" and NetBeans will go crazy adding files to your project. When it's done, close all the files (you can right-click the tab of one of them and select "Close all documents") and your project should look something like this.
![]()
One of the files that was just created is called "PrologTemplate.pro". This is the template that will be used to create new Prolog files. Open this file
![]()
and replace the contents with the following:
/*
* Prolog Source File ${name}
* created ${date} at ${time}
* created by ${user}
*/
% fibonacci(0) = 0
% fibonacci(1) = 1
% fibonacci(2) = 1
% fibonacci(n) = fibonacci(n-1) + fibonacci(n-2)
fib(0,0).
fib(1,1).
fib(2,1).
fib(N,F) :-
N > 2,
N1 is N - 1,
N2 is N - 2,
fib(N1,F1),
fib(N2,F2),
F is F1 + F2.
This sample Prolog file is, by the way, slightly adapted from the Schliemann tutorial. I couldn't resist adding the definition of fibonacci(0), which is 0. Also, you can ignore the variables in the comment such as ${name} for now. Later I want to use freemarker to fill these fields in but I haven't figured out how to make it work yet.
Now we're going to add a small HTML file that describes our new Prolog files. Right-click your package ("org.myorg.geewhiz") and select "New" "HTML file".
![]()
In the HTML file creation wizard,
enter "PrologTemplate" for the file name. The project field should be filled in already; the folder field should refer to your package ("src/org/myorg/geewhiz"). You should make sure it is filled in in your wizard. It should be there automatically if you right-clicked the package instead of the project, but if not you should select it from the drop-down. Click "Finish" and a new PrologTemplate.html file will be created and opened for you.
In the PrologTemplate.html file,
![]()
you should add the following lines between the "body" and "/body" tags:
Create a sample Prolog source file. Prolog is an interpreted language
used for artificial intelligence applications, e.g.
Once you've done that, save and close the file. Now we're going to edit the "layer.xml" file to associate our new description file with the template. we created. In the project window, find "layer.xml" and expand it.
![]()
Under "this layer", find "Templates" "Other" "Empty prolog file" and right-click it, then select "Open Layer File(s)". Under the element that says "file name=PrologTemplate.pro..." insert the following line:
<attr name="templateWizardURL"
urlvalue="nbresloc:/org/hulles/geewhiz/PrologTemplate.html"/>
Change "org/hulles" to "org/myorg" and save and close the file. Next, since the new Prolog file being created from our template isn't really empty, we're going to change the bundle property that describes it. In your project,
![]()
expand "Bundle.properties" and "default language" and right-click "Templates/Other/PrologTemplate.pro" and select "Edit". Change the line
![]()
for "Templates/Other/PrologTemplate.pro" to say simply "Prolog File", then save and close the "Bundle.properties" file.
Now we're going to test what we've done so far. In the IDE menu, click "Build" "Clean and Build Main Project" and wait until it says "Build Successful" in the output window. Then right-click the GeeWhiz project
![]()
and select "Install / Reload in Target Platform". This will install and open a new (target) version of the IDE with our module in it for testing. If you've never, ever, ever made a mistake in your life (hah - we know about that long weekend in Vegas) you can try "Install / Reload in Development IDE", which is much faster since the module is installed right where you're currently working. The disadvantage to this is that if you've screwed anything up, it can trash your development IDE and you'll possibly have to reinstall NetBeans to fix it. I know this from painful experience, so take my advice and always install to the target platform even though it means there will be two instances of the IDE running while you're testing.
While your new target IDE is loading, you'll see all kinds of messages in the devel IDE output box, which you can pretty much ignore unless you experience problems. In the Target, it should eventually say "Finished deploying test module", then "Creating personal domain...".
![]()
Wait for it to finish creating your personal domain, whatever the hell that is, then you're ready to test the new stuff.
For starters, create a brand new project in the target. From the target menu, select "File" "New Project" then in the wizard select "Java" "Java Application"
![]()
and click "Next". In the next window,
![]()
enter "BraveNewWorld" for your project name and let the folder default to the NetBeansProject folder in your home directory. Check "Create main class" and "Set as default project", then click "Finish". The target IDE should now contain the BraveNewWorld Java project. Actually, this project can be any kind of project, we just need one in which we can create new files for now. Later we'll build our own project template for Prolog. By the way, once you add the Java project the target IDE starts indexing all kinds of shit in the background. For performance reasons, you might want to wait until the indexing is done to proceed to the next step.
Now we'll create a new Prolog file in our project. In the target menu bar select "File" "New File..." to start the new file wizard.
![]()
In Categories, select Other, then select Prolog file. You should see something resembling the screenshot, with the official GeeWhiz Black Star of Prolog icon next to the Prolog file selection and the description we stuck in PrologTemplate.html in the bottom box of the wizard. Cool, eh?
Now click the "Next" button to travel to the next screen.
![]()
For the file name, type "fib1". Make sure the bravenewworld package is selected, then click "Finish". Voilą! Out pops our sample Fibonacci Prolog program, ready to be edited. Give yourself some time to say "Gee whiz! I made that." When you're done, close down the target IDE and return to the devel IDE where we're creating our project, because next we're going to add "language support" to our project so that the navigator works with our file and syntax is (more or less) correctly highlighted. Congratulations.
I'm going to take a couple minutes and tell you a little about why I'm doing things the way I am in this how-to series as regards the target IDE. I will be having you clean and build your main project in every case prior to installing to the target IDE. This destroys any target IDE instance you may have created earlier since it cleans the testdir directory. This is a good thing, since in my experience reloading to a target IDE I created earlier almost always causes some sort of weird problem. What this means, though, is that every target IDE starts ab ovo and doesn't remember anything about the last time it was installed. It reminds me of the classic soap opera character with amnesia, to tell you the truth: "Jeez, I didn't know I was married!" That is why we created our target project BraveNewWorld in the default directory, so we don't need to tell the IDE every time where our project directory is located.
And speaking of that, if anyone knows how to tailor the target IDE separately from the devel IDE, please let me know. I have not yet been able to find out where that is documented.
In this section, I'll just mention a few of the errors I made while working with the material in this entry, numbered from 0 in true geek fashion.
#0:I originally tried to install to the devel IDE, as I told you not to do above. Doh! It worked fine the first few tests, but then I screwed something up (the layer XML file I think) and crashed NetBeans. I had to reinstall NetBeans and start all over, sadder but wiser.
#1:I had a hell of a time trying to figure out what was up with the layer XML file, based on the tutorials I mentioned. It seems NB 6.1 must be a little different from what the tutorial authors were using, or at least nobody actually said you had to right-click the element of interest and select "Open Layer File(s)". I kept trying to just plain open the element and all I got were property sheets that resembled in no way what the authors were talking about. Doh! Since I'm mentioning it, under "layer.xml" in the project you'll see "this layer" and "this layer in context". "This layer" refers to the layer.xml elements that are actually being modified by our project. "This layer in context" refers to all IDE layer.xml elements, with the ones modified by our project in bold type. This is very useful as you get more familiar with the layer.xml stuff. I am still learning a lot about it.
#2:When I first tested the above stuff, I couldn't for the life of me figure out why I couldn't get a new file description in the new file wizard from PrologTemplate.html. It turned out I created the file in the source directory of the project, not in the "org.hulles.geewhiz" package, so it wasn't being found. Doh! That's why I emphasized that the package should be shown in the Create New HTML File wizard earlier.