======================================================================= 1 === Date: 02 Jan 1995 09:50:26 GMT From: jojo@strawinsky.informatik.rwth-aachen.de (Joachim Bausch) Subject: pickle Dear Modula-3 users: I have encountered a problem with Pickle. I would like to write a graph-structure to disk using a simple call to Pickle.Write. I have taken the required precautions such as explicit branding and no procedure variables. The program will crash while trying to execute that call with the following message: sendsig: bad signal stack pid=17614, sig=11 sigsp = 0x2aa8c8, action = 0xef020ba0, upc = 0xef6ba544 [2] + illegal instruction adt Running the program in gdb will yield the message: Program received signal SIGSEGV, Segmentation fault. 16_ef6af6cc in ThreadPosix.XRelease (m=???) at ThreadPosix.m3:438 ThreadPosix.m3:438: No such file or directory. So I suppose that the program crashes somewhere in a run-time library. Does anuone have any idea what I could do about the problem? Is there any obvious mistake I could have made? I need to use NetObjects and I understand that they use Pickle, too. So I cannot really work around that point. My system's configuration is: m3-3.3 on a SPARCstation 10 with SUNOS 4.1.3 Thank you very much for your help, -- email: jojo@i3.informatik.rwth-aachen.de smail: Joachim Bausch, Lehrstuhl f. Informatik III Ahornstr. 55, 52074 Aachen, Germany phone: +49/241/80-21320 fax: +49/241/8888-218 ======================================================================= 2 === Date: Tue, 3 Jan 1995 00:09:02 GMT From: g@clio.demon.co.uk (Gareth Webber) Subject: Linux LOCKs Is there a problem with the LOCKs set up under Linux M3 version 3.3 as I have a program which behaves perfectly (apart from concurrency problems...) without locks but as soon as I protect data to remove the concurency issues the program gives a deferencing NIL pointer exception. Is this a known problem ? I am using the larger of Michael Dagenais's versions. I have heard whispers of a version 3.4. Is there a likely release date ? What new features are there ? TIA, gary... -- Gareth Webber, g@clio.demon.co.uk Trinity Hall, gpw1000@cus.cam.ac.uk Cambridge. gary@royle.org "Ne te confudant illegitimi" ======================================================================= 3 === Date: Tue, 3 Jan 1995 17:53:36 GMT From: shang@corp.mot.com (David L. Shang) Subject: Re: Cows, Hogs & Farms In article <1994Dec29.013815@hobbit> writes: > Note: This post was originally on comp.lang.eiffel > > > In article > > milod@netcom.com (John DiCamillo) writes: > > >> chrisb@stork.cssc-syd.tansu.com.au (Chris Bitmead) writes: > > >>> In article > >>> milod@netcom.com (John DiCamillo) writes: > > >>> How does covarience *really* work in Eiffel? > >>> > >>> class COW > >>> inherit > >>> HERBIVORE redefine eat > >>> feature eat(food: GRASS) is ... > >>> > >>> class HOG > >>> inherit > >>> HERBIVORE redefine eat > >>> feature eat(food: CORN) is ... > >>> > >>> class FARM > >>> feature > >>> LIST[HERBIVORE] livestock; -- cows and hogs > >>> LIST[PLANT] foodstuff; -- grass and corn > >>>... > >>> livestock.value.eat(foodstuff.value); > >>> > >>> Is there a compile-time or a run-time error? What > >>> happens? > > > I'm cross-posting this to comp.object, comp.lang.eiffel & comp.lang.sather > to get some discussion from people who are trying to do these complex > things as well as for those of us who are still just talking about it. > > Here's how it might be done: > ... > class herbivore is > inherit plants.plant; > procedure eat ( food is in plant ); > end herbivore; > > class herbivore body is > variable data is plant; > procedure eat ( get data is out plant; -- "get" binds data to the proc. > food is in plant ) is > begin > data := food; -- food the herbivore has most recently eaten > end eat; > end herbivore; > ... To make the implementation interface diferent from the exported interface is not a good idea to handle this situation. By your herbivore class, you declare that a herbivore can eat any plant. Therefore, if hog and cow are herbivores, they should eat any plant, otherwise they are not herbivores. If hog and cows are herbivores in the real world, then, your definition of herbivore class is wrong. It makes a false promise on which its subclasses cannot agree. It really depends on the precision that you want to model the real world. If you do not care the futher classification of herbivores on their food types (plants), the definition of "procedure eat ( food is in plant )" is fine for a herbivore class. But if you do care the classification of herbivores on their food types, herbivore should be an abstract class because its real food type is unknown yet. The way it eats may be unknown either. Therefore, a herbivore class should be: class herbivore [FoodType <: plant] is procedure eat ( food is in FoodType ); end herbivore; Then, you can have cows and hogs: class hog is herbivore [FoodType = corn]; class cow is herbivore [FoodType = grass]; If farms are a collection of herbivores with a field where their food grows, we should think about how to model a farm. There are three different ways. Firstly, you could have a homogeneous farm where only on type of herbivores are raised: class field [FoodType <: plant] function getCrop(): FoodType; end field; class farm [AnimalType <: herbivore] is animals: list [MemberType = AnimalType]; fields: list [MemberType = field [FoodType = AnimalType.FoodType]]; function getRipeFood(): AnimalType.FoodType; -- get the ripe food from one of its fields. ... end farm; class hog_farm is herbivore [AnimalType = hog]; class cow_farm is herbivore [AnimalType = cow]; You do not need any run-time type check or system validation for this kind of farm within a close world: program farming is c is cow_farm; h is hog_farm; begin ... for each animal in c.animals do animal.eat(aCorn); -- wrong! for each animal in c.animals do animal.eat(aGrass); -- correct. for each animal in c.animals do animal.eat (c.getRipeFood ()); -- correct. end farming. You do not need any run-time type check or system validation for this kind of farm even with an open world if the type dependency is known statically: procedure farming [FarmType <:farm] (f: FarmType; food: FarmType.AnimalType.FoodType) begin ... for each animal in f.animals do animal.eat(food); -- correct end farming. procedure self_farming (f: farm) begin ... for each animal in f.animals do animal.eat(f. getRipeFood()); -- correct end self_farming. Secondly, you could have an ill-structured heterogeneous farm where various type of herbivores are raised at random fields. That is, there is no relationship between a field type and a herbivore type: class farm is animals: list [MemberType <: herbivore]; fields: list [MemberType <: field]; function getRipeFood(): plant; -- get the ripe food from one of its fields. end farm; You need run-time type check or system validation for this ill-structured farm: procedure self_farming is (f is in farm) begin ... for each animal in f.animals do animal.eat(f.getRipeFood ()); -- wrong! for each animal in f.animals do plant food := f.getRipeFood(); when typeof(animal).Foodtype = typeof(food) do animal.eat(food); -- correct end end self_farming. Lastly, you could have an well-structured heterogeneous farm where each type of herbivores are raised at the field that grows their own food. That is, there is a relationship between a field type and a herbivore type: class group [AnimalType <: herbivore] is animals: list [MemberType = AnimalType]; fields: list [MemberType = field [FoodType = AnimalType.FoodType]]; function getRipeFood(): AnimalType.FoodType; -- get the ripe food from one of its fields. ... end group; class farm is groups: group; ... end farm; When you do self farming, you do not need run-time type check or system validation for this well-structured farm: procedure self_farming is (f is in farm) begin ... for each group in f.groups do for each animal in group do animal.eat(group.getRipeFood ()); -- correct! end self_farming. I really cannot tell you which way is the best. It depends on the requirement of your problem domain. However, a good language should provide all the possible ways. The language BETA and Cluster come close to what I presented above. David Shang ======================================================================= 4 === Date: 3 Jan 1995 13:43:14 -0500 From: russo@cs.purdue.edu (Vincent F. Russo) Subject: Call For Papers: COOTS '95 Announcement and Call for Papers Conference on Object-Oriented Technologies (COOTS) June 26-29, 1995 Monterey, California, USA Sponsored by the USENIX Association IMPORTANT DATES Submissions due: March 6, 1995 Notification to authors: April 3, 1995 Camera-ready final papers due: May 15, 1995 PRELIMINARY PROGRAM COMMITTEE Program Chair: Vincent F. Russo, Purdue University Tutorial Program Chair: Doug Lea, SUNY Oswego Luca Cardelli, Digital Systems Research Center Murthy Devarokonda, IBM Watson Research Labs Ted Goldstein, SUN Microsystems Labs. Paul Leach, Microsoft Mark Linton, Silicon Graphics Inc. Chris Pettus, Taligent Jim Waldo, SUN Microsystems Labs. OVERVIEW The COOTS conference is designed to be the showplace for advanced development work in object-oriented technologies. The conference will emphasize research and experience derived from efforts to use object-oriented techniques to build complex systems that meet real world needs. The COOTS conference will begin with two days of tutorials. The tutorial program will offer a selection of tutorials from among several tracks. We expect tutorial topics to include: * distributed object systems (CORBA, etc.) * object-oriented network programming * alternative object-oriented languages * advanced techniques in memory management * efficient and effective class design Two days of technical sessions will follow the tutorials. Proceedings of the conference will be published by USENIX and will be provided free to technical session attendees; additional copies will be available for purchase from USENIX. Like the USENIX C++ Conferences and Advanced Topics Workshops from which it is derived, COOTS will emphasize the advanced engineering aspects of object technology. While papers covering work in C++ are encouraged, the conference i s broader in scope than its ancestors and invites submissions describing results and work in other object-oriented or object-based languages. CONFERENCE TOPICS We seek papers describing original work concerning the design, implementation, and use of object-oriented technologies. Questions regarding a topic's relevance may be addressed to the program chair via electronic mail to russo@cs.purdue.edu. Potential topics include: * work on object-oriented programming languages (C++, Modula-3, Eiffel, etc.) * implementations of commercial object infrastructures (CORBA, NextStep, OLE-II, SOM/DSOM, etc.) * interface description languages * distributed object systems * unique applications of and experiences with object-oriented technologies WHAT TO SUBMIT Submissions must be received by March 6, 1995. Full papers should be 10 to 15 pages. Instead of a full paper, authors may submit an extended abstract which discusses key ideas. Extended abstracts should be 5-7 pages long (about 2500-3500 words), not counting references and figures. The body of the extende d abstract should be complete paragraphs. The object of an extended abstract is to convince the reviewers that a good paper and presentation will result. While, by acceptance of extended abstracts, we intend to stimulate industrial participation, submission of extended abstracts by academics is in no way discouraged. All submissions will be judged on originality, relevance, and correctness. Eac h accepted submission will be assigned a member of the program committee to act a s its shepherd through the preparation of the final paper. The assigned member will act as a conduit for feedback from the committee to the authors. Camera-ready final papers are due May 15, 1995. Please accompany each submission by a cover letter stating the paper title and authors along with the name of the person who will act as the contact to the program committee. Please include a surface mail address, daytime and evening phone number, and, if available, an email address and fax number for the contac t person. If you would like to receive detailed guidelines for submission and examples of extended abstracts, you may telephone the USENIX Association office at +1 510 528-8649, or email to cootsauthors@usenix.org or to the program committee chair. The COOTS conference, like most conferences and journals, requires that papers not be submitted simultaneously to another conference or publication and that submitted papers not be previously or subsequently published elsewhere. Papers accompanied by "non-disclosure agreement" forms are not acceptable and will be returned to the author(s) unread. All submissions are held in the highest confidentiality prior to publication in the Proceedings, both as a matter of policy and in accord with the U.S. Copyright Act of 1976. WHERE TO SUBMIT Please send one copy of a full paper or an extended abstract to the program committee via one of the following methods. All submissions will be acknowledged. o Preferred Method: email (Postscript or ASCII) to cootspapers@usenix.org o Alternate Method: postal delivery to USENIX COOTS Conference c/o Dr. Vincent F. Russo Department of Computer Sciences Purdue University West Lafayette, IN 47907 U.S.A. +1 317 494-6008 REGISTRATION MATERIALS Materials containing all details of the technical and tutorial programs, registration fees and forms, and hotel information will be available beginning in April 1995. If you wish to receive the registration materials, please contact USENIX at: USENIX Conference Office 22672 Lambert Street, Suite 613 Lake Forest, CA USA 92630 +1 714 588-8649; Fax: +1 714 588-9706 Internet: conference@usenix.org ======================================================================= 5 === Date: Tue, 3 Jan 1995 15:56:04 GMT From: cs_wcm@ug.cs.ust.hk (Woo Chat Ming) Subject: Is m3 suitable for me ? I am working on a project to stimulate the performance of optical computer network. I am deciding what language to use. I want the program to have a graphic user interface ( i.e. the user should be able press the buttons to change parameters, and the flowing of messages between nodes should be displayed graphically like a movie as the simulation goes on.) Is modula-3 suitable for this project ? I am new to modula-3 and I have never programmed in neither windows and X-win envirnoment. I have never used Motif. Is X-win programming in modula-3 difficult to learn ? Which books/material is good for beginner like me ? Thank you for any suggestion. Woo Chat Ming. ======================================================================= 6 === Date: Wed, 4 Jan 1995 01:03:07 GMT From: hgeorge@eskimo.com (Harry George) Subject: Which OS for Modula-3 I have a 486-66 PC with 16Mbyte and a Mitsumi CD ROM. I want to do serious Modula-3 coding (not just try it out a few times). What's your recommendation for an OS. Assume I am busy until midsummer, so something available then is ok. Linux? (Slackware?) OS/2? WinNT? FreeBSD? Thanks, -- Harry George email: hgeorge@eskimo.com smail: 22608 90th Ave W / Edmonds WA 98026 quote: "The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, progress depends on the unreasonable man." G. B. Shaw ======================================================================= 7 === Date: 3 Jan 95 22:30:31 EDT From: hathawa2@marshall.edu (Mark S. Hathaway) Subject: Re: Cows, Hogs & Farms > In article <1995Jan3.175336.14940@schbbs.mot.com>, > shang@corp.mot.com (David L. Shang) writes: >> In article <1994Dec29.013815@hobbit> >> hathawa2@marshall.edu (Mark S. Hathaway) writes: >> Note: This post was originally on comp.lang.eiffel >>> In article >>> milod@netcom.com (John DiCamillo) writes: >>>> chrisb@stork.cssc-syd.tansu.com.au (Chris Bitmead) writes: >>>>> In article >>>>> milod@netcom.com (John DiCamillo) writes: >>>>> How does covarience *really* work in Eiffel? >>>>> >>>>> class COW >>>>> inherit >>>>> HERBIVORE redefine eat >>>>> feature eat(food: GRASS) is ... >>>>> >>>>> class HOG >>>>> inherit >>>>> HERBIVORE redefine eat >>>>> feature eat(food: CORN) is ... >>>>> >>>>> class FARM >>>>> feature >>>>> LIST[HERBIVORE] livestock; -- cows and hogs >>>>> LIST[PLANT] foodstuff; -- grass and corn >>>>>... >>>>> livestock.value.eat(foodstuff.value); >>>> >>>>> Is there a compile-time or a run-time error? What >>>>> happens? >> ... It appears Mr. Shang has added comp.lang.beta and some other(s) to the distribution list. Perhaps it will expand the conversation to others who can enlighten us all. >> Here's how it might be done: >> >> ... >> class herbivore is >> inherit plants.plant; >> procedure eat ( food is in plant ); >> end herbivore; >> >> class herbivore body is >> variable data is plant; >> procedure eat ( get data is out plant; -- "get" binds data to the proc. >> food is in plant ) is >> begin >> data := food; -- food the herbivore has most recently eaten >> end eat; >> end herbivore; >> ... > To make the implementation interface diferent from the exported interface is > not a good idea to handle this situation. I'm not keen on the idea of a class body having global data, so the added parameter binds the method to particular data within the class. There could be several variables which together define the object. By binding only the particular one(s) to a method it should be clearer what is acting on what. Will you elaborate on your view? > By your herbivore class, you declare that a herbivore can eat any plant. > Therefore, if hog and cow are herbivores, they should eat any plant, > otherwise they are not herbivores. If hog and cows are herbivores in the > real world, then, your definition of herbivore class is wrong. It makes > a false promise on which its subclasses cannot agree. If grass and corn are all they will eat then the way I wrote it is correct. If they will eat other plants then the constraint that the hog and cow should only eat grass and corn aren't defined in those classes then it would have to be introduced later. I wouldn't object to that. We wouldn't want them eating anything dangerous. :-) I was following the example of the original post to comp.lang.eiffel. > It really depends on the precision that you want to model the real world. If > you do not care the futher classification of herbivores on their food types > (plants), the definition of "procedure eat ( food is in plant )" is fine > for a herbivore class. > > But if you do care the classification of herbivores on their food types, > herbivore should be an abstract class because its real food type is unknown > yet. The way it eats may be unknown either. Therefore, a herbivore class > should be: > > class herbivore [FoodType <: plant] is > procedure eat ( food is in FoodType ); > end herbivore; A herbivore's food is plant material. I only gave the type plant as the foods there might be on a farm. If I was being more thorough I'd have defined plant more completely and have made even more readers angry with me for making the post too long. Besides, it wasn't the point of the example. In my example the "way it eats" is undefined. All that is recorded is what was eaten most recently. I didn't even begin to discuss the chewing of cud. Without defining "plant" you've left yourself open for problems. Somehow someone will have to get around to defining it for this to work. > Then, you can have cows and hogs: > > class hog is herbivore [FoodType = corn]; > class cow is herbivore [FoodType = grass]; Funny how you, too, specify corn & grass as the foods these animals can eat. It's the most natural way to describe a HOG or COW. If there are other plants these animals eat then there should be a subset of "plants" created for each of them. > If farms are a collection of herbivores with a field where their food > grows, we should think about how to model a farm. There are three > different ways. In the example from the comp.lang.eiffel post there were only HOG & COW and an example FARM. I tried not to stray too far from that. > Firstly, you could have a homogeneous farm where only on type of herbivores > are raised: > > class field [FoodType <: plant] > function getCrop(): FoodType; > end field; Isn't a generic field which can grow any plant more correct? Doesn't the notation you've given tie one specific plant to the field and not allow for future crop rotations? Farmers plant different crops to avoid depleting the soil too much. > class farm [AnimalType <: herbivore] is > animals: list [MemberType = AnimalType]; > fields: list [MemberType = field [FoodType = AnimalType.FoodType]]; > function getRipeFood(): AnimalType.FoodType; > -- get the ripe food from one of its fields. > ... > end farm; > > class hog_farm is herbivore [AnimalType = hog]; > class cow_farm is herbivore [AnimalType = cow]; Why would a farm be a herbivore? I don't care for your syntax which appears to only allow single inheritance. What if a COW is not only a HERBIVORE, but a DOMESTICATED_ANIMAL? I could write... class cow is inherit herbivore; inherit domesticated_animal; end cow; Perhaps you're right that I should have developed a generic farm and then populated it with particular animals. That wouldn't be too difficult, as you showed. Again, I wasn't focusing on these peripheral classes as much as on the COW and HOG classes and how to build the FARM from them. All this shows how difficult it is to fully define something as simple as a farm. Once you begin to model the real world things get very complicated. > You do not need any run-time type check or system validation for this > kind of farm within a close world: > > program farming is > c is cow_farm; > h is hog_farm; > begin > ... > for each animal in c.animals do animal.eat(aCorn); -- wrong! > for each animal in c.animals do animal.eat(aGrass); -- correct. > for each animal in c.animals do animal.eat (c.getRipeFood ()); -- correct. > end farming. What if the farmer sells some cows and buys some hogs to have a mixed farm? How do you readjust to handle this? > You do not need any run-time type check or system validation for this kind > of farm even with an open world if the type dependency is known statically: > > procedure farming > [FarmType <:farm] > (f: FarmType; food: FarmType.AnimalType.FoodType) > begin > ... > for each animal in f.animals do animal.eat(food); -- correct > end farming. Sure, it's easier if it's a homogeneous farm because you don't have to figure-out what food to match with which animal and if it's grown in the field where the animal is and if it's ripe. The real world is complicated. > procedure self_farming (f: farm) > begin > ... > for each animal in f.animals do animal.eat(f. getRipeFood()); -- correct > end self_farming. > > Secondly, you could have an ill-structured heterogeneous farm where various > type of herbivores are raised at random fields. That is, there is no > relationship between a field type and a herbivore type: > > class farm is > animals: list [MemberType <: herbivore]; > fields: list [MemberType <: field]; > function getRipeFood(): plant; > -- get the ripe food from one of its fields. > end farm; Why do you say "animals: list [MemberType <: herbivore];" instead of animals: list [ herbivore ]; ? And, how does "herbivore" define a COW or HOG when they could easily be created from both HERBIVORE and DOMESTICATED_ANIMAL? What would you do in that case? > You need run-time type check or system validation for this ill-structured > farm: > > procedure self_farming is (f is in farm) > begin > ... > for each animal in f.animals do animal.eat(f.getRipeFood ()); -- wrong! > for each animal in f.animals do > plant food := f.getRipeFood(); > when typeof(animal).Foodtype = typeof(food) do > animal.eat(food); -- correct > end > end self_farming. This version of farming() looks pretty good. I like the use of "typeof()" also. It's quite useful. My example was difficult to read compared to this. > Lastly, you could have an well-structured heterogeneous farm where each > type of herbivores are raised at the field that grows their own food. That > is, there is a relationship between a field type and a herbivore type: But, if an animal (or group of animals) is put in a field simply for temporary holding then there's no plan for them to eat there and no need to observe the binding of animal-to-field. That binding only needs to be checked when they're trying to eat. > class group [AnimalType <: herbivore] is > animals: list [MemberType = AnimalType]; > fields: list [MemberType = field [FoodType = AnimalType.FoodType]]; > function getRipeFood(): AnimalType.FoodType; > -- get the ripe food from one of its fields. > ... > end group; > > class farm is > groups: group; > ... > end farm; > > When you do self farming, you do not need run-time type check or system > validation for this well-structured farm: > > procedure self_farming is (f is in farm) > begin > ... > for each group in f.groups do > for each animal in group do > animal.eat(group.getRipeFood ()); -- correct! > end self_farming. > > I really cannot tell you which way is the best. It depends on the > requirement of your problem domain. However, a good language should > provide all the possible ways. I'd like to know why you didn't address the identification of individual animals. For a long time COBOL and FORTRAN were considered "good" languages and they didn't provide facilities to do these class things. I guess we become comfortable with those early developments and begin to take them for granted. Now, a good language is soooo much more. I doubt we're seen a quiescence of language development regarding features which allow us to develop programs using the OO paradigm. > The language BETA and Cluster come close to what I presented above. > > David Shang I've not seen BETA and have never heard of Cluster. Could you provide a pointer-->ftp_site or other info. about them? :-) Finally, I apologize to those who thought my original post was too long at more than 300 lines. I thought it necessary to flesh-out the problem at hand. In fact, as Mr. Shant points out, it really requires more than I gave. Mark S. Hathaway ======================================================================= 8 === Date: 4 Jan 1995 17:03:26 GMT From: kalsow@src.dec.com (Bill Kalsow) Subject: Re: SRC M3 v. 3.4 out In article <3eegn0$dtp@hermes.unt.edu>, schaub@ponder.csci.unt.edu (Stephen Sch aub) writes: > When browsing the Modula-3 home page this morning, I happened to see that > the current version of the SRC distribution is now 3.4. > ... > Did I miss an announcement in this group? No, you didn't miss the announcement. I usually let a few people try out the system before announcing it. Indeed, they have already reported a minor bug that I'll fix ASAP. Yes, 3.4 includes lots of changes: - new ports to IRIX 5.2, FreeBSD, and Windows/NT(w/o Trestle) - a single top-level, build-everything m3makefile - faster compilation (merged driver & pass0) - runtime error message that include file and line number - m3browser, an HTTP server that provides "virtual Modula-3 space" - better shared library support for SOLsun and SPARC - more robust type encodings for the debugger (but not Peter Klein's changes) - ParseParams and SLisp are back - a floating-point version of the geometry package - countless bug fixes If you wait a few days the release will be stable. - Bill Kalsow ======================================================================= 9 === Date: Wed, 4 Jan 1995 13:25:57 GMT From: kees@dutiag.twi.tudelft.nl (Kees Pronk) Subject: Question on generics I have two questions on generics: In the languge definition in SigPlan (and in the book by G. Nelson it says): #5.5 Generics #In a generic interface or module, *some* of the imported #interfaces are treaded as formal parameters, to be bound # to actual interfaces when the generic is instantiated. It is unclear to me why the *some* is not *all*. Is this partial instantiation? There seem to be no examples of this. In the book by Harbison it is said that (my wording may not be exact, as I do not have the book available now): # There is no need for the interface list of a generic interface # to match the interface of its asociated module. Again there are no examples of such a situation. Could someone explain the background of these, and perhaps provide some examples? (Sorry if this is a faq) Thanks in advance, Kees Pronk. -- -------------------------------------------------------- - C. (Kees) Pronk - Delft University of Technology - Fac. of Techn. Math. and Informatics ======================================================================= 10 === Date: 4 Jan 95 09:10:44 From: dagenais@notung.vlsi.polymtl.ca (Michel Dagenais) Subject: Re: Which OS for Modula-3 I have a 486-66 PC with 16Mbyte and a Mitsumi CD ROM. I want to do serious Modula-3 coding (not just try it out a few times). Hundreds of thousands of lines of M3 code have been compiled on such platforms so this should be serious enough (m3tk, formsvbt, netobj...). What's your recommendation for an OS. Assume I am busy until midsummer, so something available then is ok. Linux? (Slackware?) OS/2? WinNT? FreeBSD? M3 for LINUX has been working very well for some time. M3 for FreeBSD recently appeared and is not yet out for newer versions of FreeBSD. WinNT support may be there by then. -- Prof. Michel Dagenais dagenais@vlsi.polymtl.ca Dept of Electrical and Computer Eng. Ecole Polytechnique de Montreal tel: (514) 340-4029 ======================================================================= 11 === Date: 4 Jan 95 09:04:37 From: dagenais@notung.vlsi.polymtl.ca (Michel Dagenais) Subject: Re: Linux LOCKs In article <1995Jan3.000902.2586@clio.demon.co.uk> g@clio.demon.co.uk (Gareth W ebber) writes: Is there a problem with the LOCKs set up under Linux M3 version 3.3 as I have a program which behaves perfectly (apart from concurrency problems...) without locks but as soon as I protect data to remove the concurency issues the program gives a deferencing NIL pointer exception. Is this a known problem ? I am using the larger of Michael Dagenais's versions. No known problems in this area. Concurrency is tricky to get right... and to debug. I have heard whispers of a version 3.4. Is there a likely release date ? What new features are there ? No idea for a release date; the longer we wait the more stuff will be in there :-). The major feature i have heard about is M3 lite, a very fast compiler for Win32 (Windows NT/ Windows 95) which i will attempt to get running on Linux. -- Prof. Michel Dagenais dagenais@vlsi.polymtl.ca Dept of Electrical and Computer Eng. Ecole Polytechnique de Montreal tel: (514) 340-4029 ======================================================================= 12 === Date: Wed, 4 Jan 1995 15:15:58 GMT From: rsutc@twu.ca (Rick Sutcliffe) Subject: generics Can anyone here give me a summary of the general consensus on the success of the generic template facility in Modula-2? What would you change if you were designing the facility? What are its strengths and weaknesses vis a vis other languages that have generics? Rick -- Rick Sutcliffe Assoc. Prof. Computing/Math Trinity Western University Canadian Chair, WG13. Not an official spokesperson for TWU or WG13 ======================================================================= 13 === Date: 4 Jan 1995 16:00:32 GMT From: schaub@ponder.csci.unt.edu (Stephen Schaub) Subject: SRC M3 v. 3.4 out When browsing the Modula-3 home page this morning, I happened to see that the current version of the SRC distribution is now 3.4. According to history, v 3.4 provides ports for WinNT (without Trestle) and FreeBSD, I believe. There was mention of a merging of the m3 front-end and the first compiler phase, but no word about any other changes (I'd hoped to read that run-time error messages would include module/line number debugging info, which was rumored to be an improvement scheduled for release with 3.4). It seems that the sources are now available via FTP. Did I miss an announcement in this group? Or perhaps I'm just the first one to see it. Stephen Schaub schaub@cs.unt.edu ======================================================================= 14 === Date: Wed, 4 Jan 1995 15:14:26 GMT From: rsutc@twu.ca (Rick Sutcliffe) Subject: Sam Harbison??? Can anyone here provide an e-mail address for him? Thanks Rick -- Rick Sutcliffe Assoc. Prof. Computing/Math Trinity Western University Canadian Chair, WG13. Not an official spokesperson for TWU or WG13 ======================================================================= 15 === Date: Wed, 4 Jan 1995 18:18:54 GMT From: rsutc@twu.ca (Rick Sutcliffe) Subject: Re: generics In article , rsutc@twu.ca (Rick Sutcliffe) wrote: > Can anyone here give me a summary of the general consensus on the success > of the generic template facility in Modula-2? What would you change if > you were designing the facility? What are its strengths and weaknesses > vis a vis other languages that have generics? > Rick > > -- Whoops That should of course have been Modula-Three. I type the other all the time and it was automatic. Rick -- Rick Sutcliffe Assoc. Prof. Computing/Math Trinity Western University Canadian Chair, WG13. Not an official spokesperson for TWU or WG13 ======================================================================= 16 === Date: 04 Jan 1995 17:49:33 GMT From: alfh@gyda.ifi.uio.no (Alf-Ivar Holm) Subject: Re: Cows, Hogs & Farms In article <1995Jan3.223031@hobbit> hathawa2@marshall.edu (Mark S. Hathaway) wr ites: > I've not seen BETA and have never heard of Cluster. Could you provide > a pointer-->ftp_site or other info. about them? :-) The BETA home page is found at: http://www.daimi.aau.dk/~beta/info I have no info on Cluster. Affi ======================================================================= 17 === Date: 4 Jan 95 02:27:32 From: vixie@gw.home.vix.com (Paul A Vixie) Subject: Re: Is m3 suitable for me ? I think that you will find Modula-3 uniquely suited for your application. Because of its separation of interface and implementation, it is an ideal language for high level simulations where modules of the system being simulated need to map fairly evenly to modules of the simulator. I have found that its strong typing and exception support lead to code that does what it looks like it does, perhaps more so than any other language I have used. But the clinching argument in your case is that you want to animate an algorythm, and you can thus benefit from the experience of the folks at SRC, who have done just that, using just this language. The techreports database on www.digital.com should have a postscript file of the technical reports on algorythm animation. One thing, though -- graphical programs in Modula-3 don't really teach much about X Windows since the programming environment isolates those details. There is no reason in principle why a graphics program in Modula-3 could not be build on some other system -- as long as the Trestle library had been implemented for the native windows/graphics system. -- Paul Vixie La Honda, CA decwrl!vixie!paul ======================================================================= 18 === Date: Wed, 04 Jan 95 13:54:45 -0800 From: kalsow@pa.dec.com Subject: Re: Modula-3 Generics > * Is the generic facility useful vis a vis other languages? Yes. It's more restrictive than what you find in C++ or CLU, but it's still quite usable. > * If you could improve it would you? What would you change? > * What do you think of having types and constant expressions as parameters > rather than modules? Yes, any compile-time constant should be allowed as a parameter to a generic. This change would be sound and no problem to implement in the compiler. As a programmer, I would like to be able to instantiate a generic at the point you import it. For example: IMPORT List[CHAR]; But as a compiler writer, I wouldn't be thrilled to implement the resulting language. The current m3build system is quite a bit more powerful than make. It's pretty easy for the author of a generic to provide a build-time function that produces the little bit of text that Modula-3 requires. So, here again, the line between programming language and programming environment is fuzzy. Where to draw the line is quite subjective. > * I understand from Sam's book that the interface list for a generic > interface and for the corresponding generic module are not necessarily the > same. Is this correct? Yes. For example, see the Modula-3 Sequence generic. There are two interfaces (a public and a friends one). The public interface is parameterized by the element type's interface, the private interface is parameterized by the element type and the public interface. And finally, the implementation is parameterized by all three. If you were able to instantiate generics in import statements this cascading of generic parameters wouldn't be necessary. - Bill Kalsow ======================================================================= 19 === Date: Wed, 4 Jan 1995 19:19:10 GMT From: shang@corp.mot.com (David L. Shang) Subject: Re: Cows, Hogs & Farms In article <1995Jan3.223031@hobbit> writes: > It appears Mr. Shang has added comp.lang.beta and some other(s) to the > distribution list. Perhaps it will expand the conversation to others who > can enlighten us all. I think that the BETA and the Modula3 groups are intersted in this subject too. > > > By your herbivore class, you declare that a herbivore can eat any plant. > > Therefore, if hog and cow are herbivores, they should eat any plant, > > otherwise they are not herbivores. If hog and cows are herbivores in the > > real world, then, your definition of herbivore class is wrong. It makes > > a false promise on which its subclasses cannot agree. > > If grass and corn are all they will eat then the way I wrote it is correct. > If they will eat other plants then the constraint that the hog and cow > should only eat grass and corn aren't defined in those classes then it would > have to be introduced later. I wouldn't object to that. We wouldn't want > them eating anything dangerous. :-) As I said already in my previous posts on the subject of covariance, we cannot have covariance for a subclass if we cannot find a general rule for that subclass. If a subclass of herbivore eat all plant (of cause not including poisonous plant, which is not a food), you can have: AllPlantEatingHerbivore is Herbivore [ FoodType=plant]; If a subclass of herbivore eat all most all plants except for a few plants that you cannot rule out a classification on the food they do not eat, you can have: AlmostAllPlantEatingHerbivore is Herbivore [ FoodType=plant]; and use run-time type check to reject those food they do not eat. If a subclass of herbivore eat only a few plants that you cannot rule out a classification on the food they eat, you can also have: SomePlantEatingHerbivore is Herbivore [ FoodType=plant]; and use run-time type check to accept those food they eat. Sometimes multiple inheritance may help the last case to get rid of run-time type check. class Panda is Herbivore [FoodType = BambooLeaf], Herbivore [FoodType = Corn] procedure Herbivore[BambooLeaf]::eat (food: BambooLeaf); procedure Herbivore[Corn]::eat (food: Corn); end Panda; In reality, we always have exceptions. We can use covariance to rule out a general principle and use run-time type check for a few exceptions. As to the animal example, it is clearly worthwhile to divide animals into herbivires, carnivores and (?)(animals eating both food) according to the type of their food. We can use covaraince. But it might be very hard to rule out a general principle for the futher classification for a certain number of animals. > > Then, you can have cows and hogs: > > > > class hog is herbivore [FoodType = corn]; > > class cow is herbivore [FoodType = grass]; > > Funny how you, too, specify corn & grass as the foods these animals can eat. > It's the most natural way to describe a HOG or COW. If there are other > plants these animals eat then there should be a subset of "plants" created > for each of them. We are not developing a commercial software for zoologists, are we? These are only padagogical examples. Be wise to make things as simple as possible -- just for the key points you want to say. > > > If farms are a collection of herbivores with a field where their food > > grows, we should think about how to model a farm. There are three > > different ways. > > In the example from the comp.lang.eiffel post there were only HOG & COW and > an example FARM. I tried not to stray too far from that. > > > Firstly, you could have a homogeneous farm where only on type of herbivores > > are raised: > > > > class field [FoodType <: plant] > > function getCrop(): FoodType; > > end field; > > Isn't a generic field which can grow any plant more correct? Doesn't the > notation you've given tie one specific plant to the field and not allow for > future crop rotations? Farmers plant different crops to avoid depleting the > soil too much. This is an abstract field. No object can be intantiated by the class unless you associate it with a plant type. > > > class farm [AnimalType <: herbivore] is > > animals: list [MemberType = AnimalType]; > > fields: list [MemberType = field [FoodType = AnimalType.FoodType]]; > > function getRipeFood(): AnimalType.FoodType; > > -- get the ripe food from one of its fields. > > ... > > end farm; > > > > class hog_farm is herbivore [AnimalType = hog]; > > class cow_farm is herbivore [AnimalType = cow]; > > Why would a farm be a herbivore? Sorry, a typo. Should be: class hog_farm is farm [AnimalType = hog]; class cow_farm is farm [AnimalType = cow]; > > I don't care for your syntax which appears to only allow single inheritance. > What if a COW is not only a HERBIVORE, but a DOMESTICATED_ANIMAL? I could > write... > > class cow is > inherit herbivore; > inherit domesticated_animal; > end cow; > Multiple inheritance is fine: class cow is herbivore [FoodType = Grass], domesticated_animal [ FoodType = ManMadeCowFood ]; You can even have: class cow is herbivore [FoodType = Grass], herbivore [FoodType = Hay], herbivore [FoodType = Corn], ... domesticated_animal [ FoodType = ManMadeCowFood ]; Note that herbivore[Grass], herbivore[Hay], ... are anonymous subclasses of herbivore and they share the common base of herbivore. > Perhaps you're right that I should have developed a generic farm and then > populated it with particular animals. That wouldn't be too difficult, as > you showed. Again, I wasn't focusing on these peripheral classes as much > as on the COW and HOG classes and how to build the FARM from them. Note that the generic classes I presented above are not conventional generic classes. You cannot have this by Eiffel's generic class, which is not a real class, and hence it is meaningless to discuss the subclass relationship between a generic class and the class instantiated by the generic class. > > > You do not need any run-time type check or system validation for this > > kind of farm within a close world: > > > > program farming is > > c is cow_farm; > > h is hog_farm; > > begin > > ... > > for each animal in c.animals do animal.eat(aCorn); -- wrong! > > for each animal in c.animals do animal.eat(aGrass); -- correct. > > for each animal in c.animals do animal.eat (c.getRipeFood ()); > > -- correct. > > end farming. > > What if the farmer sells some cows and buys some hogs to have a mixed farm? > How do you readjust to handle this? Being owners of homogeneous farms, they cannot have a mixed farm. Being owners of homogeneous farms, farmers can sell their creatures to a market that accept the type of their creatures: cow_farm sells cows to cow market -- correct cow_farm sells cows to hog market -- incorrect cow_farm sells cows to mixed market -- correct Being owners of homogeneous farms, farmers can only buy their creatures from a market sells the type of their creatures: cow_farm buys cows from cow market -- correct cow_farm buys cows from hog market -- incorrect cow_farm buys cows from mixed market -- ensured by run-time type check The last case must be ensured by a run-time type check, beacuse it is a reverse assignment: cow_farm::buy(creature: cow); mixed_market::sell():herbivore; aCow_farm.buy(aMixed_market.sell()); -- wrong, reverse assignment here! You should write the code like this: a: herbivore := aMixed_market.sell(); when typeof(a)=cow do aCow_farm.buy(a) otherwise aMixed_market.send_back(a); > > > > Secondly, you could have an ill-structured heterogeneous farm where various > > type of herbivores are raised at random fields. That is, there is no > > relationship between a field type and a herbivore type: > > > > class farm is > > animals: list [MemberType <: herbivore]; > > fields: list [MemberType <: field]; > > function getRipeFood(): plant; > > -- get the ripe food from one of its fields. > > end farm; > > Why do you say "animals: list [MemberType <: herbivore];" > instead of animals: list [ herbivore ]; > ? > The latter is equivalent to: animals: list [ MemberType = herbivore ]; where "animals" is not a polymorphic (heterogeneous) variable. > And, how does "herbivore" define a COW or HOG when they could easily be > created from both HERBIVORE and DOMESTICATED_ANIMAL? What would you do > in that case? > By multiple inheriatnce as I shown above. > > You need run-time type check or system validation for this ill-structured > > farm: > > > > procedure self_farming is (f is in farm) > > begin > > ... > > for each animal in f.animals do animal.eat(f.getRipeFood ()); -- wrong! > > for each animal in f.animals do > > plant food := f.getRipeFood(); > > when typeof(animal).Foodtype = typeof(food) do > > animal.eat(food); -- correct > > end > > end self_farming. > > This version of farming() looks pretty good. I like the use of "typeof()" > also. It's quite useful. My example was difficult to read compared to this. > > > Lastly, you could have an well-structured heterogeneous farm where each > > type of herbivores are raised at the field that grows their own food. That > > is, there is a relationship between a field type and a herbivore type: > > But, if an animal (or group of animals) is put in a field simply for > temporary > holding then there's no plan for them to eat there and no need to observe > the binding of animal-to-field. That binding only needs to be checked when > they're trying to eat. > There could be a lot of buts. But I don't like to make things unnecessarily complicated for the subject discussed here. David Shang ======================================================================= 20 === Date: Thu, 5 Jan 95 11:07 MET From: olaf@logware.de (Olaf Wagner) Subject: Re: SRC M3 v. 3.4 out : Yes, 3.4 includes lots of changes: : - new ports to IRIX 5.2, FreeBSD, and Windows/NT(w/o Trestle) : - a single top-level, build-everything m3makefile : - faster compilation (merged driver & pass0) : - runtime error message that include file and line number : - m3browser, an HTTP server that provides "virtual Modula-3 space" : - better shared library support for SOLsun and SPARC : - more robust type encodings for the debugger (but not Peter Klein's changes ) : - ParseParams and SLisp are back : - a floating-point version of the geometry package : - countless bug fixes : If you wait a few days the release will be stable. Great! Just to save you from lots of mail concerning FreeBSD, you should point out that the version built from the patches I sent you will under no circumstances run on FreeBSD 2.0 (which is the actual FreeBSD version), but only on FreeBSD 1.1(.5). I got the compiler running last week on FreeBSD 2.0, and I will sent you the patches as soon as possible. There was no way around a new target (FreeBSD2), and there have been a lot of changes in the Unix-Interfaces. I'm trying to send you everything before Saturday, before my computer and everything else will move to a new flat (and won't be connected for some time...) Olaf -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \ Olaf Wagner at Logware GmbH Schwedenstrasse 9 \ \ olaf@logware.de (work) 13359 Berlin 65 \ \ wagner@luthien.in-berlin.de (private) Germany / Deutschland \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ======================================================================= 21 === Date: Thu, 5 Jan 1995 09:56:33 GMT From: olaf@logware.de (Olaf Wagner) Subject: Re: Which OS for Modula-3 Michel Dagenais (dagenais@notung.vlsi.polymtl.ca) wrote: : What's your recommendation for an OS. Assume I am busy until midsummer, : so something available then is ok. Linux? (Slackware?) OS/2? WinNT? : FreeBSD? : M3 for LINUX has been working very well for some time. M3 for FreeBSD : recently appeared and is not yet out for newer versions of FreeBSD. : WinNT support may be there by then. I got the compiler running on FreeBSD 2.0 last week, after about 20 attempts of cross-comilation. The patches will be send to SRC as soon as I have some hours time to tidy everything up a bit. The debugger is still not compilable. I am trying to integrate the m3-bits of the m23gdb-release into the gdb port of FreeBSD, but the underlying gdb versions are quite different. You may expect something (patches and perhaps a small binary distribution) within two or three weeks. -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \ Olaf Wagner at Logware GmbH Schwedenstrasse 9 \ \ olaf@logware.de (work) 13359 Berlin 65 \ \ wagner@luthien.in-berlin.de (private) Germany / Deutschland \ ======================================================================= 22 === Date: Wed, 04 Jan 95 18:42:55 -0800 From: heydon@usenet.pa.dec.com Subject: Re: Question on generics Kees Pronk asks: > I have two questions on generics: > > In the languge definition in SigPlan (and in the book by G. Nelson > it says): > > # 5.5 Generics > # In a generic interface or module, *some* of the imported > # interfaces are treated as formal parameters, to be bound > # to actual interfaces when the generic is instantiated. > > It is unclear to me why the *some* is not *all*. Is this partial > instantiation? There seem to be no examples of this. I think you are just forgetting about the interfaces imported explicitly via IMPORT statements. The names listed as the formal imports of the generic interface/module are treated as formal parameters, and the names listed in normal IMPORT statements are not. For example, in the generic interface: GENERIC INTERFACE G(A, B); IMPORT C, D, E; END G. the names "A" and "B" are treated as formal parameters, while the names "C", "D", and "E" are not. > In the book by Harbison it is said that (my wording may not > be exact, as I do not have the book available now): > > # There is no need for the interface list of a generic interface > # to match the interface of its associated module. > > Again there are no examples of such a situation. As Bill Kalsow pointed out in a recent message to comp.lang.modula3, the generic implementation of Sequences gives an example of this situation: > For example, see the Modula-3 Sequence generic. There are two > interfaces (a public and a friends one). The public interface is > parameterized by the element type's interface, the private interface > is parameterized by the element type and the public interface. And > finally, the implementation is parameterized by all three. - Allan -------------------------------------------------------------------- Allan Heydon Digital Equipment Corporation heydon@pa.dec.com Systems Research Center (415) 853-2142 130 Lytton Avenue (415) 853-2104 (FAX) Palo Alto, CA 94301 ======================================================================= 23 === Date: 5 Jan 1995 16:36:54 GMT From: laszlo@bornholm.ifi.uni-klu.ac.at (Laszlo BOESZOERMENYI) Subject: Re: Binary files in M3 Have a look at our SIO (Simple I/O) and SF (Simple Files) interfaces. The PC-version (compatible to m3 V.2x) is part of the newest release of the M3PC-Klanegfurt system, just put on the gatekeeper (announcement comes Monday). I can send you a version compatible to m3 V.3x, if needed. (I append the interfaces - they are indepedent from the version). Best regards Laszlo Boeszoermenyi ********************************* * Prof. Laszlo Boeszoermenyi * * Institut fuer Informatik * * * * Universitaet Klagenfurt * * Universitaetsstr. 65-67 * * A-9022 Klagenfurt / Austria * * * * e-mail: * * laszlo@ifi.uni-klu.ac.at * * Tel.: * * 00-43-463-2700-509 * * 00-43-463-2700-506 (secr.) * * Fax.: * * 00-43-463-2700-505 * ********************************* INTERFACE SIO; (*Simple Input/Output 13.04.94. LB*) (*SIO provides a Reader and a Writer type. A reader or a writer is a stream of typed data. Data can be read from a reader by "Get" procedures, and can be written by "Put" procedures onto a writer. The "Get" and "Put" procedures advance a (hidden) position over the reader resp. writer stream. The procedure "LookAhead" returns the next character, without advancing the reader position. All "Put" procedures flush automtically on stdout. GetText, GetInt, GetReal, GetBool terminate with any white space character, leading whitespaces are ignored. (White spaces are: new line, tab, space, form feed and carriage return.) The terminating character is removed from the reader, and can be retrieved by the TermChar function. "Error" exception is raised only for readers, not connected to Stdio.stdin. For Stdio.stdin, the user is prompted to type in a new value. SIO provides some additional functions, such as positioning (seeking) in readers, length and end of readers, flushing of writers etc. Writers are strictly sequential, positioning is not supported. The default value of the reader or writer parameter is always NIL, with the effect, selecting the appropriate standard device. Standard reader is Stdio.stdin, which is normally the keyboard. Standard writer is Stdio.stdout, which is normally the screen.*) IMPORT Rd, Wr; EXCEPTION Error; TYPE Reader = Rd.T; (*A Reader is an Rd.T*) Writer = Wr.T; (*A Writer is a Wr.T*) (*-------- Basic procedures --------*) PROCEDURE GetChar(rd: Reader := NIL): CHAR RAISES {Error}; (*Returns the next char.*) PROCEDURE PutChar(ch: CHAR; wr: Writer := NIL); (*Outputs a single character.*) PROCEDURE GetText(rd: Reader := NIL): TEXT RAISES {Error}; (*Reads a text. The terminating character is not appended.*) PROCEDURE PutText(t: TEXT; wr: Writer := NIL); (*Outputs all characters in t.*) PROCEDURE GetLine(rd: Reader := NIL): TEXT RAISES {Error}; (*Reads a line and returns is as a text. The terminating nl is not appended.* ) PROCEDURE PutLine(t: TEXT; wr: Writer := NIL); (*Outputs all characters in t and appends a new line.*) PROCEDURE GetInt(rd: Reader := NIL): INTEGER RAISES {Error}; (*Reads a decimal integer.*) PROCEDURE PutInt(i: INTEGER; length := 3; wr: Writer := NIL); (*Outputs an integer number. The number is right-aligned in a field of length "length", i.e. leading blanks are output if the number of digits < "length".*) PROCEDURE GetReal(rd: Reader := NIL): REAL RAISES {Error}; (*Reads a real number.*) PROCEDURE PutReal(r: REAL; wr: Writer := NIL); (*Outputs a real number. *) PROCEDURE GetLongReal(rd: Reader := NIL): LONGREAL RAISES {Error}; (*Reads a longreal number.*) PROCEDURE PutLongReal(r: LONGREAL; wr: Writer := NIL); (*Outputs a longreal number. *) PROCEDURE GetBool(rd: Reader := NIL): BOOLEAN RAISES {Error}; (*Reads a Boolean constant, terminated by any character in "terminate". Legal values are: TRUE, True, true, T, t resp. FALSE, False, false, F, f.*) (*!!! Currently accepts only T, t, F, f due to a bug in "Lex".*) PROCEDURE PutBool(b: BOOLEAN; wr: Writer := NIL); (*Outputs a Boolean value.*) (*-------- Additional procedures --------*) PROCEDURE LookAhead(rd: Reader := NIL): CHAR RAISES {Error}; (*Returns the next character, without removing it from the reader.*) PROCEDURE TermChar(rd: Reader := NIL): CHAR RAISES {Error}; (*Returns the last terminating character.*) PROCEDURE Nl(wr: Writer := NIL); (*Outputs a new line.*) PROCEDURE PutUnsigned(i: INTEGER; length := 6; base: [2..16] := 16; wr: Writer := NIL); (*Outputs an unsigned number with given base. The number is right-aligned in a field of length "length".*) PROCEDURE End(rd: Reader := NIL): BOOLEAN; (*Returns TRUE iff end of reader reached. On the keyborad CTRL-Z on the PC, and CTRL-D in Unix.*) PROCEDURE Flush(wr: Writer := NIL); (*Flushes the writer on the file. Not necessary for Stdio.stdout.*) PROCEDURE Available(rd: Reader := NIL): BOOLEAN; (*Returns TRUE iff some characters are available.*) PROCEDURE Length(rd: Reader := NIL): CARDINAL; (*Returns the length of the reader. Returns 0 if the length cannot be computed.*) PROCEDURE Seek(rd: Reader := NIL; position: CARDINAL := 0); (*Sets the reader on "position" if it is seekable. Default corresponds to reset a reader.*) END SIO. ---------------------------------------------------- INTERFACE SF; (*SimpleFiles 14.04.94. LB*) (*SimpleFiles provides simple procedures to connect readers and writers with files ("Open" procedures), and to decouple them ("Close" procedures). "OpenRead" connects a reader to an existing file, "OpenWrite" connects a writer to a new file. If the file with the given name already exists, the user may type in a new name or let it overwrite. "OpenAppend" positions the writer at the end of a file. The text in parameter "prompt" is displayed on standardout (screen). The file connected to a writer is made permanent by a "CloseWrite". SimpleFiles provides a flexible mechanism for file naming. If the "name" parameter is omitted (or NIL) at opening, then the opening procedures ask the user for a file name. If the user enters an empty line or Std (actually = "#") the file defaults to standard i/o, i.e. normally to keyboard (standardin) and screen (standardout). "GetFileName" provides more explicit control over file naming. *) IMPORT SIO; CONST Overwrite = "!"; Standard = "#"; PromptStart = "Type file name "; PromptEnd = " or NL or for standard = "; InPrompt = PromptStart & "for input" & PromptEnd; OutPrompt = PromptStart & "for output" & PromptEnd; AppPrompt = PromptStart & "for append" & PromptEnd; TYPE Reader = SIO.Reader; Writer = SIO.Writer; PROCEDURE OpenRead(name: TEXT := NIL; prompt:= InPrompt): Reader; (*Connects the file, called "name" to a reader. If "name" is NIL, or the file does not exists, it asks the user for a file name until the file can be opened. It returns Stdio.stdin if the user enters "return" or Std ("#").*) PROCEDURE OpenWrite(name: TEXT := NIL; prompt:= OutPrompt; overwrite:= FALSE): Writer; (*Connects a writer to the file, called "name". If "name" is NIL it asks the user for a file name. It returns Stdio.stdout if the user enters "return" or Std ("#"). If the file (given in "name" or typed in by the user) already exists, and "overwrite" is false, it prompts the user to give another file name or to type constant Overwrite (actually = "!") for overwriting. If parameter "overwrite" is true, an existing file with same name will be overwritten, without asking the interactive user.*) PROCEDURE OpenAppend(name: TEXT := NIL; prompt:= AppPrompt): Writer; (*Connects a writer to the file, called "name". If "name" is NIL it asks the user for a file name. It returns Stdio.stdout if the user enters "return" or Std ("#"). Creates a new file, if the specifeid file doesn't exist yet. If the file already exists, it positions the writer to the end of it.*) (*!!! Currently doesn't work on the PC !!! - it doesn't append*) PROCEDURE FileExists(name: TEXT): BOOLEAN; (*Returns TRUE iff the file exists.*) PROCEDURE CloseRead(VAR rd: Reader); (*Closes the file. Assigns NIL to rd - except rd is stdin.*) PROCEDURE CloseWrite(VAR wr: Writer); (*Flushes the writer and closes the file. Assigns NIL to wr - except wr is stdout. Close MUST be called if the content of the writer should be made permanent!*) PROCEDURE GetFileName(prompt:= PromptStart & PromptEnd): TEXT; (*Asks the user for a file name - actually a simple text. It is the very same procedure used by OpenRead and OpenWrite.*) END SF. ======================================================================= 24 === Date: 5 Jan 1995 21:21:39 GMT From: wobber@src.dec.com (Ted Wobber) Subject: Re: pickle The current version of pickle uses stack recursion to traverse data structures. It's possible that you have encountered a stack overflow. I believe that the depth limit is fairly small with the default stack size. If this is the case, there are currently two options: 1) increase your stack size, 2) write a "pickle special" that iterates through your data structure, rather than using recursion. You can find an example of the latter approach in the ListPkl module in the Net work Objects runtime. Ted Wobber DEC SRC ======================================================================= 25 === Date: Thu, 5 Jan 1995 18:35:34 GMT From: shang@corp.mot.com (David L. Shang) Subject: Re: Cows, Hogs & Farms In article <3e07c4$sup@muss.cis.McMaster.CA> u9442202@muss.cis.McMaster.CA (E.H. Schnetter) writes: > OK, here is an example in Sather. I didn't include much fancy stuff. > type $HERBIVORE is > -- an abstract HERBIVORE > name: STR; > eat (food: $PLANT); > end; -- type $HERBIVORE > > class HERBIVORE is > -- a general herbivore > attr name: STR; > create (name: STR): SAME is res::=new; res.name:=name; return res end; > eat (food: $PLANT) is raise "HERBIVORE::eat not defined\n" end; > end; -- class HERBIVORE > > class COW < $HERBIVORE is > include HERBIVORE; > eat (food: $PLANT) is > typecase food > when GRASS then > #OUT + "Cow " + name + " eats " + food.name + "\n"; > else > raise "Error: Cow " + name + " cannot eat " + food.name + "\n"; > end; -- typecase > end; -- eat > end; -- class COW > > class HOG < $HERBIVORE is > include HERBIVORE; > eat (food: $PLANT) is > typecase food > when CORN then > #OUT + "Hog " + name + " eats " + food.name + "\n"; > else > raise "Error: Hog " + name + " cannot eat " + food.name + "\n"; > end; -- typecase > end; -- eat > end; -- class HOG > > type $PLANT is > -- an abstract plant > name: STR; > end; -- type $PLANT > > class PLANT is > -- a general plant > const name: STR := "general plant"; > create: SAME is return new end; > end; -- class PLANT > > class GRASS < $PLANT is > include PLANT; > const name: STR := "grass"; > end; -- class GRASS > > class CORN < $PLANT is > include PLANT; > const name: STR := "corn"; > end; -- class CORN > > class FARM is > > attr livestock: ARRAY{$HERBIVORE}; -- cows and hogs > attr foodstuff: ARRAY{$PLANT}; -- grass and corn > > main is > -- Set up the farm > livestock := |#COW("Elsa"), #HOG("Peter Pan")|; > foodstuff := |#GRASS, #CORN|; > -- Feed everything to everyone > loop -- all the food > food::=foodstuff.elt!; > loop -- all the animals > protect > -- try to feed... > livestock.elt!.eat(food); > when STR then > -- oops, went wrong > #OUT + exception; > end; -- protect > end; -- loop animals > end; -- loop food > end; -- main > > end; -- class FARM > What you presented here is "Invaraince + Runtime Type Check", not a covariance. At a hogsty, if there is a plate saying "please feed me any plant", what will hapen? The sty will be full of rotten food that the hog does not eat. The plate should say "please feed me corn only". That is, the eat interface should tell its feeder the right food (if we suppose that a hog eat corn only). I'm not syaing that an interface should always tells the exact type. It depends on the desired semantics for that function. "eat" definitely needs an exact interface: hog eats corns only -- covariance "try" may have a vaguer interface: hog try all plant -- invaraince + runtime type check As I always said, a good language should provide all the possiblities. When hog knows "x" is a corn, it should be able to eat "x" without run-time type check: cornstuff: list[corn]; aHog.eat (cornstuff.first); When a herbivore knows "x" is the food that it eats, it should be able to eat "x" without run-time type check: [HerbivoreType <: herbivore] ( aHerbivore: HerbivoreType; food: HerbivoreType.FoodType ) enter aHerbivore.eat(food); end; But by Sather, run-time type check is always a neccessity. And by Eiffel's covariance, a system validation is required for the above case. By Cluster, runtime type check is not necessary for the above cases. It is only necessary when a herbivore cannot identify whether the food is its food. This happens only in the case of a reverse/cross assignment: foodstuff: list[plant]; ... aHog.eat (cornstuff.getfirst()); -- wrong! reverse assignment here -- We should use run time type check here: for each food in foodstuff do { when typeof(food) is corn do { aHog.eat(food); break; } } Run time type check can also be encapsulated by a hog's method, say "try": function hog::try(food: plant): plant enter when typeof(food) is corn do { eat (food); return nil; } return food; end; Back to the original example when both the food type and the animal type are unknown: livestock: list[herbivore]; foodstuff: list[plant]; ... livestock.getfirst().eat (foodstuff.getfirst()); -- wrong! cross assignment here -- we should write code like this: hungry: list[herbivore] = {}; unused: list[plant] = {}; for each animal in livestock do { for each food in foodstuff do { food:= animal.try(food); if food<>nil then { for each animal in hungry do { food:= animal.try(food); if food=nil then { hungry.remove(animal); break; } } if food<>nil then unused.add(food) } else { animal := nil; break; } } if (animal<>nil) then { for each food in unused do { food:= animal.try(food); if food=nil then { unused.remove(food); animal:=nil; break; } } if animal<>nil then hungry.add(animal); } } >From the above example, we can see that a runtime type mismaych is not necessarily an exception, nor a type error. The system is designed this way. It is the desired semantics. What is a type error? A type error happens only when the type voilates the requirement of the interface specification. hog eats grass is a type error, but hog tries grass is not a type error. Runtime type check is not an very important issue. The keypoint is that whether the language can say the way you want! David Shang ======================================================================= 26 === Date: Thu, 5 Jan 1995 19:17:51 GMT From: shang@corp.mot.com (David L. Shang) Subject: Cluster -- wsa Re: Cows, Hogs & Farms In article alfh@gyda.ifi.uio.no (Alf-Ivar Holm) writes: > In article <1995Jan3.223031@hobbit> hathawa2@marshall.edu (Mark S. Hathaway) writes: > > > I've not seen BETA and have never heard of Cluster. Could you provide > > a pointer-->ftp_site or other info. about them? :-) > > The BETA home page is found at: > > http://www.daimi.aau.dk/~beta/info > > I have no info on Cluster. > > Affi Cluster: An Informal Report. SIGPLAN Notices 26:1(1991) 57-76. Towards a Combinative Distributed OS in Cluster. IEEE CS Proc. 10th Intl. Conf. on Distributed Computing Systems, Paris, May, 1990. Type-Safe Reuse of Prototype Software. Proc. of 3rd SEKE Intl. Conf. Skokie, Illinois, 1991. Covariant Specification. SIGPLAN Notices 29:12(1994) 58-65. Covariant Deepsubtyping Reconsidered. Unpulished. Cluster in implemented under the DOS version in 1987. I don't consider Cluster is an execellent practical programming language. I completely redefined the object-oriented terminology and use an hermetic syntax, which makes the language hard to understand and to use. However, there are a number of new concepts which are useful for bridging the gap between the static and dynamic typing systems, for dealing with covariant deep subtyping safely, and for programming at a meta level to create, for example, various concurrent models, various object storage protocols, and so on. In the recent years of my study on various other OOPLs, I found that Cluster's concepts can be integrated with common notions very well. I am in the redesign of the language -- Cluster-2 -- or some other name. It is not just another language added to the pile. The sytax and semantics of the new language will be a natual extension to ordinary languages. The basic sytax will be Pascal-like with some C/C++'s convnient feature. But the expanded sytax and semantics will be far beyond the Pascal/C++ language. Just an example to show a little bit of the langauge style: function foo (input1: Type1; input2: Type2): OutputType declare // local declarations here enter // function body here; end; I use "enter" instead of "begin" because "enter" is not a counterpart of "end", rather, is in the equal position of "declare". People who knows Pascal will have a smooth transition to the above format. However, for people who want to explore a more flexible structure, they have to learn more. Firstly, when we say that "foo" is a "function", we actually mean that "foo" is a class and its superclass is "function". Therefore, language users can design their own super "function" classes like "process", "thread", "task", "remoteProcedure", "DatabaseTransaction", and so on. And then, they can have: process foo (input1: Type1; input2: Type2): OutputType declare // local declarations here enter // function body here; end; Calling "foo" will create a process. Secondly, the above format is a simple format from a more general format for a class: class foo is function declare // local declarations here enter (input1: Type1; input2: Type2): OutputType // function body here; end; You can have multiple input interfaces: class foo is function declare // local declarations here enter (input1: Type1): OutputType // function body1 here; enter (input1: Type1; input2: Type2): OutputType // function body2 here; end; Thirdly, class can be nested. You can have something like: class foo is task declare // local declarations of variables shared // by multiple threads thread thd1 ( ... ) // local class declaration enter // thd1 code end; thread thd2 ( ... ) enter // thd2 code end; ... enter ( (*input for task creation*) ) // tast initialization code; end; Note that both "task" and "thread" are user-defined classes. This is a simular form of a class declaration: class foo is object declare // local declarations of variables shared // by methods method mhd1 ( ... ) enter // mhd1 code end; method mhd2 ( ... ) enter // mhd2 code end; ... enter ( (*input for task creation*) ) // object construct (initilization) code; end; The difference is that the later is sequential while the fommer is concurrent. The key point is that the language does NOT provide built-in features like "thread", "method", rather, it provides only the framework to build those features. And this framework is uniformed by the class concept. Lastly, class can be parameterized. And the supported parameterization is not the coventional one, though the syntax is very similar to Eiffel's generic class. Generic classes are real classes and are fully interagted into the type system. David Shang ======================================================================= 27 === Date: 6 Jan 1995 04:31:34 GMT From: mbk@inls1.ucsd.edu (Matt Kennel) Subject: Re: Cows, Hogs & Farms David L. Shang (shang@corp.mot.com) wrote: : But by Sather, run-time type check is always a neccessity. And by Eiffel's : covariance, a system validation is required for the above case. : By Cluster, runtime type check is not necessary for the above cases. It is on ly : necessary when a herbivore cannot identify whether the food is its food. This : happens only in the case of a reverse/cross assignment: : : Runtime type check is not an very important issue. The keypoint is that wheth er : the language can say the way you want! : David Shang You can do most of Cluster's static solution in Sather, and I guess Eiffel. type $HERBIVORE is -- generic herbivore, no specific foodtype known. name:STR; eat_or_barf(food:$PLANT); type $HERBIVORE{FOODT < $PLANT} < $HERBIVORE is name:STR; eat(food:FOODT) -- must be able to eat end; class COW < $HERBIVORE{GRASS} is -- blah blah end; class HOG < $HERBIVORE{CORN} is -- blah blah end; class MONOCULTUREFARM{FOODT, ANIMALT < $HERBIVORE{FOODT} } is attr livestock : LIST{ANIMALT}; -- type is known at compile time attr foodstock : LIST{FOODT}; -- type is known dinnertime is loop elsie ::= livestock.elt!; dinner ::= foodstock.elt; elsie.eat(dinner); -- sooouie! no run-time check needed. end; end; end; class FREEFORMFARM is attr livestock : LIST{$HERBIVORE}; attr foodstock : LIST{$PLANT}; dinnertime is loop animal ::= livestock.elt!; dinner ::= foodstock.elt!; animal.eat_or_barf(dinner); -- run-time check in there. end; end; end; In Cluster I guess, you could have written MONOCULTUREFARM with just one type parameter (the ANIMAL) and then extract its preferred food from that. You can't do that in Sather I don't think but there isn't so much harm, as it's a compile time error to instantiate it with a bad combination of herbivore and food. cheers Matt -- -Matt Kennel mbk@inls1.ucsd.edu -Institute for Nonlinear Science, University of California, San Diego -*** AD: Archive for nonlinear dynamics papers & programs: FTP to -*** lyapunov.ucsd.edu, username "anonymous". ======================================================================= 28 === Date: Thu, 5 Jan 1995 12:09:46 GMT From: skj@oasis.icl.co.uk (Simon Johnston) Subject: Re: SRC M3 v. 3.4 out Bill Kalsow (kalsow@src.dec.com) wrote: : In article <3eegn0$dtp@hermes.unt.edu>, schaub@ponder.csci.unt.edu (Stephen S chaub) writes: : > Did I miss an announcement in this group? : No, you didn't miss the announcement. I usually let a few people : try out the system before announcing it. Indeed, they have already : reported a minor bug that I'll fix ASAP. Damn good idea IMHO. : Yes, 3.4 includes lots of changes: : - new ports to IRIX 5.2, FreeBSD, and Windows/NT(w/o Trestle) WNT?!? - I am a die hard OS2 developer (have been for 4+ years), weve been crying for an OS2 port for some time, though noone has had enough time. Could I ask what compiler youre using for WNT?, could we see a SRC OS2 version? : - a single top-level, build-everything m3makefile : - faster compilation (merged driver & pass0) : - runtime error message that include file and line number All good. : - m3browser, an HTTP server that provides "virtual Modula-3 space" Uh ? : - better shared library support for SOLsun and SPARC Howabout Linux? : - more robust type encodings for the debugger (but not Peter Klein's changes ) : - ParseParams and SLisp are back : - a floating-point version of the geometry package : - countless bug fixes All sounds good. : If you wait a few days the release will be stable. I can wait. ======================================================================= 29 === Date: 6 Jan 1995 10:12:29 GMT From: olevi@daimi.aau.dk (Ole Villumsen) Subject: Re: Cows, Hogs & Farms I haven't followed (nor understood) the entire discussion. But as far as I can see, Beta does not have the problem Sather is claimed to have. herbivore: (# foodType:< plant; (* virtual type *) eat: (# someFood: ^foodType; enter someFood[] do ... #); #); cow: herbivore (# foodType::< grass; (* further binding the virtual *) #); hog: herbivore (# foodType::< corn; #); Now we can go (assuming the variables are declared with the expected types: someGrass: ^grass; somePlant: ^plant; etc.): someGrass[] -> &aCow.eat; (* o.k.; typechecked at compile-time *) someGrass[] -> &aHog.eat; (* error, reported by compiler *) somePlant[] -> &aCow.eat; (* compiler will insert a runtime type check *) someCorn[] -> &aHerbivore.eat; (* again, runtime type check *) (if somePlant## // grass## then somePlant[] -> &aCow.eat; // corn## then somePlant[] -> &aHog.eat; else ... if); How's that? (The compiler will insert runtime type checks in the last example, unless you instruct it not to; maybe future versions of the compiler will be smart enough to "see" that it's not necessary.) Ole ======================================================================= 30 === Date: 6 Jan 1995 19:01:26 GMT From: kalsow@src.dec.com (Bill Kalsow) Subject: Re: SRC M3 v. 3.4 out In article , skj@oasis.icl.co.uk (Simon Johnston) w rites: > : Yes, 3.4 includes lots of changes: > : - new ports to IRIX 5.2, FreeBSD, and Windows/NT(w/o Trestle) > > WNT?!? - I am a die hard OS2 developer (have been for 4+ years), weve been > crying for an OS2 port for some time, though noone has had enough time. Could > I ask what compiler youre using for WNT?, could we see a SRC OS2 version? We use the Microsoft C compiler included in the NT/SDK for the few pieces of the system that are C. The Modula-3 source code is compiled directly to object code, none of the M3 -> IL -> gcc-tree -> RTL -> asm -> object nonsense that we use on Unix. Given our resource limits, we cannot port the system to all platforms. So far, we've only ported it to DS3100, ALPHA_OSF and NT386. All other ports were done outside SRC. A year ago we decided Chicago would be the next platform we targeted. NT was ready first, so we used it. I don't have any particular bias for or against OS/2. Given the number of people grumbling, somebody should port M3 to OS/2. I don't know why it hasn't happened yet. > : - m3browser, an HTTP server that provides "virtual Modula-3 space" > > Uh ? The browser is an HTTP server that provides WWW access to your installed Modula-3 system. It lets you browse and search in the module and type name spaces. > : - better shared library support for SOLsun and SPARC > > Howabout Linux? It's hard to keep up with the changes in Linux. We don't do much of the work for M3/Linux, we just distribute what others tell us. - Bill Kalsow ======================================================================= 31 === Date: Fri, 6 Jan 1995 16:49:48 GMT From: shang@corp.mot.com (David L. Shang) Subject: Re: Cows, Hogs & Farms In article <3eih36$94g@network.ucsd.edu> mbk@inls1.ucsd.edu (Matt Kennel) writes: > > You can do most of Cluster's static solution in Sather, and I guess Eiffel. > > ... > class MONOCULTUREFARM{FOODT, ANIMALT < $HERBIVORE{FOODT} } is > attr livestock : LIST{ANIMALT}; -- type is known at compile time > attr foodstock : LIST{FOODT}; -- type is known > ... My guess is that Eiffel can have a similar expression in its contrained generic class. How about Modula-3 and Ada9x's generic class? This form is slightly different in semantics from the Cluster's form: class MONOCULTUREFARM [ANIMALT <: HERBIVORE] attr livestock : list[ANIMALT]; attr foodstock : list[ANIMALT.FOODT]; ----- (1) or BETA's form: MONOCULTUREFARM (# ANIMALT :< HERBIVORE attr livestock : @list (# eleT::ANIMALT #); attr foodstock : @list (# eleT::ANIMALT.FOODT #); #) However, Cluster can provide the equivalent form to your Sather's vertion. There is a major difference between Cluster/BETA's generic class and Sather's. I'll discuss the major difference later. We first discuss the minor difference you mentioned: > In Cluster I guess, you could have written MONOCULTUREFARM with > just one type parameter (the ANIMAL) and then extract its preferred > food from that. You can't do that in Sather I don't think but > there isn't so much harm, as it's a compile time error to instantiate it > with a bad combination of herbivore and food. > Sometimes we should use two type parameters (in Cluster): class MONOCULTUREFARM [FOODT <: FOOD; ANIMALT <: HERBIVORE[FOODT]] attr livestock : list[ANIMALT]; attr foodstock : list[FOODT]; ----- (2) or sometimes we should use: class MONOCULTUREFARM [FOODT <: FOOD] attr livestock : list[<:ANIMAL[FOODT]]; attr foodstock : list[FOODT]; ----- (3) Semantics of (1), (2) and (3) are different. The first one means a farm with a set of animals of the same type, where a foodstock is provided to hold the food that those animals can eat. The second one mean a farm with a set of animals that eat the same food, and a foodstock is provided to hold the food. Those animals are not necessararily in the same type. Thus you can have a farm with mixed cows and sheeps. The third one mean farm with a foodstock, where a number of animals that eat its food are raised. It is basically the same as the second one: those animals are not necessararily in the same type. Thus you can put mixed cows and sheeps into the farm. The first one lay its stress on animals: farms are classified by animals. The food type is a dependent type to the animal type that the farm has. The last two lay their stress on food: farms are classified by food types. The animal type is a dependent type to the food type that the farm has. It might be difficult to argue which way is better for a farm, but as I said, the language should at least give the way that the speaker wants. Back to the major differece: Cluster's generic class are real classes but Sather's is not. Therefore, by Cluster, HERBIVORE[GRASS] is a subclass/subtype of HERBIVORE. By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of HERBIVORE. That's whay Sather cannot have the expression: ANIMALT < $HERBIVORE because HERBIVORE is not a class. What raised by the original post is really a covariance issue. Without the subclass relationship, it is meaningless to discuss the covariant relationship between COW/HOG and HERBIVORE in a type theory. Another drawback of Sather's generic class is that it cannot support a dynamic polymorphism or runtime binding based on class paramenters. Therefore, it is impposible to use Sather to specify a HETERCULTUREFARM composed of a number of MONOCULTUREFARMs -- a farm I called well-structured heterogeneous farm in my previous post. Runtime type check should be unnecessary for self-farming in this heterogeneous farm. David Shang ======================================================================= 32 === Date: 6 Jan 95 19:18:22 From: nayeri@gte.com (Farshad Nayeri) Subject: Re: Question on generics In article <9501062053.AA19195@spieler.pa.dec.com> Alan Heydon (heydon@usenet.pa.dec.com) points out where the sequence package resides. You can also view the sequence implementation or other SRC Modula-3 sources via anonymous ftp from ftp.vlsi.polymtl.ca, directory /lude/modula-3.34/run/poly/sun4.1_sparc/lib/m3/pkg. The URL for the sequence directory is: ftp://ftp.vlsi.polymtl.ca /lude/modula3-3.4/run/poly/sun4.1_sparc/lib/m3/pkg/libm3/src/sequence Another version of the sources with hyprtext markups exist within Bill Kalsow's Alphabetical Index for Modula-3 interfaces. See the SRC Modula-3 entry under the Modula-3 Mosaic Home Page for more information. -- Farshad -- Farshad Nayeri nayeri@gte.com ======================================================================= 33 === Date: 06 Jan 1995 19:51:22 GMT From: nayeri@gte.com (Farshad Nayeri) Subject: Re: SRC M3 v. 3.4 out In article <3eekcu$avv@src-news.pa.dec.com> kalsow@src.dec.com (Bill Kalsow) wr ites: > > Did I miss an announcement in this group? > > No, you didn't miss the announcement. I usually let a few people > try out the system before announcing it. Indeed, they have already > reported a minor bug that I'll fix ASAP. > > Yes, 3.4 includes lots of changes: > > [many wonderful additions and changes deleted.] A few of us have been testing the system to check for minor problems before it goes "public". I am happy to report that everything has been very smooth on SPARCs. (As Bill says, however, please wait until he announces it, as some of the minor changes haven't made it back to the release.) The compiler has been overhauled and the libraries re-organized, a couple of important architectures have been added. Yet, everything seems to work just fine. SRC Modula-3 is cleaner, much easier to install, more portable, and faster (at least on SPARCs). I'd like to take this chance to commend Bill Kalsow and the rest of the people at SRC who helped with the SRC Modula-3 distribution for doing such a great job! -- Farshad -- Farshad Nayeri nayeri@gte.com ======================================================================= 34 === Date: 7 Jan 1995 00:31:37 GMT From: mbk@inls1.ucsd.edu (Matt Kennel) Subject: Re: Cows, Hogs & Farms David L. Shang (shang@corp.mot.com) wrote: : Sometimes we should use two type parameters (in Cluster): : class MONOCULTUREFARM [FOODT <: FOOD; ANIMALT <: HERBIVORE[FOODT]] : attr livestock : list[ANIMALT]; : attr foodstock : list[FOODT]; : ----- (2) : or sometimes we should use: : class MONOCULTUREFARM [FOODT <: FOOD] : attr livestock : list[<:ANIMAL[FOODT]]; : attr foodstock : list[FOODT]; : ----- (3) : Semantics of (1), (2) and (3) are different. : The first one means a farm with a set of animals of the same type, where a : foodstock is provided to hold the food that those animals can eat. : The second one mean a farm with a set of animals that eat the same food, and a : foodstock is provided to hold the food. Those animals are not necessararily i n : the same type. Thus you can have a farm with mixed cows and sheeps. Ok you could do this in Sather by just saying illinois: MONOCULTUREFARM{GRASS,$HERBIVORE{GRASS}} and so the animals in 'illinois' would be anything that could eat grass. : The third one mean farm with a foodstock, where a number of animals that eat : its food are raised. It is basically the same as the second one: those animal s : are not necessararily in the same type. Thus you can put mixed cows and sheep s : into the farm. : The first one lay its stress on animals: farms are classified by animals. The : food type is a dependent type to the animal type that the farm has. : The last two lay their stress on food: farms are classified by food types. Th e : animal type is a dependent type to the food type that the farm has. : It might be difficult to argue which way is better for a farm, but as I said, : the language should at least give the way that the speaker wants. Right it's a limitation that the generic type parameter is nameless. : Back to the major differece: Cluster's generic class are real classes but : Sather's is not. Therefore, by Cluster, HERBIVORE[GRASS] is a subclass/subtyp e : of HERBIVORE. By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of : HERBIVORE. That's whay Sather cannot have the expression: : ANIMALT < $HERBIVORE : because HERBIVORE is not a class. OK. But you could write a type $HERBIVORE > $HERBIVORE{FOODT} that specified just those features not dependent on FOODT (say "eat_or_barf(x:$PLANT)"), and so all COW's and HOG's could be a subclass of some $HERBIVORE, if somewhere else you needed to classify ANIMAL's on the basis on whether or not they were an $HEBIVORE. : What raised by the original post is really a covariance issue. Without the : subclass relationship, it is meaningless to discuss the covariant relationshi p : between COW/HOG and HERBIVORE in a type theory. : Another drawback of Sather's generic class is that it cannot support a dynami c : polymorphism or runtime binding based on class paramenters. : Therefore, it is : impposible to use Sather to specify a HETERCULTUREFARM composed of a number o f : MONOCULTUREFARMs -- a farm I called well-structured heterogeneous farm in my : previous post. Runtime type check should be unnecessary for self-farming in : this heterogeneous farm. What is this exactly? I guess I don't quite see. Sather and Eiffel et cetera are statically typed in this sense: there is no notion of a variable which contains a "type" that can be modified at run-time, and new objects made in a fashion which depend on this run-time type as a generic parameter. I guess I don't quite understand the implications or meaning of when this is not the case. All type parameters must be resolved at compile time; there must be some performance benefit, yes? For example if you have run-time computatble types, you have to conceivably deal with all legal specializations of some generic type, for the type parameter might be some value comptuted at run-time which in general might be unknown. : David Shang -- -Matt Kennel mbk@inls1.ucsd.edu -Institute for Nonlinear Science, University of California, San Diego -*** AD: Archive for nonlinear dynamics papers & programs: FTP to -*** lyapunov.ucsd.edu, username "anonymous". ======================================================================= 35 === Date: 06 Jan 1995 21:06:20 GMT From: schwartz@galapagos.cse.psu.edu (Scott Schwartz) Subject: Re: SRC M3 v. 3.4 out nayeri@gte.com (Farshad Nayeri) writes: SRC Modula-3 is cleaner, much easier to install, more portable, and faster (at least on SPARCs). Has the runtime system gotten any smaller? ======================================================================= 36 === Date: Fri, 6 Jan 1995 18:44:58 GMT From: rsutc@twu.ca (Rick Sutcliffe) Subject: Re: Question on generics In article <9501050242.AA08630@spieler.pa.dec.com>, heydon@usenet.pa.dec.com wrote: > As Bill Kalsow pointed out in a recent message to comp.lang.modula3, > the generic implementation of Sequences gives an example of this > situation: > > > For example, see the Modula-3 Sequence generic. There are two > > interfaces (a public and a friends one). The public interface is > > parameterized by the element type's interface, the private interface > > is parameterized by the element type and the public interface. And > > finally, the implementation is parameterized by all three. > Could you point us to where this example is, please. Rick -- Rick Sutcliffe Assoc. Prof. Computing/Math Trinity Western University Canadian Chair, WG13. Not an official spokesperson for TWU or WG13 ======================================================================= 37 === Date: Fri, 06 Jan 95 12:53:31 -0800 From: heydon@usenet.pa.dec.com Subject: Re: Question on generics > Could you point us to where this [Sequence] example is, please. The generic Sequence interfaces and implementations live in the package named "sequence": heydon> ls /proj/m3/pkg/sequence/src Sequence.ig Sequence.mg gen.sh sequence.tmpl Sequence.lm3 SequenceRep.ig m3makefile string.lsl To read them, you need to have installed v3.X of the Modula-3 distribution. If you don't have the Modula-3 distribution, see the Modula-3 FAQ for instructions on how to FTP it from gatekeeper.dec.com. - Allan -------------------------------------------------------------------- Allan Heydon Digital Equipment Corporation heydon@pa.dec.com Systems Research Center (415) 853-2142 130 Lytton Avenue (415) 853-2104 (FAX) Palo Alto, CA 94301 ======================================================================= 38 === Date: Sat, 7 Jan 1995 10:20:52 -0500 From: Philip Siming Zhan Subject: How to install M3? I just got the src files for M3 compiler, lib, etc., for Linux from sunsite FTP site. (src-m3-3.3l2.strip.tar.gz, m3gdb.tgz and *.lsm and *.html files). After uncompressed the files, I found out that there are pre-compiled binaries, src files and lib files. BUT there is no instruction how to install the packages (setup the path and env variables, etc.). Is it enough just by setting binaries file path? I am new to M3 (taking the course this semester). Phil ======================================================================= 39 === Date: Sat, 7 Jan 1995 15:20:51 GMT From: szhan@watdragon.uwaterloo.ca (Philip Siming Zhan) Subject: How to install M3? I just got the src files for M3 compiler, lib, etc., for Linux from sunsite FTP site. (src-m3-3.3l2.strip.tar.gz, m3gdb.tgz and *.lsm and *.html files). After uncompressed the files, I found out that there are pre-compiled binaries, src files and lib files. BUT there is no instruction how to install the packages (setup the path and env variables, etc.). Is it enough just by setting binaries file path? I am new to M3 (taking the course this semester). Phil ======================================================================= 40 === Date: 8 Jan 1995 11:34:59 GMT From: and1000@cus.cam.ac.uk (Austin Donnelly) Subject: Re: Linux LOCKs In article , Michel Dagenais wrote: >In article <1995Jan3.000902.2586@clio.demon.co.uk> g@clio.demon.co.uk >(Gareth Webber) writes: > > Is there a problem with the LOCKs set up under Linux M3 version 3.3 as I > have a program which behaves perfectly (apart from concurrency problems...) > without locks but as soon as I protect data to remove the concurency issues > the program gives a deferencing NIL pointer exception. Is this a known > problem ? I am using the larger of Michael Dagenais's versions. > >No known problems in this area. Concurrency is tricky to get right... and >to debug. > At a wild guess, are you using NEW() to get yourself a mutex? Eg: VAR mu:= NEW(MUTEX); LOCK mu (* burble *) END; Since MUTEX <: ROOT, it needs storage allocated on the heap for it. Austin ======================================================================= 41 === Date: 9 Jan 95 00:56:27 EDT From: hathawa2@marshall.edu (Mark S. Hathaway) Subject: Re: Cows, Hogs & Farms > In article <1995Jan6.164948.4782@schbbs.mot.com>, > shang@corp.mot.com (David L. Shang) writes: >> In article <3eih36$94g@network.ucsd.edu> >> mbk@inls1.ucsd.edu (Matt Kennel) writes: >> ... >> You can do most of Cluster's static solution in Sather, and I guess Eiffel. >> >> ... >> class MONOCULTUREFARM{FOODT, ANIMALT < $HERBIVORE{FOODT} } is >> attr livestock : LIST{ANIMALT}; -- type is known at compile time >> attr foodstock : LIST{FOODT}; -- type is known >> ... Should there be a $FOOD abstract type used here ( "FOODT < $FOOD" )? Would there have to be an "include HERBIVORE" and maybe "include FOOD" for this to work? How would that be done? > This form is slightly different in semantics from the Cluster's form: > > class MONOCULTUREFARM [ANIMALT <: HERBIVORE] > attr livestock : list[ANIMALT]; > attr foodstock : list[ANIMALT.FOODT]; > ----- (1) Does Cluster separate the subtyping and inheritance as Sather does? Is the use of "ANIMALT <: HERBIVORE" a convenience or requirement? So, ANIMALT.FOODT implies that a particular food is associated with a particular animal? How can it be a HERBIVORE and yet eat only one kind of plant? > or BETA's form: > > MONOCULTUREFARM > (# ANIMALT :< HERBIVORE > attr livestock : @list (# eleT::ANIMALT #); > attr foodstock : @list (# eleT::ANIMALT.FOODT #); > #) It's not especially readable, is it? Is it really ":<" rather than Cluster's "<:"? Very funny contrarianism! Since "ANIMALT :< HERBIVORE" is inside the "(#" & "#)" enclosure I wouldn't guess you could create a MONOCULTUREFARM(COW). Since there's no "class" in front of "MONOCULTUREFARM" I'd guess that everything in BETA is a class or pattern or somethin', huh? So, by having only one "form" it can be understood what this is. Is there any special notation to differentiate a main program from these others? Do any of these MONOCULTUREFARMs (Sather, Cluster or BETA) inherit from FARM or are they the lowest base of farm that will exist in this class hierarchy? [snipped a bunch] > It might be difficult to argue which way is better for a farm, but as I > said, the language should at least give the way that the speaker wants. Yes, the language should provide a way to express something. That's why I cringe when I see syntax like BETA's. :-) How about... class MonocultureFarm ( food is plant, animal is herbivore ) is procedure feed (); end MonocultureFarm; class MonocultureFarm body is import list; object livestock is list(animal); foodstock is list(food); procedure feed ( get livestock is in out list(animal); get foodstock is in out list(food) ) is begin ... end feed; end MonocultureFarm; program temp is import MonocultureFarm; object myfarm is MonocultureFarm(corn,hog); begin myfarm.feed(); end temp. Since it's not like a procedure within a module the parameters of MonocultureFarm which are of type/class plant and herbivore aren't "import"ed first. That's a little awkward, but these other languages (BETA, Cluster, Sather) don't seem to need the "import". Is it no longer regarded as necessary? > Back to the major differece: > > Cluster's generic class are real classes but Sather's is not. > Therefore, by Cluster, HERBIVORE[GRASS] is a subclass/subtype > of HERBIVORE. I hesitate to ask what kind of GRASS is an HERBIVORE. > By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of HERBIVORE. > That's whay Sather cannot have the expression: > > ANIMALT < $HERBIVORE > > because HERBIVORE is not a class. I asked (above) if Sather would also have to use an "include HERBIVORE" to comlete the equation. This comparison of Cluster's inheritance scheme to Sather's asks the same question. If you're inheriting an HERBIVORE then how can it be an HERBIVORE that only eats GRASS? It seems to me that the tying together of the specific food(s) to the animal has to be done at a higher level of abstraction -- probably in the algorithm which represents the farmer's actions. You can put a COW in a field of several plants, but you can't force it to eat only GRASS. A HERBIVORE COW might choose to eat clover. :-) Mark S. Hathaway ======================================================================= 42 === Date: 9 Jan 95 02:10:43 EDT From: hathawa2@marshall.edu (Mark S. Hathaway) Subject: Re: Cows, Hogs & Farms > In article <1995Jan4.191910.13968@schbbs.mot.com>, > shang@corp.mot.com (David L. Shang) writes: >> In article <1995Jan3.223031@hobbit> >> hathawa2@marshall.edu (Mark S. Hathaway) wrote: [ much deleted here and there throughout this post ] > In reality, we always have exceptions. We can use covariance to rule out a > general principle and use run-time type check for a few exceptions. As to > the animal example, it is clearly worthwhile to divide animals into > herbivires, carnivores and (?)(animals eating both food) according to the > type of their food. We can use covaraince. But it might be very hard to > rule out a general principle for the futher classification for a certain > number of animals. It's herbivore, carnivore & omnivore. Eats plants, meat & pizza with everything! :-) > We are not developing a commercial software for zoologists, are we? These > are only padagogical examples. Be wise to make things as simple as possible > -- just for the key points you want to say. I have created a few examples in the past which thoroughly confused people because they weren't realistic enough. I'm trying to avoid the sins of my past. >>> class field [FoodType <: plant] >>> function getCrop(): FoodType; >>> end field; >> Isn't a generic field which can grow any plant more correct? Doesn't the >> notation you've given tie one specific plant to the field and not allow for >> future crop rotations? Farmers plant different crops to avoid depleting >> the soil too much. > This is an abstract field. No object can be intantiated by the class > unless you associate it with a plant type. Yes, but after you've instantiated an object with a particular plant, can you then change the plant? >>> class farm [AnimalType <: herbivore] is >>> animals: list [MemberType = AnimalType]; >>> fields: list [MemberType = field [FoodType = AnimalType.FoodType]]; >>> function getRipeFood(): AnimalType.FoodType; >>> -- get the ripe food from one of its fields. >>> ... >>> end farm; >>> > class hog_farm is farm [AnimalType = hog]; > class cow_farm is farm [AnimalType = cow]; > Note that the generic classes I presented above are not conventional generic > classes. You cannot have this by Eiffel's generic class, which is not a real > class, and hence it is meaningless to discuss the subclass relationship > between a generic class and the class instantiated by the generic class. I like the looks of class farm above. It's quite similar to what I've been developing in pseudo-code. I've used "(param)" instead of "[param]" though. I'd certainly be interested to read further discussion on the differences between these classes and those of Sather & Eiffel. There seem to be some rather major differences. BTW, are these examples of yours in Cluster? >>> program farming is >>> c is cow_farm; >>> h is hog_farm; >>> begin >>> ... >>> for each animal in c.animals do animal.eat(aCorn); -- wrong! >>> for each animal in c.animals do animal.eat(aGrass); -- correct. >>> for each animal in c.animals do animal.eat (c.getRipeFood ()); >>> -- correct. >>> end farming. >>> Secondly, you could have an ill-structured heterogeneous farm where >>> various type of herbivores are raised at random fields. That is, there >>> is no relationship between a field type and a herbivore type: >>> >>> class farm is >>> animals: list [MemberType <: herbivore]; >>> fields: list [MemberType <: field]; >>> function getRipeFood(): plant; >>> -- get the ripe food from one of its fields. >>> end farm; >> Why do you say "animals: list [MemberType <: herbivore];" >> instead of animals: list [ herbivore ]; > The latter is equivalent to: > > animals: list [ MemberType = herbivore ]; > > where "animals" is not a polymorphic (heterogeneous) variable. Are you saying that without "<:" it won't recognize "herbivore" as a class from which to inherit; and that in the second case it would simply "think" "animals: list [ herbivore ];" refers to some "herbivore" other than the class? >>> procedure self_farming is (f is in farm) >>> begin >>> ... >>> for each animal in f.animals do animal.eat(f.getRipeFood ()); -- wrong! >>> for each animal in f.animals do >>> plant food := f.getRipeFood(); >>> when typeof(animal).Foodtype = typeof(food) do >>> animal.eat(food); -- correct >>> end >>> end self_farming. Looks decent. But, it doesn't make me want to take up farming. :-) Mark S. Hathaway ======================================================================= 43 === Date: Mon, 09 Jan 95 10:32:53 -0800 From: heydon@pa.dec.com Subject: Re: Question on generics In a previous message <9501062053.AA19195@spieler.pa.dec.com>, I wrote: > The generic Sequence interfaces and implementations live in the > package named "sequence": In separate e-mail, Farshad Nayeri pointed out to me that "sequence" does not have its own separate package in the public distribution. Instead, it lives in the "src/sequence" directory of the "libm3" package. Alternatively, the "Sequence.i3", "SequenceRep.i3", and "Sequence.m3" files are available on the Modula-3 WWW server that Bill has set up. The URL for the server's home page is: http://www.research.digital.com/SRC/modula-3/html/home.html The URL for the alphabetical index for Modula-3 sources is: http://www.research.digital.com/SRC/m3sources/html/INDEX.html The "Sequence" and "SequenceRep" generic interfaces, as well as the "Sequence" generic module, are all reachable from this index. - Allan -------------------------------------------------------------------- Allan Heydon Digital Equipment Corporation heydon@pa.dec.com Systems Research Center (415) 853-2142 130 Lytton Avenue (415) 853-2104 (FAX) Palo Alto, CA 94301 ======================================================================= 44 === Date: 9 Jan 1995 15:21:56 GMT From: jacobse@daimi.aau.dk (Jacob Seligmann) Subject: Re: Cows, Hogs & Farms Mark S. Hathaway wrote: > > or BETA's form: > > > > MONOCULTUREFARM > > (# ANIMALT :< HERBIVORE > > attr livestock : @list (# eleT::ANIMALT #); > > attr foodstock : @list (# eleT::ANIMALT.FOODT #); > > #) > > [...] > > Since "ANIMALT :< HERBIVORE" is inside the "(#" & "#)" enclosure I wouldn't > guess you could create a MONOCULTUREFARM(COW). But you can! In BETA, you would say MONOCULTUREFARM (# ANIMALT :: COW #) to denote a subclass of MONOCULTUREFARM in which the virtual attribute ANIMALT is further-bound to COW. That is, genericity is handled through inheritance and virtuals alone - there is no special template mechanism whatsoever! Of course, this is only possible because BETA allows virtual types, not just virtual methods. This is typical of how BETA offers only a few basic mechanisms, but makes them powerful and orthogonal, so that they can be combined to obtain a wide range of features for which most other languages provide special mechanisms. > It's not especially readable, is it? > [...] > Yes, the language should provide a way to express something. That's why > I cringe when I see syntax like BETA's. :-) The reverse sign of the minimalism coin, of course, is the need to use more syntax to express a feature which is obtainable through a special (nice-looking) construct in another language. I agree that MONOCULTUREFARM [COW] or even MONOCULTUREFARM [ ANIMALT = COW ] is easier to read than MONOCULTUREFARM (# ANIMALT :: COW #) However, when working with BETA, you quickly learn to recognize use patterns such as the one above. It's not a big deal in practice, really. Best regards, /Jacob Seligmann ------------------------------------------------------------------------ Computer Science Department Phone: +45 89 42 31 88 Aarhus University Direct: +45 89 42 32 74 Ny Munkegade 116 Fax: +45 89 42 32 55 DK-8000 Aarhus C, Denmark E-mail: jacobse@daimi.aau.dk ------------------------------------------------------------------------ More info on BETA is available at URL http://www.daimi.aau.dk/~beta/info ------------------------------------------------------------------------ ======================================================================= 45 === Date: 09 Jan 1995 18:40:58 GMT From: jackg@downhaul.crc.ricoh.com (Jack Greenbaum) Subject: Circular imports M3 does not allow interfaces to cicularly import each other. This comes up when I'm trying to do the following: A graph contains Node and Edge objects. These are distinct object types. I would like the Node objects to contain fields of type Edge, and the Edge object to contain fields of type Node so that the graph is easily traversable. In order to do this the Node interface must import the Edge interface so that an edge may be added to the node. As well the Edge interface must import Node so that a node may be added to an edge. Ooops! We're hosed. One way to solve this is to have a Graph interface which exports both Edge and Node. Everyone is in the same interface, so no problem. Is another way to do this to have multiple interfaces to Node, where one of those interfaces is imported by Edge and doesn't make reference to Edge? Then a single module will reveal the "One True Node" and export all interfaces. Does "System Programming with Modula-3" discuss such issues? -- Jack Greenbaum -- Research Engineer, Ricoh California Research Center --------------------------------------------------------------------- Digital: jackg@crc.ricoh.com | http://www.crc.ricoh.com/~jackg --------------------------------------------------------------------- Analog: (415) 496-5711 voice | 2882 Sand Hill Rd. Suite 115 (415) 854-8740 fax | Menlo Park, CA 94025-7002 --------------------------------------------------------------------- -- Jack Greenbaum -- Research Engineer, Ricoh California Research Center --------------------------------------------------------------------- Digital: jackg@crc.ricoh.com | http://www.crc.ricoh.com/~jackg --------------------------------------------------------------------- ======================================================================= 46 === Date: 9 Jan 1995 15:25:59 GMT From: olevi@daimi.aau.dk (Ole Villumsen) Subject: Beta syntax (was Re: Cows, Hogs & Farms) In Danish schools, we learn that multiplication is denoted by a dot (or nothing at all: xy means x times y), and a colon : is used for division. When I started learning programming, I learned that * meant multiplication, and / was used for division. It's no problem: I got accustomed to * and / very quickly and never gave it a second's thought. It's the same with Beta: A few things that are used often have a short notation in Beta that every programmer uses without thinking about it; but they (and especially the sum of them) are apt to confuse people who don't know Beta. For instance (from David L. Shang 's posting): >> or BETA's form: >> >> MONOCULTUREFARM >> (# ANIMALT :< HERBIVORE >> attr livestock : @list (# eleT::ANIMALT #); >> attr foodstock : @list (# eleT::ANIMALT.FOODT #); >> #) The "attr" in the above should be deleted. The "@" later in the same lines do the job; which is very convenient once you know it. That's Beta. I'll return to "@" below. (Also, there should be a colon : after MONOCULTUREFARM - it wasn't important, as the original posting didn't discuss syntax details; but we do now.) Mark S. Hathaway asks: >It's not especially readable, is it? Most people dislike Beta's syntax at first. As a more experienced user I'd say, it's very straightforward to read once you've learned it. But beautiful - it's not. >Is it really ":<" rather than Cluster's "<:"? Very funny contrarianism! >Since "ANIMALT :< HERBIVORE" is inside the "(#" & "#)" enclosure I wouldn't >guess you could create a MONOCULTUREFARM(COW). In Beta, you create a MONOCULTUREFARM(# animalT::cow #) I suppose it's the same, only with a different syntax. Just like you create a list (# eleT::ANIMALT #) instead of a list(animalT). ("List" alone would be a list that could contain any type of objects.) Not knowing Cluster, I don't think Beta's ":<" and Cluster's "<:" have exactly the same meaning. Maybe it's a pure coincidence that the two languages include symbols made up of the same 2 characters. Beta uses x : ... for an ordinary (static) declaration x :< ... for a virtual declaration x ::< ... for a further binding (extension) of a virtual x :: ... for a final binding (after which x is no longer virtual) It's easy and consistent, isn't it? >Since there's no "class" in front of "MONOCULTUREFARM" I'd guess that >everything in BETA is a class or pattern or somethin', huh? So, by >having only one "form" it can be understood what this is. ... Again, you have to know the language - but you'll learn very quickly, since these are the details the Beta programmer uses every day and soon stops thinking about: x: (# ... #); (* declares a pattern (e.g. a class) *) x: @ ... ; (* declares a static instance (object) *) x: ^ ... ; (* declares a dynamic reference to an instance *) > ... Is there >any special notation to differentiate a main program from these others? The main program is preceeded by "--- program: descriptor ---" (which is strictly speaking part of the fragment language, not part of Beta itself). >Yes, the language should provide a way to express something. That's why >I cringe when I see syntax like BETA's. :-) You won't find a programming langauge with greater expressive power than Beta :-) :-) >Since it's not like a procedure within a module the parameters of >MonocultureFarm which are of type/class plant and herbivore aren't >"import"ed first. That's a little awkward, but these other languages >(BETA, Cluster, Sather) don't seem to need the "import". Is it no >longer regarded as necessary? If plant and herbivore are defined in different files (fragment groups), you should do an "include" of those files. Again, this is done using the fragment language. If you have other Beta questions, please ask. You can also read more in the Beta FAQ file. I have set follow-ups to comp.lang.beta. Ole -- Ole Villumsen, Computer Science Department, Aarhus University, Denmark A European Union is a self contradiction. Either the European will kill the union, or the union will kill the European. ======================================================================= 47 === Date: Mon, 9 Jan 1995 18:36:27 GMT From: shang@corp.mot.com (David L. Shang) Subject: Re: Cows, Hogs & Farms In article <3eknd9$noi@network.ucsd.edu> mbk@inls1.ucsd.edu (Matt Kennel) writes: > Ok you could do this in Sather by just saying > > illinois: MONOCULTUREFARM{GRASS,$HERBIVORE{GRASS}} > > and so the animals in 'illinois' would be anything that could eat grass. This is my Cluster's version in (2), which I used to describe an euivalent form to the Sather's orignal version. Now you translate it back into Sather. To use MONOCULTUREFARM in version (2), Cluster has the equivalent form: illinois: MONOCULTUREFARM[GRASS,HERBIVORE[GRASS]] where illinois could be a farm with cows, sheeps, and any other creatures that are subclasses of HERBIVORE[GRASS], or, illinois: MONOCULTUREFARM[GRASS,COW] where illinois is a cow farm if we suppose that COW be a subclass of HERBIVORE[GRASS]. In Cluster's version (1), you can simply written: illinois: MONOCULTUREFARM[HERBIVORE[GRASS]], or illinois: MONOCULTUREFARM[COW] In Cluster's version (3), you can simply written: illinois: MONOCULTUREFARM[GRASS] > : ... by Cluster, HERBIVORE[GRASS] is a subclass/subtype > : of HERBIVORE. By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of > : HERBIVORE. That's whay Sather cannot have the expression: > > : ANIMALT < $HERBIVORE > > : because HERBIVORE is not a class. > > OK. But you could write a type $HERBIVORE > $HERBIVORE{FOODT} that > specified just those features not dependent on FOODT (say > "eat_or_barf(x:$PLANT)"), and so all COW's and HOG's could be a subclass of > some $HERBIVORE, if somewhere else you needed to classify ANIMAL's on the > basis on whether or not they were an $HEBIVORE. > Is it a little bit strange to have a hieratchy like: $HERBIVORE > $HERBIVORE{FOODT} > COW ? Is HERBIVORE{FOODT} or HERBIVORE{GRASS} a real class by Sather? If they are not, what is the relationship between: HERBIVORE > HERBIVORE{FOODT} and HERBIVORE{FOODT} > COW ? The only valid relationship I see is: HERBIVORE > COW HERBIVORE dose not have any information on the food type. If we try to classify herbivores accroding to their food types, this HERBIVORE class could not help more than what we have like this: ANY_OBJECT > COW > > All type parameters must be resolved at compile time; > there must be some performance benefit, yes? Not necessarily true. Class paprameters can be resovled at run time by Cluster. This is done by dynamic binding. I don't see any significant performance slowing down by just an indirect access when a dynamic binding must be performed. The benefit is the power of dynamic typing. For example: farm: MONOCULTUREFARM; // a polymorphic farm variable; creature: HERBIVORE; // a polymorphic herbivore animal varaible; ... creature := aMixedmarket.GetHerbivoreFromMixedMarket(); // at this point, we do not know the exact type of // the creature. ... farm := new MONOCULTUREFARM[typeof(creature)]; // create a farm in a new class accroding to // the type of the creature when typeof(farm).ANIMALT is typeof(creature) do farm.add(creature); The last type assurance statement is used for type-safety, because creature -> farm.add's input is a cross assignment, which, like a reverse assignment, violates the substitution law. The compiler won't let the program pass if the type assurance statement is not used. However, the type assurance statement may not necessary accroding to the context. It could be eliminated by optimization. It is the same case as: var i: integer := 4; if i=4 then i++; Therefore, all the programs passed by the compiler will be type safe. No system level type check or data flow analysis is required for type safety. They are required only for the purpose of code optimization. David Shang ======================================================================= 48 === Date: Mon, 9 Jan 1995 20:35:28 GMT From: shang@corp.mot.com (David L. Shang) Subject: Re: Cows, Hogs & Farms In article <1995Jan9.005627@hobbit> writes: > > In article <1995Jan6.164948.4782@schbbs.mot.com>, > > shang@corp.mot.com (David L. Shang) writes: > > This form is slightly different in semantics from the Cluster's form: > > > > class MONOCULTUREFARM [ANIMALT <: HERBIVORE] > > attr livestock : list[ANIMALT]; > > attr foodstock : list[ANIMALT.FOODT]; > > ----- (1) > > Does Cluster separate the subtyping and inheritance as Sather does? > No. Subtype and subclass are the samething by Cluster. > Is the use of "ANIMALT <: HERBIVORE" a convenience or requirement? For a MONOCULTUREFARM classified by the type herbivore animals, using a class parameter "ANIMALT <: HERBIVORE" is a requirement, otherwise, a MONOCULTUREFARM will be a heterogenrous farm. > > So, ANIMALT.FOODT implies that a particular food is associated with a > particular animal? How can it be a HERBIVORE and yet eat only one kind > of plant? It cannot be in reality. I am reluctant to complicate this example. But to describe a HERBIVORE that eat more than one kinds of food is also possible by multiple inheritance: class COW is HERBIVORE [ FOODT = GRASS ], HERBIVORE [ FOODT = HAY ], ... But there will be a problem when you try to substitude ANIMALT with COW: class MONOCULTUREFARM [ANIMALT <: HERBIVORE] attr livestock : list[ANIMALT]; attr foodstock : list[ANIMALT.FOODT]; cow_farm: MONOCULTUREFARM [COW]; As COW has multiple bases: HERBIVORE[GRASS], HERBIVORE[HAY], ..., which base is used? You have to specify: grass_farm: MONOCULTUREFARM [COW as HERBIVORE[GRASS]]; or hay_farm: MONOCULTUREFARM [COW as HERBIVORE[HAY]]; In fact, the MONOCULTUREFARM designed here is no longer suitable for an animal that eats more than one plant, becase it only keeps one kind of food. However, if we could figure out a subclass of PLANT for COW, say, COW_FOOD, ther is not problem to have HERBIVORE[COW_FOOD] and the MONOCULTUREFARM as define above. Unfortuantely, in most cases, it is almost impossible to classify herbivores according to the food type they eat. This is probably a bad example to demonstrate the covariance. I whould like to use the herbivore/carnivore classification example. > > Do any of these MONOCULTUREFARMs (Sather, Cluster or BETA) inherit > from FARM or are they the lowest base of farm that will exist in this > class hierarchy? > By Cluster, I guess BETA too, MONOCULTUREFARM[ANIMAT<:HERBIVORE] could be the lowest base of farm that exist in the class hierarchy. but no Sather, since a generci class is not a real class by Sather. We can have this hierarchy: (1)MONOCULTURE[ANIMAT<:HERBIVORE] (2)MONOCULTURE[ANIMAT<:HERBIVORE] (3)MONOCULTURE[HERBIVORE[PLANT]] (4)MONOCULTURE[COW] (5)MONOCULTURE[HOG] Note that ANIMAT is fixed to HERBIVORE[PLANT] in (3). It is a MONOCULTURE farm if we don't care the further division of the herbivores according to their animal food types. But we may still have an interest in the further division according to other things by adding addtional class parameters in subclasses. > How about... > > class MonocultureFarm ( food is plant, animal is herbivore ) is > procedure feed (); > end MonocultureFarm; > > class MonocultureFarm body is > import list; > object livestock is list(animal); > foodstock is list(food); > procedure feed ( get livestock is in out list(animal); > get foodstock is in out list(food) ) is Why should you provide additional input/output parameters for feed in the class body? Why should the feed interfaces be different? > begin > ... > end feed; > end MonocultureFarm; > > program temp is > import MonocultureFarm; > object myfarm is MonocultureFarm(corn,hog); How about: object myfarm is MonocultureFarm(corn,cow); if a cow dose not eat corn? > begin > myfarm.feed(); > end temp. > > Since it's not like a procedure within a module the parameters of > MonocultureFarm which are of type/class plant and herbivore aren't > "import"ed first. That's a little awkward, but these other languages > (BETA, Cluster, Sather) don't seem to need the "import". Is it no > longer regarded as necessary? > "import", or "use" decalrations is not the subject we discussed here. BETA and Cluster do need these declarations to have a complete program. > > If you're inheriting an HERBIVORE then how can it be an HERBIVORE that > only eats GRASS? Why not? Of cuase if you define a HERBIVORE that can eat ANY plant, a HERBIVORE that only eats GRASS cannot be a subclass. But if we define a HERBIVORE that can eat a certain type of food which is a subclass of PLANT, why cannot a HERBIVORE that only eats GRASS be a subclass? > > You can put a COW in a field of several plants, but you can't force it > to eat only GRASS. A HERBIVORE COW might choose to eat clover. Agian, I don't consider this herbivore example a good example to demonstrate covariance. Lets just take the assumption that COW eat GRASS only and HOG eat CORN only, and make things simple. If you don't like the assumption, we may consider the animal/herbivore/carnivore example. David Shang ======================================================================= 49 === Date: 9 Jan 95 08:33:40 From: dagenais@notung.vlsi.polymtl.ca (Michel Dagenais) Subject: Re: How to install M3? I just got the src files for M3 compiler, lib, etc., for Linux from sunsite FTP site. (src-m3-3.3l2.strip.tar.gz, m3gdb.tgz and *.lsm and *.html files). After uncompressed the files, I found out that there are pre-compiled binaries, src files and lib files. BUT there is no instruction how to install the packages (setup the path and env variables, etc.). Is it enough just by setting binaries file path? These files originate from ftp.vlsi.polymtl.ca:pub/m3/linux. There you will find a README. Basically you need to set your PATH variable to point to /usr/local/soft/modula3-3.3/bin and your LD_LIBRARY_PATH to /usr/local/soft/modula3-3.3/lib/m3/LINUX. -- Prof. Michel Dagenais dagenais@vlsi.polymtl.ca Dept of Electrical and Computer Eng. Ecole Polytechnique de Montreal tel: (514) 340-4029 ======================================================================= 50 === Date: 10 Jan 1995 07:29:47 GMT From: bhawley@orion.it.luc.edu (Brian Hawley) Subject: Re: Circular imports Jack Greenbaum (jackg@downhaul.crc.ricoh.com) wrote: : M3 does not allow interfaces to cicularly import each other. This comes : up when I'm trying to do the following: : A graph contains Node and Edge objects. These are distinct object : types. I would like the Node objects to contain fields of type Edge, : and the Edge object to contain fields of type Node so that the graph : is easily traversable. In order to do this the Node interface must : import the Edge interface so that an edge may be added to the node. As : well the Edge interface must import Node so that a node may be added : to an edge. Ooops! We're hosed. : One way to solve this is to have a Graph interface which exports both : Edge and Node. Everyone is in the same interface, so no problem. : Is another way to do this to have multiple interfaces to Node, where one : of those interfaces is imported by Edge and doesn't make reference to : Edge? Then a single module will reveal the "One True Node" and export : all interfaces. Why can't you just define a module Graph, which contains types Node and Edge? If you can't define more than one object type in a module, doesn't that get rid of a major advantage that Modula-3 has over Eiffel and C++, the module scope of visibility rather than class scope? I thought that the whole advantage of a seperate module scope in oop was to enable cooperative classes like your Node-Edge to work without needing friend classes or circular interfaces. Since I program mostly in Oberon-2 I am not aware of the special limitations of Modula-3, but this kind of restriction would greatly increase the amount of code I would have to write and would complicate the public interfaces (i.e. those visible to others than the partner). An example of cooperative object types is the Oberon file i/o. There is a module Files, which exports types File and Rider. File represents the array of bytes on the disk, and Rider represents an access point to a File. There can be many Riders on a File, at different positions, but a Rider only points to one File. The i/o is buffered, using a third type Buffer that is not exported. A File can have multiple buffers, but only one Buffer to a (disk) block. Each Rider is associated with a Buffer, but if more than one Rider is in the same block, they use the same Buffer. In this example, Buffer has to be visible to Rider and File, but should not be public. If you define one object type to a module, Buffer will be public (will have at least one public interface). This is the problem with traditional oop languages like smalltalk and C++. It should not be a problem with languages like Modula-3 and Oberon-2. Just my $.02. Brian Hawley bhawley@orion.it.luc.edu and math.luc.edu ======================================================================= 51 === Date: 9 Jan 95 08:38:33 From: dagenais@notung.vlsi.polymtl.ca (Michel Dagenais) Subject: Re: SRC M3 v. 3.4 out A few of us have been testing the system to check for minor problems before it goes "public". I am happy to report that everything has been very smooth on SPARCs. (As Bill says, however, please wait until he announces it, as some of the minor changes haven't made it back to the release.) The whole source tree is available under ftp.vlsi.polymtl.ca pub/lude/modula3-3.4 in src/orig with locally modified files in src/poly and binaries under run/poly/sun4.1_sparc. I have problems with Mentor and Obliq which i did not have time to investigate yet. This is why i would recommend that you let the dust settle for a week or so. I'd like to take this chance to commend Bill Kalsow and the rest of the people at SRC who helped with the SRC Modula-3 distribution for doing such a great job! Indeed! Very much so!! -- Prof. Michel Dagenais dagenais@vlsi.polymtl.ca Dept of Electrical and Computer Eng. Ecole Polytechnique de Montreal tel: (514) 340-4029 ======================================================================= 52 === Date: 10 Jan 1995 16:59:40 GMT From: kalsow@src.dec.com (Bill Kalsow) Subject: Re: Circular imports In article , jackg@downhaul.crc.rico h.com (Jack Greenbaum) writes: > > M3 does not allow interfaces to cicularly import each other. This comes > up when I'm trying to do the following: > > A graph contains Node and Edge objects. These are distinct object > types. I would like the Node objects to contain fields of type Edge, > and the Edge object to contain fields of type Node so that the graph > is easily traversable. In order to do this the Node interface must > import the Edge interface so that an edge may be added to the node. As > well the Edge interface must import Node so that a node may be added > to an edge. Ooops! We're hosed. My usual solution is to define the interrelated types as opaques in a tiny interface. Then, introduce the names I prefer in higher-level interfaces and use them whenever possible. For example: INTERFACE XX; TYPE Node <: REFANY; (* == Node.T *) TYPE Edge <: REFANY; (* == Edge.T *) END XX. INTERFACE Node; IMPORT XX; TYPE T = XX.Node; PROCEDURE New (READONLY edges: ARRAY OF XX.Edge): T; ... INTERFACE Edge; IMPORT XX; TYPE T = XX.Edge; PROCEDURE New (a, b: XX.Node): T; ... As in the example, I usually break the circularity symmetrically. It's possible to define only one of XX.Node or XX.Edge and only define the ".T" version of the other. In my experience, this arrangement usually decays over time and becomes hard to understand. If you need, you can provide more information in the Node and Edge interfaces by including full or partial revelations. For example: INTERFACE Edge; IMPORT XX; TYPE T = XX.Edge; REVEAL T <: OBJECT a, b: XX.Node; END; PROCEDURE New (a, b: XX.Node): T; ... Finally, all of the implementation code and any higher-level interfaces use the names Node.T and Edge.T. For example: INTERFACE Graph; IMPORT Node, Edge; TYPE T <: REFANY; PROCEDURE FromNodes (READONLY n: ARRAY OF Node.T): T; PROCEDURE FromEdges (READONLY e: ARRAY OF Edge.T): T; Anyway, that's what I do. - Bill Kalsow ======================================================================= 53 === Date: 9 Jan 95 08:43:05 From: dagenais@notung.vlsi.polymtl.ca (Michel Dagenais) Subject: Postscript for the M3 language definition In http://www.vlsi.polymtl.ca/m3/Doc you will find the Postscript for a number of Modula-3 related documents including the language definition. It was derived automatically from the HTML version available on the Web; any formatting error you may find there is probably mine since the tools used for this conversion still have limitations. -- Prof. Michel Dagenais dagenais@vlsi.polymtl.ca Dept of Electrical and Computer Eng. Ecole Polytechnique de Montreal tel: (514) 340-4029 ======================================================================= 54 === Date: Tue, 10 Jan 95 18:02:33 GMT From: lady0065@sable.ox.ac.uk (David J Hopwood) Subject: Re: Cows, Hogs & Farms In article <1995Jan5.183534.10065@schbbs.mot.com>, David L. Shang wrote: >In article <3e07c4$sup@muss.cis.McMaster.CA> u9442202@muss.cis.McMaster.CA >(E.H. Schnetter) writes: >> OK, here is an example in Sather. [example using type-cases snipped] >What you presented here is "Invaraince + Runtime Type Check", not a >covariance. > >At a hogsty, if there is a plate saying "please feed me any plant", what will >happen? The sty will be full of rotten food that the hog does not eat. > >The plate should say "please feed me corn only". That is, the eat interface >should tell its feeder the right food (if we suppose that a hog eat corn >only). > >I'm not syaing that an interface should always tells the exact type. It >depends on the desired semantics for that function. > >"eat" definitely needs an exact interface: > > hog eats corns only -- covariance > >"try" may have a vaguer interface: > > hog try all plant -- invaraince + runtime type check > >As I always said, a good language should provide all the possiblities. Exactly. In the general case, we have an Animal which is guaranteed to eat all food of type A, and may in addition eat food of type B: type Animal {A, B} eat (A) -- accept _at least all_ food of type A try (partial B) -- accept _at least some_ food of type B A hog is guaranteed to eat all corn, and may in addition eat other plants: type Hog eat (Corn) try (partial Plant) Note that Hog is intended to be equivalent to Animal {Corn, Plant}; they represent the same type. The argument of try is declared to be partial, to indicate that it is not necessarily defined for all Plants. Suppose that a hog, fred, eats both corn and maize, but nothing else (and in particular, not venus-flytraps): venus-flytrap: Plant := ... maize: Plant := ... corn: Corn := ... fred: Hog := ... fred.try (venus-flytrap) -- legal, but fails at run-time fred.try (maize) -- legal, and succeeds at run-time fred.try (corn) -- legal, and succeeds at run-time fred.eat (venus-flytrap) -- illegal (detected statically) fred.eat (maize) -- also illegal, since the semantics of eat requires -- that success is guaranteed fred.eat (corn) -- legal, no run-time check required try and eat have different semantics, in that they make different guarantees about whether the call will succeed. Most languages do not allow try and eat to be declared differently (ie. they have no equivalent to 'partial'). One reason for declaring them differently is as a warning to the programmer. To use try properly, the program must be designed so that it does not matter if it succeeds or not (as in David Shang's excellent example of type-safely matching a heterogeneous list of animals with a list of foods). Another reason is that they behave differently with respect to subtyping. Ordinary parameters are contravariant, but partial parameters are not necessarily so. For example, is Animal {Corn, Maize} a subtype of Animal {Corn, Plant}? It must be, since fred is evidently a member of type Animal {Corn, Maize}, and in the above example we declared fred to be of type Hog (ie. Animal {Corn, Plant}). Ie. the argument of try (in this case) is covariant. Consideration of similar examples shows that a programming language cannot impose _either_ co- or contravariance on the types of partial arguments, without rejecting some perfectly type-safe programs. It must allow these types to be changed arbitrarily. Since the programmer is required to handle the case where the method fails, this does not contravene type safety. [much snipped] >Run time type check can also be encapsulated by a hog's method, say "try": > > function hog::try(food: plant): plant > enter > when typeof(food) is corn do ^^^^^^^^^^^^^^^^^^^^ > { eat (food); > return nil; > } > return food; > end; try should allow the run-time type of its argument to be a subtype of corn. It should not restrict it to being exactly corn. Ie. the language should allow something like: when typeof(food) is-subtype-of corn do ... >Back to the original example when both the food type and the animal type are >unknown: [example of type-safely matching a heterogeneous list of animals with their corresponding foods snipped] >From the above example, we can see that a runtime type mismatch is not >necessarily an exception, nor a type error. The system is designed this way. >It is the desired semantics. > >What is a type error? A type error happens only when the type voilates the >requirement of the interface specification. > > hog eats grass > >is a type error, but > > hog tries grass > >is not a type error. > >Runtime type check is not an very important issue. The key point is >whether the language can say the way you want! > >David Shang Agreed. David Hopwood david.hopwood@lmh.oxford.ac.uk ======================================================================= 55 === Date: 10 Jan 95 21:16:07 EDT From: hathawa2@marshall.edu (Mark S. Hathaway) Subject: Re: Cows, Hogs & Farms > In article <1995Jan10.180233.23224@inca.comlab.ox.ac.uk>, > lady0065@sable.ox.ac.uk (David J Hopwood) writes: >> In article <1995Jan5.183534.10065@schbbs.mot.com>, >> David L. Shang wrote: >>> In article <3e07c4$sup@muss.cis.McMaster.CA> >>> u9442202@muss.cis.McMaster.CA (E.H. Schnetter) writes: >>> OK, here is an example in Sather. > [example using type-cases snipped] >>What you presented here is "Invaraince + Runtime Type Check", not a >>covariance. >> >>At a hogsty, if there is a plate saying "please feed me any plant", what >>will happen? The sty will be full of rotten food that the hog does not eat. >> >>The plate should say "please feed me corn only". That is, the eat interface >>should tell its feeder the right food (if we suppose that a hog eat corn >>only). Why should a plate say "please feed me corn only"? Since when is that relevant? It's the HOG which favors CORN. The hog is a herbivore which eats and favors corn. A farmer (presumably) feeds (read as offers) something (usually corn) to the hog. You can say the hog has a method eat(), but that doesn't explain the states which are needed for it to decide when and what and how much to eat(). And, when the hog sees something in its trough and it appears to be corn and the hog is hungry (nearly always) the hog still might not eat if it senses there's something contaminating the food. Even the American congressman/woman won't feed at the gov't. trough if it's not something his constituents want. :-) I favor the declaration of HOG separate from its foods. There might be a hog in some part of the world which doesn't eat corn. Maybe the favorite food of HOG will depend more upon what's available than we're imagining. If a hog will eat something else then the class with CORN will be wrong. A more generic HOG with a derived HOG_liking_CORN or a HOG with an attribute ( attr favorite_food is plant(corn) ) would be more enduring and correct. > try and eat have different semantics, in that they make different guarantees > about whether the call will succeed. Most languages do not allow try and eat > to be declared differently (ie. they have no equivalent to 'partial'). Can't "try" be easily achieved with... procedure freds_life is begin if food_available AND hungry AND ( food = CORN ) then fred.eat(food); else #OUT.write "Yuck, get this " + string(food) + " outta here!" + nl; end; end freds_life; I can't see HOG having a method TRY. That makes no sense. Mark S. Hathaway ======================================================================= 56 === Date: Thu, 12 Jan 95 03:15:15 GMT From: lady0065@sable.ox.ac.uk (David J Hopwood) Subject: Re: Cows, Hogs & Farms In article <1995Jan9.005627@hobbit>, Mark S. Hathaway wrote: >> In article <1995Jan6.164948.4782@schbbs.mot.com>, >> shang@corp.mot.com (David L. Shang) writes: ... >>> You can do most of Cluster's static solution in Sather, and I guess Eiffel. >>> >>> ... >>> class MONOCULTUREFARM{FOODT, ANIMALT < $HERBIVORE{FOODT} } is >>> attr livestock : LIST{ANIMALT}; -- type is known at compile time >>> attr foodstock : LIST{FOODT}; -- type is known >>> ... > >Should there be a $FOOD abstract type used here ( "FOODT < $FOOD" )? Yes, that would be better. >Would there have to be an "include HERBIVORE" and maybe "include FOOD" >for this to work? No. That would only be needed if we wanted to copy the implementation of the classes HERBIVORE and FOOD, which is not the case here. >> This form is slightly different in semantics from the Cluster's form: >> >> class MONOCULTUREFARM [ANIMALT <: HERBIVORE] >> attr livestock : list[ANIMALT]; >> attr foodstock : list[ANIMALT.FOODT]; >> ----- (1) > >Does Cluster separate the subtyping and inheritance as Sather does? No. In Cluster subclassing implies subtyping. IMO this is not a good idea, because it is useful to be able to use part of the implementation of a class without subtyping from it. >Is the use of "ANIMALT <: HERBIVORE" a convenience or requirement? It is a requirement if you want to make ANIMALT a polymorphic type variable that can be referred to within MONOCULTUREFARM. (ANIMALT on its own would mean ANIMALT <: ANY, which is wrong in this case). >So, ANIMALT.FOODT implies that a particular food is associated with a >particular animal? Yes (more accurately, a particular type of food with a particular type of animal). >How can it be a HERBIVORE and yet eat only one kind >of plant? If ANIMALT is bound to exactly HERBIVORE, then the animals will eat any PLANT (ie. HERBIVORE.FOODT = PLANT) If it bound to a subtype of HERBIVORE, then they will eat a subtype of PLANT (eg. HOG.FOODT = CORN) >> or BETA's form: >> >> MONOCULTUREFARM >> (# ANIMALT :< HERBIVORE >> attr livestock : @list (# eleT::ANIMALT #); >> attr foodstock : @list (# eleT::ANIMALT.FOODT #); >> #) > >It's not especially readable, is it? Nope :-) >Is it really ":<" rather than Cluster's "<:"? Very funny contrarianism! Yep :-) >Since "ANIMALT :< HERBIVORE" is inside the "(#" & "#)" enclosure I wouldn't >guess you could create a MONOCULTUREFARM(COW). Yes you can (but I can't remember the syntax). >Since there's no "class" in front of "MONOCULTUREFARM" I'd guess that >everything in BETA is a class or pattern or somethin', huh? Yes (a pattern). >So, by having only one "form" it can be understood what this is. Is there >any special notation to differentiate a main program from these others? I don't know (I don't program much in BETA). The idea of a main program is only really needed at the end of development, and only then because you're running it from a non-OO environment. >Do any of these MONOCULTUREFARMs (Sather, Cluster or BETA) inherit >from FARM or are they the lowest base of farm that will exist in this >class hierarchy? It doesn't really matter. No other FARM types are being modelled in this example, but they could be. >[snipped a bunch] > >> It might be difficult to argue which way is better for a farm, but as I >> said, the language should at least give the way that the speaker wants. > >Yes, the language should provide a way to express something. That's why >I cringe when I see syntax like BETA's. :-) To be fair, orthogonality is very nice. But I think it could have been done in a little more user-friendly way, in the case of BETA. All those symbols give me a headache. >How about... > > class MonocultureFarm ( food is plant, animal is herbivore ) is > procedure feed (); > end MonocultureFarm; > > class MonocultureFarm body is > import list; > object livestock is list(animal); > foodstock is list(food); > procedure feed ( get livestock is in out list(animal); > get foodstock is in out list(food) ) is > begin > ... > end feed; > end MonocultureFarm; > > program temp is > import MonocultureFarm; > object myfarm is MonocultureFarm(corn,hog); > begin > myfarm.feed(); > end temp. Looks good to me. This sort of code would be valid in Cluster, Sather and BETA. The difference in Cluster et al, is that you can also say program temp is import MonocultureFarm; object myfarm is MonocultureFarm(myanimal, myfood); object currentanimal is myanimal; object currentfood is myfood; begin -- can refer to 'myanimal' and 'myfood' as type variables anywhere -- inside here. end temp. >Since it's not like a procedure within a module the parameters of >MonocultureFarm which are of type/class plant and herbivore aren't >"import"ed first. That's a little awkward, but these other languages >(BETA, Cluster, Sather) don't seem to need the "import". Is it no >longer regarded as necessary? Personally, I like explicitly importing things. It means you don't have cluttered global namespaces. But it's not strictly necessary. >> Back to the major difference: >> >> Cluster's generic class are real classes but Sather's is not. >> Therefore, by Cluster, HERBIVORE[GRASS] is a subclass/subtype >> of HERBIVORE. > >I hesitate to ask what kind of GRASS is an HERBIVORE. So you should. Personally, I find the way Cluster is being explained here rather obscure; I would prefer to consider HERBIVORE to refer to a module rather than a type (because it isn't qualified with a type parameter). The thing which is causing the confusion is that Cluster allows type parameters to be referred to either by name, or by position (a bit like function parameters in Ada83, if that helps). As far as I can make out, it also allows the following syntactic sugar: instead of declaring object foo is X [TYPETAG = T] -- where T is a type variable object bar is T you can say object foo is X -- the T is now implicit object bar is X.TYPETAG Using that sugar, you can claim that HERBIVORE [GRASS] (which is the same thing as HERBIVORE [FOODT = GRASS]), is a subtype of HERBIVORE. That is equivalent to introducing T as a local type variable, and saying that HERBIVORE [GRASS] is a subtype of HERBIVORE [T] for some T. I hope I haven't confused people utterly with that. >> By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of HERBIVORE. >> That's whay Sather cannot have the expression: >> >> ANIMALT < $HERBIVORE >> >> because HERBIVORE is not a class. > >I asked (above) if Sather would also have to use an "include HERBIVORE" to >comlete the equation. This comparison of Cluster's inheritance scheme to >Sather's asks the same question. The basic difference between Sather's genericity and Cluster's is that in Cluster (and BETA, Cecil, Trellis/Owl, and lots of functional languages), you can use type variables outside the particular class that defines them. The difference between Sather's inheritance and Cluster's is a separate issue; in Sather, subtyping is separated from inheritance (which is why you need include as a new construct), while in Cluster it is not. >If you're inheriting an HERBIVORE then how can it be an HERBIVORE that >only eats GRASS? It seems to me that the tying together of the specific >food(s) to the animal has to be done at a higher level of abstraction -- >probably in the algorithm which represents the farmer's actions. Exactly. To do this, you need to use type parameters within the farmer algorithm, not just within MONOCULTUREFARM. The resulting algorithm doesn't need to be instantiated with specific types in order to work correctly (as in Sather, C++, Ada-style genericity); there is only one algorithm, which can be used with its parameters bound either to type variables, or to specific types. Cluster et al allow you to do this; Sather et al don't. ... >Mark S. Hathaway David Hopwood david.hopwood@lmh.oxford.ac.uk ======================================================================= 57 === Date: Thu, 12 Jan 1995 14:20:08 GMT From: trumpet-user@a.site.name (Default Trumpet User) Subject: Re: OOPSLA'95 Electronic Hotline In article bnfb@scs.carleton.ca (Bjorn Freeman-B enson) writes: >From: bnfb@scs.carleton.ca (Bjorn Freeman-Benson) >Subject: OOPSLA'95 Electronic Hotline >Date: Fri, 30 Dec 1994 02:19:56 GMT > OOPSLA'95 ELECTRONIC INFORMATION HOTLINE > Tenth Annual ACM Conference on >Object-Oriented Programming Systems, Languages and Applications > >CONFERENCE CHAIR REBECCA WIRFS-BROCK 15-19 October 1995 >PROGRAM CHAIR MARY LOOMIS Austin, TX, USA >________________ WHAT INFORMATION IS AVAILABLE ____________________ >The Hotline currently contains the on-line version of the Call for >Participation including the submission dates, guidelines, articles about >how to write good papers, important dates, etc. As October approaches, >more and more information will be available including the Advanced Program, >registration forms, maps of Austin, etc. >__________ HOW TO RECEIVE MORE INFORMATION ELECTRONICALLY _________ >There are three mechanisms for receiving further information electronically: >WWW, anonymous ftp, and e-mail list server. > W W W >http://info.acm.org/sig_forums/sigplan/oopsla/oopsla95.html > A N O N Y M O U S F T P >Host name: info.acm.org >Host id: 137.117.5.4 >FTP directory: sig_forums/sigplan/oopsla/ >The file READ.ME contains a list of the files available. > E - M A I L L I S T S E R V E R > [Unfortunately, the ACM Email List Server is currently > not functioning... I will repost this announcement when the > list server recovers.] >____________________ CONTACT WITH A HUMAN ________________________ >This Hotline is automatic - your e-mail has been processed by auto-answer >program. No human has read your message. If you are having trouble with >the Hotline, or need to communicate with an OOPSLA'95 representative about >some issue that the Hotline does not provide an answer for, you can contact >bjorn@oti.on.ca (for Hotline Problems), oopsla95@applelink.apple.com >(for OOPSLA'95 Administration). > >>> PLEASE <<< >Please do not contact the administration or registration people if your >problem can be answered by files on the Hotline. OOPSLA is a big >conference and it is staffed by unpaid volunteers - we give our time to >make it happen. This Hotline has been set up to provide answers to >Frequently Asked Questions and to reduce the administrative load on us... >Thank you. (Also, the Hotline is automatic and thus available 24 hours a >day, whereas the administration is a 9am-5pm West Coast time operation.) ======================================================================= 58 === Date: 12 Jan 1995 18:20:08 GMT From: bm@stieglitz.cs.columbia.edu (Blair MacIntyre) Subject: HP-UX and shared libraries. (CC:d to comp.cgcc.help since this is a question about the gcc backend that m-3 uses, based on gcc 2.5.7) I'm attempting to get Modula-3 (v3.4) compiled on HPUX using shared libraries. It appears to me that the gcc backend is not generating position independent code. I cannot tell gcc to do so using the -fpic option (says it does not work on the pa architecture), so I don't know what do try next. Has anyone gotten gcc to generate position indenpendent code that can be loaded into a shared library on HPUX 9.x (using ld -b)? -- Blair MacIntyre -- bm@cs.columbia.edu -- Graduate Student (Graphics and UI Lab) smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St., Columbia University, New York, NY 10027 ======================================================================= 59 === Date: Thu, 12 Jan 95 01:08:22 GMT From: lady0065@sable.ox.ac.uk (David J Hopwood) Subject: Re: Cows, Hogs & Farms In article <1995Jan9.021043@hobbit>, Mark S. Hathaway wrote: ... > David Shang wrote: ... >> In reality, we always have exceptions. We can use covariance to rule out a >> general principle and use run-time type check for a few exceptions. As to >> the animal example, it is clearly worthwhile to divide animals into >> herbivires, carnivores and (?)(animals eating both food) according to the >> type of their food. We can use covaraince. But it might be very hard to >> rule out a general principle for the futher classification for a certain >> number of animals. ... >> We are not developing a commercial software for zoologists, are we? These >> are only pedagogical examples. Be wise to make things as simple as possible >> -- just for the key points you want to say. > >I have created a few examples in the past which thoroughly confused people >because they weren't realistic enough. I'm trying to avoid the sins of >my past. Same here. ... >I'd certainly be interested to read further discussion on the differences >between these classes and those of Sather & Eiffel. There seem to be some >rather major differences. It might help to read about the typing systems of Cecil, Trellis/Owl, or ML (and various other functional languages), which use a similar approach to Cluster. A paper on the Cecil typing system is at http://www.cs.washington.edu/research/projects/cecil/www/cecil-spec.html At least, I think that's the right paper - I can't read postscript on this terminal to check. Don't get too confused by the stuff on multi-methods - it's fascinating, but not really relevant. Genericity is described near the end of the paper. A good account of dynamic genericity (also called Milner polymorphism) in functional languages is given in An Introduction to Functional Programming Richard Bird and Phillip Wadler Prentice Hall series in Computing Science (sorry, don't have the ISBN on me). Hope this helps, David Hopwood david.hopwood@lmh.oxford.ac.uk ======================================================================= 60 === Date: Fri, 13 Jan 1995 00:48:57 +0100 From: msm13@cus.cam.ac.uk (M.S. Mamo) Subject: help with threads I am trying out threads in Modula-3. The firstthread prints out the 5 times table and the second thread prints out the 6 times table. However the program prints all of the 6 times table out and then all of the 5 times table out. I hoped the two would be interleaved. What am I doing wrong? Could it just be the way threads have been implemented on our system? ... BEGIN firstthread := Thread.Fork(Proc1); secondthread := Thread.Fork(Proc2); EVAL Thread.Join(firstthread); END threadtest. ======================================================================= 61 === Date: Fri, 13 Jan 1995 15:44:23 GMT From: olaf@logware.de (Olaf Wagner) Subject: rel 3.3 and ILU? Has anybody succeeded in using ILU with rel 3.3 of SRC Modula-3? Are patches available? If so, any hints where to look for them? Olaf -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \ Olaf Wagner at Logware GmbH Schwedenstrasse 9 \ \ olaf@logware.de (work) 13359 Berlin 65 \ \ wagner@luthien.in-berlin.de (private) Germany / Deutschland \ ======================================================================= 62 === Date: 13 Jan 1995 06:21:01 GMT From: hansels@hk.super.net (Mr Hansel HC Sin) Subject: Re: Cows, Hogs & Farms Alf-Ivar Holm (alfh@gyda.ifi.uio.no) wrote: : In article <1995Jan3.223031@hobbit> hathawa2@marshall.edu (Mark S. Hathaway) writes: : > I've not seen BETA and have never heard of Cluster. Could you provide : > a pointer-->ftp_site or other info. about them? :-) : The BETA home page is found at: : http://www.daimi.aau.dk/~beta/info : I have no info on Cluster. : Affi ======================================================================= 63 === Date: Sat, 14 Jan 1995 03:26:41 GMT From: krystof@cs.washington.edu (Krzysztof Zmudzinski) Subject: Compiling error I am trying to build m3 release 3.3 on an ALPHA running OSF/1. I have 150MB of free disk space. s - creating symbol hash table. Wait... ar: Error: libm3.a cannot grow sym table: oldmax=864, size=1198614080 *** error code 1 "/afs/cs.washington.edu/project/spin/krystof/m3/boot-ALPHA_OSF/m3build/template s/COMMON.BOOT", line 47: command execute failed *** call stack *** "/afs/cs.washington.edu/project/spin/krystof/m3/boot-ALPHA_OSF/m3build/template s/COMMON.BOOT", line 47: call to built-in exec "./make.boot", line 457: call to procedure boot_lib Krystof ======================================================================= 64 === Date: Fri, 13 Jan 1995 20:51:13 GMT From: lrr@Princeton.EDU (Lawrence R. Rogers) Subject: Building version 3.4 under Solaris 2.4 with gcc I've successfully built gcc under Solaris 2.4 without problem. However when I try to build m3cc under version 3.4, I get the following: gcc -DIN_GCC -DSVR4 -g -o genattrtab \ genattrtab.o rtl.o print-rtl.o rtlanal.o ` case "obstack.o" in ?*) echo obstac k.o ;; esac ` ` case "gcc"@"alloca.o" in "cc"@?*) echo alloca.o ;; esac ` ` cas e "" in ?*) echo ;; esac ` if cmp -s Makefile md; \ then \ echo Using ; \ cp tmp-attrtab.c; \ else \ ./genattrtab md > tmp-attrtab.c; \ fi *** Error code 139 make: Fatal error: Command failed for target `stamp-attrtab' Anybody get this one to work? Thanks for the tip. ===== ======= ======= Larry Rogers = = = = Manager, UNIX Systems = = = Princeton University = = = 87 Prospect Avenue, Room 201 = = = Princeton, NJ 08544 = = = lrr@Princeton.EDU, princeton!lrr = = = Phone: 609-258-6483/6000 = = = = FAX: 609-258-1069/3943 ===== ======= = NeXT and Sun Mail Happily Accepted ======================================================================= 65 === Date: 13 Jan 95 21:19:38 EDT From: hathawa2@marshall.edu (Mark S. Hathaway) Subject: Re: Cows, Hogs & Farms > In article <1995Jan9.203528.29056@schbbs.mot.com>, > shang@corp.mot.com (David L. Shang) writes: >> In article <1995Jan9.005627@hobbit> writes: >>> In article <1995Jan6.164948.4782@schbbs.mot.com>, >>> shang@corp.mot.com (David L. Shang) writes: >>> ... >> So, ANIMALT.FOODT implies that a particular food is associated with a >> particular animal? How can it be a HERBIVORE and yet eat only one kind >> of plant? > It cannot be in reality. I am reluctant to complicate this example. But to > describe a HERBIVORE that eat more than one kinds of food is also possible > by multiple inheritance: > > class COW is HERBIVORE [ FOODT = GRASS ], > HERBIVORE [ FOODT = HAY ], > ... > > But there will be a problem when you try to substitude ANIMALT with COW: > > class MONOCULTUREFARM [ANIMALT <: HERBIVORE] > attr livestock : list[ANIMALT]; > attr foodstock : list[ANIMALT.FOODT]; > > cow_farm: MONOCULTUREFARM [COW]; > > As COW has multiple bases: HERBIVORE[GRASS], HERBIVORE[HAY], ..., which > base is used? You have to specify: > > grass_farm: MONOCULTUREFARM [COW as HERBIVORE[GRASS]]; > > or > hay_farm: MONOCULTUREFARM [COW as HERBIVORE[HAY]]; > > In fact, the MONOCULTUREFARM designed here is no longer suitable for an > animal that eats more than one plant, becase it only keeps one kind of > food. However, if we could figure out a subclass of PLANT for COW, say, > COW_FOOD, there is not problem to have HERBIVORE[COW_FOOD] and the > MONOCULTUREFARM as define above. > > Unfortuantely, in most cases, it is almost impossible to classify herbivores > according to the food type they eat. This is probably a bad example to > demonstrate the covariance. I whould like to use the herbivore/carnivore > classification example. The reason I continue to ask this question is that the first example I gave didn't bind the animal to the food. Someone added that later and confused the entire issue. See what a mess it makes? If you have... PLANT HERBIVORE _____| |_____ _____| |_____ | | | | CORN GRASS HOG COW I'm ignoring LIST | | | | for the moment. V V V V ----------- ---------- | HOG | | COW | | FARM | | FARM | |___________| |__________| it would seem much easier to bring the CORN & GRASS to mix separately rather than saying COW inherits HERBIVORE[GRASS] Also, notice that if you want a heterogeneous FARM you drop back to using HERBIVORE, but a HERBIVORE isn't necessarily a COW or HOG. For a heterogeneous farm you need LIST[COW] & LIST[HOG]. To create a class which could represent either COW or HOG would be interesting. I haven't seen any instances of that. What I have in mind is.... -- HERBIVORE is the base class COW is HERBIVORE; HOG is HERBIVORE; FARM_ANIMAL is COW or HOG; FARM is LIST[FARM_ANIMAL]; >> procedure feed ( get livestock is in out list(animal); >> get foodstock is in out list(food) ) is > Why should you provide additional input/output parameters for feed in > the class body? When I was creating this pseudo-code I noticed that there was the possibility for a class to have more than one piece of data which represented a part of the object and some of the data might be only supplementary or temporary. And, there is the question of whether all the data in a class should be considered globally shared with all the methods used by the class. I decided it would be interesting to add the "get" to bind a particular data to a method. It hasn't been roundly praised or condemned. Mostly people have asked why it's there. It's just an idea, not a lifestyle. :-) > Why should the feed interfaces be different? Only to specify those extra parameters with the "get"; which should remain unseen by the user who sees the interface. > Agian, I don't consider this herbivore example a good example to demonstrate > covariance. Lets just take the assumption that COW eat GRASS only and HOG > eat CORN only, and make things simple. If you don't like the assumption, we > may consider the animal/herbivore/carnivore example. Maybe someone could begin by defining "covariance" in words and/or with an example in code. Mark S. Hathaway ======================================================================= 66 === Date: 14 Jan 1995 23:22:07 GMT From: mbk@inls1.ucsd.edu (Matt Kennel) Subject: Re: Cows, Hogs & Farms Mark S. Hathaway (hathawa2@marshall.edu) wrote: : Also, notice that if you want a heterogeneous FARM you drop back to : using HERBIVORE, but a HERBIVORE isn't necessarily a COW or HOG. For : a heterogeneous farm you need LIST[COW] & LIST[HOG]. To create a : class which could represent either COW or HOG would be interesting. : I haven't seen any instances of that. What I have in mind is.... : -- HERBIVORE is the base class : COW is HERBIVORE; : HOG is HERBIVORE; : FARM_ANIMAL is COW or HOG; : FARM is LIST[FARM_ANIMAL]; -- Sather type $HERBIVORE is try(food:$PLANT); end; type $HERBIVORE{MYFOOD < $PLANT} is try(food:$PLANT); eat(food:MYFOOD); end; class COW < $HERBIVORE{GRASS} is -- blah blah blah implementation end; class HOG < $HERBIVORE{CORN} is -- implementation end; type $IOWA_FARM_ANIMAL > COW,HOG is try(food:$PLANT); end; class IOWAFARM is -- has hogs and cows. attr animals: LIST{$FARM_ANIMAL} attr food : LIST{$PLANT}; feed is loop animals.elt!.try(food.elt!); end; end; feed_corn is -- Cluster does this one a little cleaner loop f ::= food.elt!; a ::= animals.elt!; typecase f when CORN typecase a when $HERBIVORE{CORN} then a.feed(f); end; end; end; end; end; In general Cluster lets you get at the foodtype for animals for run-time selection OUTSIDE their class easily, in Sather it's usually easier to put the typecase inside the 'try'. : Mark S. Hathaway -- -Matt Kennel mbk@inls1.ucsd.edu -Institute for Nonlinear Science, University of California, San Diego -*** AD: Archive for nonlinear dynamics papers & programs: FTP to -*** lyapunov.ucsd.edu, username "anonymous". ======================================================================= 67 === Date: 16 Jan 1995 14:37:57 GMT From: c4craig@csn.net (Craig Anderson) Subject: trestle for NT? The m3 3.4 announcement mentions a port to Windows/NT without Trestle. Is a Trestle port to NT planned? Craig Anderson craig@c4.com ======================================================================= 68 === Date: 15 Jan 1995 17:05:57 GMT From: danan@cs.concordia.ca (DANAN itai) Subject: Modula-3 for OS/2 Does anyone know of a public domain Modula-3 compiler for OS/2? If so, where can I get it? Thanks in advance, Itai danan@concordia.ca ======================================================================= 69 === Date: 16 Jan 1995 17:48:17 GMT From: bm@shadow.cs.columbia.edu (Blair MacIntyre) Subject: which "pass" is the linker? I'm trying to properly configure modula 3 for the Iris, and the linker spews a lot of messages of the form: libm3ui.a(PackSplit.mo): does not have gp tables for all it's sectons In the template, there is a comment of the form: % "-zJ10", % The option "-zJx1" specifies that pass "x" is "noisy", "-zJx0" % specifices that it's not. The default is to assume that passes % are not noisy. The driver collects the standard output of noisy % passes in a file and then deletes the file, unless "-keep" or % "-verbose" is specified. So, which pass is the linker? I'd like to tell M3 that it's noisy. -- Blair MacIntyre -- bm@cs.columbia.edu -- Graduate Student (Graphics and UI Lab) smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St., Columbia University, New York, NY 10027 ======================================================================= 70 === Date: 17 Jan 95 08:32:44 From: dagenais@notung.vlsi.polymtl.ca (Michel Dagenais) Subject: Re: Modula-3 for OS/2 >From the FAQ. The last persons known to be working on such a port were Hendrik Boom hendrick@CAM.ORG and Craig Andrew Kingston ckingsto@undergrad.math.uwaterloo.ca. -- Prof. Michel Dagenais dagenais@vlsi.polymtl.ca Dept of Electrical and Computer Eng. Ecole Polytechnique de Montreal tel: (514) 340-4029 ======================================================================= 71 === Date: 17 Jan 1995 14:59:25 GMT From: mester@ls4.informatik.uni-dortmund.de (Arnulf Mester) Subject: yacc/bison-equivalent for M3? Are any parser generators like yacc/bison (or more comfortable ones like eli/cocktail) or equivalents in use in the M3 community? I am interested in integration and usage experiences, like degree of manual intervention, readability of code, lexical analysis software used (apart from M3.Lex) etc. If requested by e-mail, I would mail back a summary. Thanks in advance, kind regards, P.S. I do know about m3tk and MetaParser in the M3 distribution. Arnulf Mester, Informatik IV, University, D-44221 Dortmund, Germany Dipl.-Inform. * Phone: +49 231 755-4662 (Q), Secr.: -2596, Fax: -4730 * http://ls4-www.informatik.uni-dortmund.de/MA/am/pie.html * Computer Networks & Distributed Systems Group (Prof.Dr.H.Krumm ) -- Arnulf Mester, Informatik IV, AG Rechnernetze u. verteilte Systeme Campus Sued, GB V/509, Tel. 755-4662, Sekretariat -2596, Fax -4730 ======================================================================= 72 === Date: Tue, 17 Jan 95 15:49:50 -0800 From: najork@pa.dec.com (Marc Najork) Subject: Re: trestle for NT? Yes, I am working on such a port. However, I can't give you any planned release date. ======================================================================= 73 === Date: 17 Jan 1995 19:39:29 GMT From: Quentin Stafford-Fraser Subject: Re: Building version 3.4 under Solaris 2.4 with gcc Peter Klein wrote: > - Use another compiler for the backend. gcc 2.6.0 should do. No - I tried 2.6.0 at first, then upgraded my gcc to 2.6.3 hoping that would fix it :-) In the end I just copied the binary of m3cgc1 from Michel's site. The build is steaming along now! Won't help Solaris people, though. Quentin ======================================================================= 74 === Date: 18 Jan 1995 10:13:26 GMT From: anderse@dna.lth.se (Anders Edenbrandt) Subject: Re: Building version 3.4 under Solaris 2.4 with gcc In article <1995Jan13.205113.11219@Princeton.EDU>, Lawrence R. Rogers wrote: > >I've successfully built gcc under Solaris 2.4 without problem. However when I try to build m3cc under version 3.4, I get the following: > > ./genattrtab md > tmp-attrtab.c; \ >make: Fatal error: Command failed for target `stamp-attrtab' > I managed to get past this problem by replacing m3cc/gcc/va-sparc.h with the same file from a more recent version of gcc. Version 2.6.0 will do, in which case the file is called gcc-2.6.0/include/va-sparc.h. Anders Edenbrandt Dept. of Computer Science Lund University Lund, Sweden ======================================================================= 75 === Date: 18 Jan 1995 09:38:11 GMT From: charly@samsoef.ifi.uni-klu.ac.at (Karl-Heinz EDER) Subject: Announcement of M3PC-Klagenfurt ANNOUNCEMENT ------------ We have the pleasure to announce that the newest release of M3PC-Klagenfurt is immediately available on the gatekeeper! What is M3PC-Klagenfurt ? -------------------------- M3PC-Klagenfurt (previously called M3PC) is a port of the Modula-3 compiler release 2.09 to the MSDOS-PC. It translates Modula-3 source into C soure. Therefore you have to install the GNU C-compiler DJGPP as well, which is distributed, too (see 4). You may of course use a newer release of the GNU C-compiler or additional compatible libraries. What's new ? ------------- The new M3PC-Klagenfurt release supports the following (new) features: * library to access DOS files and directories * threads * pickles * a shell (incl. automatic compilation and UNIX like long filenames) Hard- and Software Requirements -------------------------------- (a) Hardware: You will need a PC: * 80486 or 80386 with floatingpoint-coprocessor, * at least 4 but preferable 8 MByte of RAM, * 20 MByte disk space free at least. (b) Software: * DOS 5.00 or higher Necessary Files for Installation --------------------------------- The necessary files are available at "gatekeeper.dec.com" in the directory "pub/DEC/Modula-3/contrib/m3pc": TAR EXE 39,353 11-07-94 10:11a INSTALL TXT 5,325 11-10-94 4:57p M3 TAR 6,799,360 11-07-94 4:26p DJGPP TAR 6,809,600 11-07-94 11:33a M3SRC TAR 6,871,040 11-07-94 11:36a README 5,331 11-10-94 5:40p For further details please see the files README and INSTALL.TXT. What is still to come? ----------------------- A student-friendly environment with integrated editor-browser-compiler is in the test-phase and should be shipped in course of March. The main purpose of the system is to provide an environment for beginners and hide unnecessary details of the operating system and run-time support. It will also be the basis of the examples of the book "Programming in style -- An introduction into programming with Modula-3" which is also intended first of all for first- and second-semester computer science students. Enjoy L.Bvszvrmenyi, C.Weich, K.-H.Eder University of Klagenfurt / AUSTRIA January, the 18th 1995 ======================================================================= 76 === Date: Wed, 18 Jan 1995 11:37:30 GMT From: joel@bris.ac.uk (Joel Crisp) Subject: Re: Building version 3.4 under Solaris 2.4 with gcc Peter Klein (pk@i3.informatik.rwth-aachen.de) wrote: : lrr@Princeton.EDU (Lawrence R. Rogers) wrote: : > : > : > I've successfully built gcc under Solaris 2.4 without problem. However whe n I try to build m3cc under version 3.4, I get the following: : > : > gcc -DIN_GCC -DSVR4 -g -o genattrtab \ : > genattrtab.o rtl.o print-rtl.o rtlanal.o ` case "obstack.o" in ?*) echo ob stack.o ;; esac ` ` case "gcc"@"alloca.o" in "cc"@?*) echo alloca.o ;; esac ` ` case "" in ?*) echo ;; esac ` : > if cmp -s Makefile md; \ : > then \ : > echo Using ; \ : > cp tmp-attrtab.c; \ : > else \ : > ./genattrtab md > tmp-attrtab.c; \ : > fi : > *** Error code 139 : > make: Fatal error: Command failed for target `stamp-attrtab' : > : > : > Anybody get this one to work? Thanks for the tip. : > : I know this is not what you want to hear, but the same problem occurs on : SunOS 4.1.3. Apparantly, gcc versions 2.6.1 to 2.6.3 are not willing : to compile the m3cc backend which is based on gcc 2.5.7. The problem : seems to be an incompatibility in the varargs library. Solutions: : - Update m3cc to a newer gcc version (Bill?) : - Work around the error (Some gcc expert?) ******* GCC expert hears you Go to /usr/local/lib/gcc-lib/sparc-sun-solaris2.3/2.6.0 ( or wherever the equivalent is for your system ) copy "specs" to another name. edit specs and remove the -D__GCC_NEW_VARARGS This fixes the problem. ******* : - Use another compiler for the backend. gcc 2.6.0 should do. : Peter : --- : Peter Klein E-Mail: pk@i3.informatik.rwth-aachen.de : Lehrstuhl fuer Informatik III Tel.: +49/241/80-21311 : Ahornstrasse 55 Fax.: +49/241/8888-218 : RWTH Aachen : 52074 Aachen : Germany Joel Joel.Crisp@bris.ac.uk ======================================================================= 77 === Date: 19 Jan 1995 18:39:29 GMT From: bm@shadow.cs.columbia.edu (Blair MacIntyre) Subject: modula3.el - blink-matching-open problem in Emacs 19 ... I was just wonder if anyone else had this problem and had a workaround. When I close a comment in Emacs, I get the error Signalling: (wrong-type-argument number-or-marker-p nil) blink-matching-open() This doesn't seem to happen in Emacs-18, so I'm wondering if it's something weird with 19, and if anybody has a fix. Turning of blink-matching-paren obviously fixes it, but that's not entirely satisfactory. Thanks. -- Blair MacIntyre (bm@cs.columbia.edu), Graduate Student (Graphics and UI Lab) smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St. Columbia University, New York, NY 10027 ======================================================================= 78 === Date: 20 Jan 1995 21:33:50 GMT From: nayeri@gte.com (Farshad Nayeri) Subject: ANNOUNCEMENT: Report of the Third Modula-3 User Group, OOPSLA'94 ANNOUNCEMENT WHAT : Informal Report of the Third Modula-3 User Group Meeting WHERE : ftp://ftp.gte.com/pub/m3/m3ug/m3ug.html The full report contains a more detailed description as well as copies of some of presenters' slides. This message contains only a capsule summary of the meeting. For the full report, follow the URL above. CAPSULE SUMMARY The Third Modula-3 User Group Meeting at OOPSLA'94 was a success thanks to the participants and presenters! In the short time of two hours, six presenters talked about their experiences with Modula-3 and what they are doing with it. The attendance was solid (25-30 people), given our limited public announcement and the timing of the event. The meeting included several presentations by people who have been using Modula-3 in the past few years. The summary contains references to some of their slides and a brief a overview of the meeting. Although there was no discussion section during the meeting itself, some of the participants joined us at a round-table discussion of Modula-3 and its needs before it can become a popular programming platform. PRESENTATIONS Geoff Wyant: Modula-3 at Sun Microsystems Laboratories [slides] Luca Cardelli: Obliq and Visual Obliq [slides] Eliot Moss: History and status of UMass work on Modula-3 Steve Freeman: Adding video capabilities to Trestle/Modula-3 [slides] Mike Spreitzer: Inter-Language Unification [slides] Farshad Nayeri: Building a prototype distributed object systems DISCUSSIONS After the meeting, some of us got together to discuss the state of Modula-3. Some of the topics discussed were: - Modula-3 as a low-level language and a competitor of C - Modula-3 as a high-level language and a competitor of Eiffel, Smalltalk, and Ada - Exposure in the computer magazines - Commercial Support NEXT MEETING We plan to arrange for the next Modula-3 User Group meeting at COOTS'95, or Conference on Object-Oriented Technologies, Monterey, California, USA during summer of 1995. Please let us know if you have suggestions about format, content, or place of the next meeting. WHAT IS MODULA-3? Modula-3 is a modular programming language; while preserving a safe type system, Modula-3 provides facilities for exception handling, concurrency, object-oriented programming, automatic garbage collection, and systems programming, making it both a practical implementation language for large software projects and an excellent teaching language. An implementation of Modula-3 is available freely from Digital Equipment Corporation's Systems Research Center. For more information, see Modula-3 Home Page: http://www.research.digital.com/SRC/modula-3/html/home.html CONTACT Farshad Nayeri: nayeri@gte.com Geoff Wyant: geoff.wyant@east.sun.com -- Farshad Nayeri nayeri@gte.com ======================================================================= 79 === Date: 20 Jan 1995 16:22:31 GMT From: Subject: US-MA-Job: Distributed Computing @ Sun East - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1/20/95 /\ \ \ \ \ / /\ | | | | \ \ / / \ | | |\ | / \/ \/ /\ \ | | | \| / / / / \/ |_| | | \/ /\ /\ / / / \ \ MICROSYSTEMS / \ \ East Coast Chelmsford, MA \ \ Development \/ Center - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Member of Technical Staff Large-Scale Distributed Computing - SunLabs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Individual contributor to join a team investigating approaches to reliable, large-scale distributed computing. Ideal candidate will have an advanced degree and at least 2 years industry experience, including experience in taking a product to a form that could be shipped to customers. **Must be well versed in distributed computing, object-oriented programming and the design of protocols for reliability.** Knowledge of Modula-3 desirable but not required. Must be able to work with a small group of highly technical and outspoken people in an experimental and rapidly changing computing environment. Recent MS / PhD candidates considered if a top grad from top school with some industry experience: **well versed in distributed computing, object-oriented programming and the design of protocols for reliability.** Eligibility to work in US required. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -> Position based in Chelmsford, Mass.<- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please send resume to: usmail: Sun Microsystems 2 Elizabeth Drive Chelmsford, MA 01824 ATTN: NET/LABS email: staffing@east.sun.com (ASCII) fax: 508 442 0011 ======================================================================= 80 === Date: 20 Jan 1995 22:10:52 GMT From: nayeri@gte.com (Farshad Nayeri) Subject: Re: Request for status on v. 3.4 (SPARC) Stephen Schaub asks about the status of version 3.4 on SPARCs. Our installation of Modula-3 3.4 works just fine. There are a few minor problems when you try to do the build. If you can't wait, I am sure Bill or Michel can forward you the list of patches that you have to make (I didn't see some of the required changes in bugs&patches page of SRC Modula-3 home page, but I wasn't looking hard.) Someone also asked about run-time sizes (was it you, Stephen?). Here are some numbers. Note that I know nothing about performance measurement, and these are very crude at best. executable build directory time(1) output size(bytes) size (blocks) see man time 3.3 hello world 1204224 1130 7.7 real,4.2 user,1.1 sys 3.4 hello world 1105920 1197 9.6 real,5.9 user,1.3 sys 3.3 dom app 802816 2454 240.6 real,132.1 user,26.4 sys 3.4 dom app 614400 2258 139.0 real, 61.2 user,14.5 sys All builds were as warm as I could make my SPARC 20s running SunOS 4.1.3 with 64Mbytes RAM. Modula-3 was running over a pretty slow NFS connection (sigh!) All builds are with the -g flag on (basically the same setups as the default.) "hello world" was compiled with "standalone()" in m3makefile. That's why it's bigger. "dom app" uses formsvbt and tcp packages among other things. It is a pretty large application, and it is using the shared libraries. Please don't take these numbers seriously, but it looks like the compiler is faster and creates smaller executables. Have a nice weekend! -- Farshad [I am typing this in a hurry. Don't be surprised if there is a mistake!] -- Farshad Nayeri nayeri@gte.com ======================================================================= 81 === Date: 20 Jan 1995 19:52:28 GMT From: schaub@ponder.csci.unt.edu (Stephen Schaub) Subject: Request for status on v. 3.4 (SPARC) A couple of weeks ago it was announced that SRC Modula-3 3.4 was out but that some final testing was needed to stabilize the release. I'm interested in the SPARC flavor--is it ready to go? The semester has started and my students will appreciate having the enhanced run-time error info. Thanks, Stephen Schaub schaub@cs.unt.edu TF, University of North Texas ======================================================================= 82 === Date: 20 Jan 1995 23:03:39 GMT From: detlefs@src.dec.com (Dave Detlefs) Subject: Re: modula3.el - blink-matching-open problem in Emacs 19 ... Blair MacIntyre writes: I was just wonder if anyone else had this problem and had a workaround. When I close a comment in Emacs, I get the error Signalling: (wrong-type-argument number-or-marker-p nil) blink-matching-open() This doesn't seem to happen in Emacs-18, so I'm wondering if it's something weird with 19, and if anybody has a fix. Turning of blink-matching-paren obviously fixes it, but that's not entirely satisfactory. I don't have this problem with emacs19. Here is the version of modula3.el we're currently using at SRC; perhaps yours is older... ---------------------------------------------------------------------- ;;; Last modified on Fri Jan 20 15:03:29 PST 1995 by detlefs ;;; modified on Fri May 15 17:13:12 PDT 1992 by heydon ;;; modified on Thu Apr 23 17:45:03 PDT 1992 by muller ;;; modified on Fri Feb 2 13:04:24 1990 by discolo ;;; modified on Tue May 2 21:59:35 1989 by ellis ;;; modified by Trevor Morris ;;; modified by Tom Perrine ;;; modified by Michael Schmidt ;;; modified by Peter Robinson ;;; modified by mjordan ;; LCD Archive Entry: ;; modula3|Eric Muller|muller@src.dec.com| ;; Modula-3 mode.| ;; 92-04-17||~/modes/modula3.el.Z| (require 'cl) (provide 'modula3) ;;; ---------- Syntax Table and Keymap (Added by TEP) ---------- (defvar m3::mode-abbrev-table nil "Abbrev table in use in C++-mode buffers.") (define-abbrev-table 'm3::mode-abbrev-table ()) (defvar m3::mode-syntax-table nil "Syntax table in use in Modula 3 mode buffers.") (if m3::mode-syntax-table () (let ((table (make-syntax-table))) (modify-syntax-entry ?_ "w" table) (modify-syntax-entry ?\\ "\\" table) (modify-syntax-entry ?* ". 23" table) (modify-syntax-entry ?\( "()1" table) (modify-syntax-entry ?\) ")(4" table) (modify-syntax-entry ?\[ "(]" table) (modify-syntax-entry ?\] ")[" table) (modify-syntax-entry ?{ "(}" table) (modify-syntax-entry ?} ")}" table) (modify-syntax-entry ?+ "." table) (modify-syntax-entry ?- "." table) (modify-syntax-entry ?= "." table) (modify-syntax-entry ?% "." table) (modify-syntax-entry ?< "." table) (modify-syntax-entry ?> "." table) (modify-syntax-entry ?\' "\"" table) (setq m3::mode-syntax-table table))) (defvar m3::mode-map nil "Keymap used in Modula 3 mode.") (defvar m3::screen-pool nil "Pool of sceens for m3") (defvar m3::mouse-map nil "mouse map for m3-mode.") (defun m3::setup-mode-map () "Sets up Modula 3 mode map; this must be called after the sequence for the keypad key \"?\\C-@\" has been setup - it uses \"function-key-sequence\" on that key in order to bind the Modula 3 specific functions" (if (not m3::mode-map) (progn (setq m3::mode-map (make-sparse-keymap)) (define-key m3::mode-map "\t" 'm3::abbrev-and-or-indent) (define-key m3::mode-map "\M-\t" 'm3::ident-complete) (define-key m3::mode-map "\C-ca" 'm3::toggle-abbrev) (define-key m3::mode-map "\C-ci" 'm3::show-interface) (define-key m3::mode-map "\C-cm" 'm3::show-implementation) (define-key m3::mode-map "\C-cs" 'm3::show-spec) (define-key m3::mode-map "\C-ct" 'm3::show-trait) (define-key m3::mode-map "\C-cb" 'm3::pp-buffer) (define-key m3::mode-map "\C-cu" 'm3::pp-unit) (define-key m3::mode-map "\C-cr" 'm3::pp-region) (define-key m3::mode-map "\M-\C-a" 'm3::beginning-of-defun) (define-key m3::mode-map "\M-\C-e" 'm3::end-of-defun) (define-key m3::mode-map "\C-c\C-f" 'm3::forward-sexp) (define-key m3::mode-map "\C-c\C-b" 'm3::backward-sexp) )) ) ;;; --------------- Constant and global variable declarations -------------- (defconst m3::identifier-char-re "[a-zA-Z0-9_]") (defconst m3::alpha-char-re "[a-zA-Z_]") (defconst m3::not-identifier-char-re "[^a-zA-Z0-9_]") (defconst m3::identifier-re (concat "\\b" m3::alpha-char-re m3::identifier-char-re "*\\b")) (defconst m3::intlit-re "\\(0\\|[1-9][0-9]*\\)") (defconst m3::poss-qual-ident-re (concat "\\(" "\\(" m3::identifier-re "\\.\\)?" m3::identifier-re "\\.\\)?" m3::identifier-re)) (defconst m3::com-start-re "\\((\\*\\|<\\*\\)") (defconst m3::com-end-re "\\(\\*)\\|\\*>\\)") (defconst m3::com-start-or-end-re (concat "\\\(" m3::com-start-re "\\|" m3::com-end-re "\\)")) (defconst m3::whitespace-char-re "[ \t]") (defconst m3::whitespace-re "[ \t]+") (defconst m3::poss-whitespace-re "[ \t]*") (defconst m3::poss-whitespace-nl-re "[ \t\n]*") (defconst m3::whitespace-line-re "^[ \t]*$") (defconst m3::char-lit-re "'\\([^\\]\\|\\\\..?.?\\)'") (defconst m3::range-end-re (concat "\\(" m3::poss-qual-ident-re "\\|" m3::intlit-re "\\|" m3::char-lit-re "\\)")) (defconst m3::range-re (concat m3::range-end-re m3::poss-whitespace-re "\\.\\." m3::poss-whitespace-re m3::range-end-re)) (defconst m3::case-label-re (concat "\\(" m3::poss-qual-ident-re "\\|" m3::char-lit-re "\\|" m3::intlit-re "\\|" m3::range-re "\\)")) (defconst m3::handler-start-re (concat "\\(|[ \t]*\\)?\\(" (concat "\\b" m3::poss-qual-ident-re m3::poss-whitespace-re "(" m3::poss-whitespace-re m3::identifier-re m3::poss-whitespace-re ")" ) "\\|" (concat "REF" m3::whitespace-re ".*" "(" m3::poss-whitespace-re m3::identifier-re m3::poss-whitespace-re ")" ) "\\|" (concat m3::case-label-re (concat "\\(" m3::poss-whitespace-re "," m3::poss-whitespace-nl-re m3::case-label-re "\\)*")) "\\)" m3::poss-whitespace-re "=>")) (defconst m3::object-re (concat "\\(" m3::identifier-re "[ \t]+\\)?\\(BRANDED[ \t]+" "\\(\"[^\"]+\"\\)?[ \t]+\\)?OBJECT")) (defconst m3::part-starters (concat "\\bINTERFACE\\b\\|\\bMODULE\\b\\|\\bIMPORT\\b\\|\\bFROM\\b\\|" "\\bTYPE\\b\\|\\bEXCEPTION\\b\\|\\bVAR\\b\\|" "\\bPROCEDURE\\b\\|\\bREVEAL\\b\\|\\bCONST\\b\\|\\bBEGIN\\b") "These are the patterns that can start lines and change the indentation of the following line.") (defconst m3::keyword-endable-ssl-introducers (concat "\\bTYPE\\b\\|\\bVAR\\b\\|" "\\bRECORD\\b\\|\\bOBJECT\\b\\|\\bMETHODS\\b\\|\\bOVERRIDES\\b\\|" "\\bBEGIN\\b\\|\\bTRY\\b\\|\\bEXCEPT\\b\\|" m3::handler-start-re "\\|" "\\bFINALLY\\b\\|\\bLOOP\\b\\|\\bTHEN\\b\\|\\bELSE\\b\\|\\bREPEAT\\b\\|" "\\bDO\\b\\|\\bOF\\b\\|\\bREVEAL\\b\\|\\bCONST\\b")) (defconst m3::statement-list-starter (concat "\\bBEGIN\\b\\|\\bTRY\\b\\|\\bEXCEPT\\b\\|" m3::handler-start-re "\\|" "\\bFINALLY\\b\\|\\bLOOP\\b\\|\\bTHEN\\b\\|\\bELSE\\b\\|\\bREPEAT\\b\\|" "\\bDO\\b")) ;;; These keywords have the property that they affect the indentation if they ;;; occur at the beginning of a line. (defconst m3::keyword-line-starters (concat "\\bTYPE\\b\\|\\bPROCEDURE\\b\\|\\bEXCEPTION\\b\\|" "\\bVAR\\b\\|\\bBEGIN\\b\\|\\bTRY\\b\\|\\bEXCEPT\\b\\|" m3::handler-start-re "\\|" "|\\|\\bFINALLY\\b\\|\\bLOOP\\b\\|\\bTHEN\\b\\|\\bELSIF\\b\\|" "\\bIF\\|ELSE\\|WHILE\\|REPEAT\\|" "WITH\\|FOR\\b\\|DO\\|CASE\\|\\bOF\\b\\|TYPECASE\\|LOCK\\|CONST\\|FROM\\|" "REVEAL\\|METHODS\\|OVERRIDES")) (defconst m3::multi-keyword-line-prefix (concat "\\(" ;; ...a PROCEDURE at the start of a line that ends ;; with an equals "^PROCEDURE[^\n]*=" "\\|" ;; ... or an IF or ELSEIF that ends with a THEN "\\(IF\\|ELSIF\\)[^\n]*THEN" "\\|" ;; ... or a WHILE, WITH, FOR, or LOCK that ends with a DO "\\(WHILE\\|WITH\\|FOR\\b\\|LOCK\\)[^\n]*DO" "\\|" ;; ... or a FOR that ends with a TO or BY "FOR[^\n]*\\(DO\\|BY\\)" "\\|" ;; ... or a CASE or TYPECASE that ends with a OF "\\(CASE\\|TYPECASE\\)[^\n]*OF" "\\|" ;; ... or at a handler-start that ends with a "=>" "\\(|\\|\\)[ \t]*" m3::handler-start-re "\\)" )) (defconst m3::multi-keyword-lines (concat m3::multi-keyword-line-prefix "[ \t]*\\($\\|(\\*\\)")) (defconst m3::statement-starters (concat "BEGIN\\b\\|TRY\\b\\|LOOP\\b\\|IF\\b\\|WHILE\\b\\|REPEAT\\b\\|" "WITH\\b\\|FOR\\b\\|CASE\\b\\|TYPECASE\\b\\|LOCK\\b") "These are the patterns that can start lines and change the indentation of the following line.") (defconst m3::keyword-ssl-enders (concat "\\(|\\|\\bEXCEPT\\b\\|\\bFINALLY\\b\\|\\bELSIF\\b\\|" "\\bELSE\\b\\|\\bUNTIL\\b\\|\\bEND\\b\\)")) (defconst m3::left-parens "\\((\\|\\[\\|{\\)") (defconst m3::right-parens "\\()\\|\\]\\|}\\)") (defconst m3::statement-keywords "RETURN\\|RAISE\\|EXCEPTION\\|IMPORT\\|WITH") (defconst m3::end-matchers (concat "\\bRECORD\\b\\|\\bOBJECT\\b\\|\\bBEGIN\\b\\|\\bTRY\\b\\|\\bLOOP\\b\\|" "\\bIF\\b\\|\\bWHILE\\b\\|\\bWITH\\b\\|\\bFOR\\b\\|\\bCASE\\b\\|" "\\bTYPECASE\\b\\|\\bLOCK\\b\\|\\bINTERFACE\\b\\|\\bMODULE\\b\\|" "\\bGENERIC\\b")) (defconst m3::same-line-ssl-keywords "\\bVAR\\b\\|\\bTYPE\\b\\|\\bCONST\\b\\|\\bEXCEPTION\\b\\|\\bREVEAL\\b" "These are the keywords that can be followed by an SSL that begins on the same line -- if so, indent to the level of the first elem.") (defconst m3::case-starters "TRY\\|CASE\\|TYPECASE") ;;; ------ Variables that control indentation behavior ------------ (defvar m3::standard-offset 2) (defvar m3::continued-line-offset 2) (defvar m3::case-offset 0) (defvar m3::open-paren-offset 4) (defvar m3::open-paren-sep 0) (defvar m3::proc-param-from-proc-keyword t) (defvar m3::assign-offset 4) (defvar m3::RAISES-offset 4) (defvar m3::follow-continued-indent t) (defvar m3::END-undent 2) (defvar m3::METHODS-undent 2) (defvar m3::OVERRIDES-undent 2) (defvar m3::EXCEPT-undent 2) (defvar m3::VERT-undent 2) (defvar m3::handler-start-undent 0) (defvar m3::EXCEPT-undent 2) (defvar m3::UNTIL-undent 2) (defvar m3::FINALLY-undent 2) (defvar m3::ELSIF-undent 2) (defvar m3::ELSE-undent 2) (defvar m3::DO-undent 1) (defvar m3::OF-undent 1) (defvar m3::THEN-undent 1) (defvar m3::OBJECT-undent 1) (defvar m3::RECORD-undent 1) ;;; -------- Variables controlling keyword-completion and end-matching. (defvar m3::abbrev-enabled t "*Non-nil indicates TAB should complete keywords.") (defvar m3::electric-end 'proc-mod "*If the value of this variable is 'proc-mod or 'all, a TAB that completes an END, or occurs after a complete END, may cause some text to be inserted after the END. If the value is 'proc-mod and the END completes the main block of a procedure or a module or interface, fills in the name of the procedure, module, or interface, and a semi-colon or period as appropriate. If the value is 'all, works as for 'proc-mod, but also adds a comment containing the keyword starting the construct completed by other END's. If the value is nil, no text is added.") (defvar m3::blink-end-matchers t "*Non-nil causes a TAB that completes an END or occurs after a completed END to momentarily move the cursor to the beginning of the keyword that starts the construct completed by the END.") ;;; ---------------------------------------------------------------------- ;;; NOT USER SETTABLE. ;;; These variables enable us to "cycle through" a list of possible ;;; completions when the prefix the user typed was ambiguous. If the ;;; point is at (m3::cur-keyword-completion-start + ;;; m3::cur-keyword-completion-len nil) and ;;; m3::cur-keyword-completions is non-nil, we substitute the first ;;; element of the list for the current completion, and rotate the list. (defvar m3::cur-keyword-completion-start (make-marker) "A marker indicating the start of the last word that was keyword-completed.") (defvar m3::cur-keyword-completion-len nil "The length of the completed keyword at the time of completion, to allow us to determine if the user has entered more text.") (defvar m3::cur-keyword-completions nil "A list of the strings that matched the originally input keyword text.") ;;; ------ THE MAIN ROUTINE - SETS UP MODULA-3 MODE -------------- (defun modula-3-mode () "This is a mode intended to support program development in Modula 3. You can avoid tedious entry of constructs involving long uppercase keywords by using 'abbrev-mode.' When m3::abbrev-enabled is non-nil, TAB typed at the end of a word completes just that current word as a keyword. This mode analyzes the context to restrict the choices admitted by partial prefixes to as small a set as possible. If more than 1 choice remain after this winnowing, they are ordered according to their popularity (assigned in an ad hoc manner by me, dld, and easily changed), and the first completion is performed, with a message that other completions are possible. If the choice is wrong, hitting TAB immediately will cycle through the other choices. There are two independent mechanism for indenting/prettyprinting text. The main addition that I (dld) have made is adding the style of 'electric' indentation normally associated with gnuemacs language modes. Basically, all you need to know is that TAB, in addition to completing keywords, also indents the current line properly. The other mechanism uses a pretty printer (m3pp) that runs as a separate process. The command m3pp-region and m3pp-unit, and the variable m3pp-options are used to apply m3pp to a portion of the buffer. Another new feature is END-matching and completion. Various non-nil values of the variable 'm3::electric-end' cause hitting TAB on a line containing just an END to do things like fill in the name of the procedure, module, or interface, or the keyword that starts the construct that the END completes. Another, independent, variable, 'm3::blink-end-matchers', temporarily blinks the curser at the beginning of the construct that the END matches. Another convenient feature is that beginning-of-defun, end-of-defun, forward-sexp, and backward-sexp have been given appropriate Modula-3 definitions, and these functions have been bound to the standard keys. The following list gives the key bindings. \\{m3::mode-map}" (interactive) (kill-all-local-variables) (m3::setup-mode-map) (use-local-map m3::mode-map) (setq major-mode 'modula-3-mode) (setq mode-name "Modula 3") (setq local-abbrev-table m3::mode-abbrev-table) (set-syntax-table m3::mode-syntax-table) (make-local-variable 'paragraph-start) (setq paragraph-start (concat "^$\\|" page-delimiter)) (make-local-variable 'paragraph-separate) (setq paragraph-separate paragraph-start) (make-local-variable 'indent-line-function) (setq indent-line-function 'm3::indent-line) (make-local-variable 'require-final-newline) (setq require-final-newline t) (make-local-variable 'comment-start) (setq comment-start "(* ") (make-local-variable 'comment-end) (setq comment-end " *)") (make-local-variable 'comment-column) (setq comment-column 41) (make-local-variable 'comment-start-skip) (setq comment-start-skip "(\\*+[ \t]*") (make-local-variable 'comment-multi-line) (setq comment-multi-line t) (make-local-variable 'comment-indent-function) (setq comment-indent-function 'c-comment-indent) (make-local-variable 'parse-sexp-ignore-comments) (setq parse-sexp-ignore-comments t) (run-hooks 'm3::mode-hook)) ;;; -------------------- Electric indentation -------------------- (defun m3::indent-line () "Indent the current-line." (interactive) (m3::indent-line-work t)) (defun m3::indent-line-work (electric) ;; If in unterminated string, give an error. If in comment and ;; electric, indent like previous line. ;;; (message "indent-line-work") (sit-for 2) (let ((string-comment-state (m3::in-comment-or-string))) ;;; (message "string-comment-state = %s" string-comment-state) (sit-for 2) (cond ((eq string-comment-state 'string) (beep) (message "Unterminated Text literal...")) ((eq string-comment-state 'comment) (if electric (let ((cur-point (point))) (beginning-of-line) (m3::skip-whitespace-in-line) (cond ;; If the current line begines with a close comment, ;; indent it to the level of the matching start comment. ((save-excursion (beginning-of-line) (m3::skip-whitespace-in-line) (looking-at "*)")) (m3::indent-to cur-point (save-excursion (beginning-of-line) (m3::skip-whitespace-in-line) (forward-char 2) (m3::skip-comment-backward (point-min) t) (current-column)))) ;;; If the current line begins with an open-comment, and ;;; the opened comment is not nested, indent like a code line. ((save-excursion (beginning-of-line) (m3::skip-whitespace-in-line) (and (looking-at "(*") (not (m3::in-comment-or-string)))) (m3::indent-to cur-point (m3::indent-for-line))) ;;; Otherwise, indent to same level as previous ;;; non-whitespace line. (t (m3::indent-to cur-point (save-excursion (forward-line -1) (while (looking-at m3::whitespace-line-re) (forward-line -1)) (m3::skip-whitespace-in-line) (if (looking-at "(\\*") (progn (forward-char 2) (m3::skip-whitespace-in-line))) (current-column)))))))) ;; We're not in a comment or a string. Indent the current line. (t (m3::indent-to (point) (m3::indent-for-line)) ;; Do the appropriate thing for electric end's. (m3::do-electric-end))))) (defun m3::indent-for-line () (save-excursion (beginning-of-line) (let* ((cur-point (point)) (part-start (save-excursion (m3::backward-to-last-part-begin) (point))) (first-code (save-excursion (re-search-forward "[ \t]*" (save-excursion (end-of-line) (point)) t) (goto-char (match-end 0)) ;;; (message "first-code 2") (sit-for 2) (point))) (need-keyword (or (save-excursion (goto-char first-code) (looking-at m3::keyword-ssl-enders)) (and (save-excursion (goto-char part-start) (looking-at m3::same-line-ssl-keywords)) (save-excursion (goto-char first-code) (looking-at m3::part-starters))))) (after-keyword nil) ; non-nil indicates that the line ; used for indentation was not ; complete, but rather was ; chose because it started ; with a keyword. ;; Must do this because Modula is case-sensitive (case-fold-search nil)) ;; Now figure out if there is an intervening "incomplete ;; line" between here and the original line: ;; (A complete statement forms a complete line. Also, a line ;; ending in an ssl-introducer forms a complete line. All other ;; lines are incomplete...) (let ((prev-statement-start (point))) ;;; (message "Checking completeness") (sit-for 2) (cond ;; Is it incomplete? ((m3::prev-line-incomplete-p cur-point first-code part-start) ;; ...OK, the previous line *was* incomplete. (goto-char cur-point) ;;; (message "m3::indent-for-line: incomplete") (sit-for 2) (m3::incomplete-indent cur-point first-code part-start)) (t ;; Find beginning of statement upon which to base the ;; indentation of the current line. ;;; (message "m3::complete-line-start before") (sit-for 2) (setq after-keyword (m3::backward-to-complete-line-start part-start first-code (if need-keyword 'need))) ;;; (message "m3::complete-line-start after") (sit-for 2) ;;; (message "m3::indent-for-line: indent, ak = %s" after-keyword) ;;; (sit-for 2) (cond (after-keyword (m3::after-keyword-adjust-indent (current-column) first-code part-start)) (t (m3::complete-adjust-indent (current-column) first-code part-start))))))))) (defun m3::backward-to-complete-line-start (part-start first-code ssl-state) "Find beginning of statement upon which to base the indentation of the line whose first non-blank character is at FIRST-CODE. If SSL-STATE is 'need, the keyword at first-code is an ssl-ender, so we want to find the line that ended with the ssl-introducer that the ssl-ender ended (whew.) If Returns t iff the line found starts with a keyword-statement-starter." ;; We must find the first previous line upon which we can base ;; the indentation. Here is the algorithm: ;; We have set first-code to the character position of the first ;; character in the line to be indented. ;; Search backward for the first end-of-statement or ;; keyword-line-starter. (An end-of-statement is a ;; semicolon or END; a keyword-line-starter is a keyword ;; that changes the indentation when it starts a line.) ;; end-of-statement was found => ;; Is there any code between the end-of-statement and ;; first-code? ;; Yes => ;; Go to the first character of that code and leave the ;; point there. ;; No ==> ;; We don't know how far back this statement begins. ;; If the statement-ender is an END => ;; Find the end-matcher. ;; If that is a line starter => ;; Leave the point there. ;; Otherwise => ;; Recursively go backward-to-complete-line-start. ;; else => ;; Search backward again for the first end-of-statement, ;; ssl-introducer, or keyword-line-starter. ;; end-of-statement, ssl-introducer found => ;; forward-to-code; leave point there. ;; keyword-line-starter => ;; Leave point at the start of the keyword. ;; keyword-line-starter was found => ;; Leave point at the start of the keyword. (let ((after-keyword nil) (in-end-match nil)) ;;; (message "m3::cl-start(A) ps = %d, need = %s" part-start ssl-state) ;;; (sit-for 2) (m3::backward-to-ender-starter-or-ssl-intro part-start) ;;; (message "m3::indent-for-line(A10)") (sit-for 2) (when (looking-at m3::handler-start-re) (m3::backward-to-handler-start)) ;;; (message "m3::indent-for-line(A11)") (sit-for 2) (cond ((looking-at "\\(;\\|\\bEND\\b\\|\\bUNTIL\\b\\)") ;; end-of-statement was found => ;;; (message "m3::indent-for-line(A-x1)") (sit-for 2) (cond ((and (eq ssl-state 'need) (not (looking-at "\\bEND\\b\\|\\bUNTIL\\b"))) ;;; (message "m3::indent-for-line(A-x1-0)") (sit-for 2) (setq after-keyword (m3::backward-to-complete-line-start part-start first-code ssl-state))) (t (let ((ender-start (point))) ;;; (message "m3::indent-for-line(A-x2-0)") (sit-for 2) (m3::end-of-ender first-code) ;;; (message "m3::indent-for-line(A-x2-1)") (sit-for 2) ;; Is there any code between the end-of-statement and ;; first-code? (m3::forward-to-code (point-max)) ;;; (message "m3::indent-for-line(A-x2)") (sit-for 2) (cond ((< (point) first-code) ;; Yes => ;; Go to the first character of that code and leave the ;; point there. ;;; (message "m3::indent-for-line(A-x2b)") (sit-for 2) (setq after-keyword (looking-at (concat "\\(" m3::keyword-line-starters "\\)")))) (t ;;; (message "m3::indent-for-line(A-x2a)") (sit-for 2) ;; No ==> ;; We don't know how far back this statement begins. (goto-char ender-start) ;;; (message "m3::indent-for-line(A-x2a0)") (sit-for 2) (cond ;; If the statement ender is an END => ;; Find the end-matcher and see if it is a ;; keyword-line-starter. If not, search again... ((looking-at "\\(\\bEND\\b\\|\\bUNTIL\\b\\)") (cond ((looking-at "\\bEND\\b") (m3::backward-to-end-match part-start)) ((looking-at "UNTIL") (m3::backward-to-until-match part-start))) (setq in-end-match t) ;;; (message "m3::complete-line-start END-match 0") (sit-for 2) (let ((begin-start (point)) (not-begin nil)) (when (looking-at "BEGIN") ;; If this begin is the main body of a procedure or ;; module, skip back further to the PROCEDURE or ;; MODULE keywords. (m3::backward-to-BEGIN-owner) (if (not (= (point) begin-start)) (setq not-begin t))) ;;; (message "m3::complete-line-start END-match") (sit-for 2) (if (and (looking-at (concat "\\(" m3::keyword-line-starters "\\)")) (not (eq ssl-state 'need))) (progn (setq after-keyword not-begin) ;;; (message "&&&&") (sit-for 2) ) (setq after-keyword (m3::backward-to-complete-line-start part-start (point) ssl-state)) ;;; (message "m3::cl-start END-match recurse returns %s" ;;; after-keyword) ;;; (sit-for 2) ))) ;; else => (t ;; Search backward again for the first end-of-statement, ;; ssl-introducer, or keyword-line-starter. (setq after-keyword (m3::backward-to-complete-line-start part-start first-code ssl-state)))))))))) ;; ssl-introducer was found => ((looking-at (concat "\\(" m3::keyword-endable-ssl-introducers "\\)")) (let ((ssl-intro-start (point))) (cond ((progn ;;; (message "m3::c-l-start X -- 1a") (sit-for 2) (re-search-forward (concat "\\(" m3::keyword-endable-ssl-introducers "\\)") first-code) (goto-char (match-end 0)) ;;; (message "m3::c-l-start X -- 1a2") (sit-for 2) (m3::forward-to-code (point-max)) (< (point) first-code)) (cond ((eq ssl-state 'need) ;;; (message "m3::c-l-start X -- 1b") (sit-for 2) (goto-char ssl-intro-start) (setq after-keyword (save-excursion (goto-char first-code) (not (looking-at m3::part-starters)))) (when (not (looking-at (concat "\\(" m3::keyword-line-starters "\\)"))) (m3::backward-to-complete-line-start part-start (point) nil))) (t ;;; (message "m3::c-l-start X -- 1b2") (sit-for 2) (setq after-keyword (looking-at (concat "\\(" m3::keyword-line-starters "\\)")))))) ((progn (goto-char ssl-intro-start) (not (looking-at (concat "\\(" m3::keyword-line-starters "\\)")))) ;;; (message "m3::c-l-start Y 1") (sit-for 2) (setq after-keyword t) ;; The ssl-introducer suffices... (m3::backward-to-complete-line-start part-start (point) nil)) ;;; must be a keyword-line-starter (t ;;; (message "m3::c-l-start Z") (sit-for 2) (setq after-keyword t))))) ;; keyword-line-starter was found, or at part-start => ;; Leave point at the start of the keyword. (t ;;; (message "after keyword.") (sit-for 2) (setq after-keyword (looking-at (concat "\\(" m3::keyword-line-starters "\\)"))))) ;; One final little thing to do: ;; Regular expression search backward matches the shortest match. ;; For the handler-start-re, we can't make sure we got the whole thing, ;; because of the poss-qual-id-re. So now extend it if necessary. (when (looking-at m3::handler-start-re) (m3::backward-to-handler-start)) ;; Now: we should be at the first code of the line, or else we ;; have to look again... (when (> (save-excursion (m3::backward-to-code part-start) (point)) (save-excursion (beginning-of-line 1) (point))) ;;; (message "not first-code, in-end-match = %s" in-end-match) (sit-for 2) ;; If we're currently looking at an ssl-introducer, that cancels the ;; need for one... (when (and (eq ssl-state 'need) (looking-at (concat "\\(" m3::keyword-endable-ssl-introducers "\\)"))) (setq ssl-state nil)) (setq after-keyword (m3::backward-to-complete-line-start part-start (point) ssl-state)) (if (and in-end-match (not (eq ssl-state 'need))) (setq after-keyword nil))) ;;; (message "returning after-keyword = %s" after-keyword) (sit-for 2) after-keyword)) (defun m3::backward-to-handler-start () ;; Assumes we are looking-at a handler-start; Ensures that point is ;; at the start of that handler. (let ((new-point (point))) ;; First of all, we might not be at the start of the id... (while (save-excursion (forward-char -1) (looking-at m3::identifier-char-re)) (forward-char -1)) (setq new-point (point)) (save-excursion (forward-char -1) (cond ((looking-at "\\b.") ;;; (message "m3::backward-to-handler-start A") (sit-for 2) (forward-word -1) (when (looking-at m3::handler-start-re) (m3::backward-to-handler-start) (setq new-point (point)))) ((looking-at "[ \t,|]") ;;; (message "m3::backward-to-handler-start B") (sit-for 2) (let ((last-point (point))) (when (and (re-search-backward "[|,][ \t]*" (point-min) t) (equal (match-end 0) last-point)) (cond ((looking-at "|") (setq new-point (match-beginning 0))) ((looking-at ",") (forward-word -1) (m3::backward-to-handler-start) (setq new-point (point))))))))) (goto-char new-point))) (defun m3::backward-to-ender-starter-or-ssl-intro (min-point) "Moves backwards to the beginning of the first statement ender, that is semi-colon or END or UNTIL, or starter (m3::keyword-line-starters) or ssl-introducer, or, if none are found before min-point, to min-point." ;;; (message "m3::backward-to...0") (m3::re-search-backward (concat "\\(;\\|\\bEND\\b\\|\\bUNTIL\\b\\|" "^[ \t]*\\(" m3::keyword-line-starters "\\)\\|" m3::keyword-endable-ssl-introducers "\\)") min-point 'move-to-point) ;;; (message "m3::backward-to...0.1") (sit-for 1) (while (m3::in-arg-list min-point) ;;; (message "m3::backward-to...0.5") (sit-for 1) ;;; (message "m3::backward-to...0.51") (sit-for 1) (m3::re-search-backward (concat "\\(;\\|\\bEND\\b\\|\\bUNTIL\\b\\|" "^[ \t]*\\(" m3::keyword-line-starters "\\)\\|" m3::keyword-endable-ssl-introducers "\\)") min-point t)) ;;; (message "m3::backward-to...1") (sit-for 2) (cond ((looking-at ";") (let ((p (point))) (m3::backward-to-code min-point) (forward-word -1) (if (and (not (looking-at "\\bEND\\b")) (progn (forward-word -1) (not (looking-at "\\bEND\\b")))) (goto-char p)))) ((looking-at (concat "^[ \t]*\\(" m3::keyword-line-starters "\\)")) ;; Must be a keyword-line-starter or ssl-introducer... ;;; (message "m3::backward-to...2") (sit-for 2) (re-search-forward "[ \t]*" (point-max) t)))) (defun m3::end-of-ender (max-point) "Assumes point is looking-at END or UNTIL or semi-colon" (cond ((looking-at "\\bEND\\b") (forward-word 1) (let ((p (point))) (m3::forward-to-code max-point) (if (looking-at ";") (forward-char 1) (forward-word 1) (if (looking-at "[;.]") (forward-char 1) (goto-char p))))) ((looking-at "UNTIL") (forward-word 1) (m3::re-search-forward "\\(;\\|\\bEND\\b\\|\\bUNTIL\\b\\|$\\)" (point-max) 'move-to-limit) (cond ((looking-at ";") (forward-char 1)) (t (m3::backward-to-code (point-min))))) (t ; semi-colon (forward-char 1)))) (defun m3::in-arg-list (part-start) "Returns non-NIL iff the point is in a procedure or method argument list." ;;; (message "m3::in-arg-list(1)") (sit-for 2) (save-excursion (let ((cur-point (point))) (m3::re-search-backward "PROCEDURE\\|METHODS" part-start t) (cond ((looking-at "PROCEDURE") (forward-word 1) (m3::re-search-forward "([^*]" (point-max) t) ;;; (message "m3::in-arg-list(3)") (sit-for 2) (and (< (point) cur-point) (condition-case err (progn (forward-sexp 1) ;;; (message "m3::in-arg-list(4)") (sit-for 2) (> (point) cur-point)) (error t)))) ((looking-at "METHODS") (let ((continue t) (res nil)) (while (and continue (< (point) cur-point)) (m3::re-search-forward "([^*]\\|\\bEND\\b" (point-max) t) ;;; (message "m3::in-arg-list(101)") (sit-for 2) (cond ((and (looking-at "([^*]") (< (point) cur-point)) ;;; (message "m3::in-arg-list(101.5)") (sit-for 2) (condition-case err (progn (forward-sexp 1) ;;; (message "m3::in-arg-list(102)") (sit-for 2) (if (> (point) cur-point) (setq res t))) (error ;; No matching right paren, so must still be in arg list. ;;; (message "m3::in-arg-list(103)") (sit-for 2) (setq continue nil) (setq res t)))) (t ;;; (message "m3::in-arg-list(104)") (sit-for 2) (setq continue nil)))) res)) (t nil))))) (defun m3::prev-line-incomplete-p (cur-point first-code part-start) ;;; (message "incomplete?") (sit-for 2) (and ;; If the last word of the previous line is ";", "END", or an ;; ssl-introducer, the previous line is complete. (save-excursion (goto-char cur-point) ;;; (message "incomplete: at-cur-point") (sit-for 2) (m3::backward-to-code part-start) ;;; (message "incomplete: at prev-code") (sit-for 2) (not (or (and (eq (point) part-start) (looking-at "(*")) (save-excursion (and (> (point) 1) (progn (forward-char -1) (looking-at ";")))) (progn (forward-word -1) (looking-at (concat "\\(\\bEND\\b\\|" m3::keyword-endable-ssl-introducers "\\)")))))) (or ;; Does the previous non-blank line end with an operator? (save-excursion ;;; (message "incomplete-1") (sit-for 2) (goto-char cur-point) (m3::backward-to-code part-start) (or (looking-at "[+\\-*&#<,(]") (and (looking-at ">") (save-excursion (beginning-of-line) ;;; (message "incomplete-1.1") (sit-for 2) (not (looking-at (concat "[ \t]*" m3::handler-start-re "[ \t]*\\($\\|(\\*\\)"))))) (and (looking-at "=") (save-excursion ;;; (message "incomplete-1.2") (sit-for 2) (beginning-of-line) ;;; (message "incomplete-1.21") (sit-for 2) (and (not (looking-at (concat "PROCEDURE.*=[ \t]*\\($\\|(\\*\\)"))) (not (m3::in-arg-list part-start))))) (and (looking-at ";") (m3::in-arg-list part-start)) (and (> (point) 2) (progn (forward-char -2) (or (looking-at (concat m3::not-identifier-char-re "OR")) (and (> (point) 1) (progn (forward-char -1) (looking-at (concat m3::not-identifier-char-re "\(DIV\\|MOD\\|AND\\|NOT"))))))))) (save-excursion (goto-char cur-point) (m3::backward-to-code part-start) (and (> (point) part-start) (progn (forward-char 1) ;;; (message "incomplete-1B1") (sit-for 2) (let ((last-char (point))) (beginning-of-line 1) (and (re-search-forward (concat "^[ \t]*\\(" m3::statement-keywords "\\)") cur-point t) (= last-char (match-end 0))))))) (save-excursion ;;; (message "incomplete-2") (sit-for 2) (cond ((looking-at "\\bEND;\\b") ;;; (message "incomplete-2.01") (sit-for 2) (forward-char 4)) ((looking-at (concat "\\bEND[ \t]*" m3::identifier-re "[ \t]*\\(;\\|\\.\\)")) ;;; (message "incomplete-2.02") (sit-for 2) (re-search-forward (concat "\\bEND[ \t]*" m3::identifier-re "[ \t]*\\(;\\|\\.\\)") (point-max) t) (goto-char (match-end 0))) ((looking-at m3::multi-keyword-line-prefix) ;;; (message "incomplete-2.1") (sit-for 2) (re-search-forward m3::multi-keyword-line-prefix (point-max) t) (goto-char (match-end 0))) ((looking-at "PROCEDURE") ;;; (message "incomplete-2.15") (sit-for 2) (forward-word 1) (m3::re-search-forward "([^*]" (point-max) t) (let ((new-point (point))) (save-excursion (condition-case err (forward-sexp 1) (error (goto-char (point-max)))) ;;; (message "incomplete-2.15-2") (sit-for 2) (and (< (point) cur-point) (m3::re-search-forward "=" (point-max) t) (progn (forward-char 1) (and (< (point) cur-point) ;;; (message "incomplete-2.15-3") (sit-for 2) (setq new-point (point)))))) (goto-char new-point))) ((looking-at "WITH") ;;; (message "incomplete-2.191") (sit-for 2) (forward-word 1) (let ((new-point (point))) (m3::re-search-forward "DO" first-code t) ;;; (message "incomplete-2.192") (sit-for 2) (cond ((looking-at "DO") (forward-word 1) ;;; (message "incomplete-2.193") (sit-for 2) (setq new-point (point)))) (goto-char new-point))) ((looking-at "\\bEND\\b") (forward-word 1) (cond ((save-excursion (m3::forward-to-code (point-max)) (looking-at ";")) (m3::forward-to-code (point-max)) (forward-char 1)))) ;; If looking-at keyword-line-starter or part-starter ((looking-at (concat m3::keyword-line-starters "\\|" m3::part-starters)) ;;; (message "incomplete-2.2") (sit-for 2) (re-search-forward (concat m3::keyword-line-starters "\\|" m3::part-starters) (point-max) t) (goto-char (match-end 0))) ((looking-at ";") (forward-char 1))) ;; Go forward to code. ;;; (message "m3::IFL: before codepoint") (sit-for 2) (m3::forward-to-code (point-max)) ;; Is there something between the last ';' and the current ;; line? ;;; (message "m3::IFL: codepoint") (sit-for 2) (and (< (point) cur-point) ;; Yes -- means that the previous statement was incomplete... ;; ...unless the current line is an ssl-ender, in which ;; case it is assumed complete... ;;; (message "incomplete-3") (sit-for 2) (or (not (save-excursion (goto-char first-code) ;;; (message "incomplete-3.1") (sit-for 2) (looking-at m3::keyword-ssl-enders))) (save-excursion ;;; (message "incomplete-3.2") (sit-for 2) (goto-char first-code) (m3::backward-to-code part-start) (forward-char 1) ;;; (message "incomplete-3.21") (sit-for 2) (let ((after (point))) (m3::re-search-backward m3::keyword-endable-ssl-introducers part-start t) (re-search-forward m3::keyword-endable-ssl-introducers cur-point t) (goto-char (match-end 0)) ;;; (message "incomplete-3.22") (sit-for 2) (= (point) after)))) ;; ... or there is a an ssl-ender between here and first-code ;; that is not a semi in an argument list... (not (save-excursion ;;; (message "incomplete-3.3-0") (sit-for 2) (and (m3::re-search-forward (concat ";\\|" m3::keyword-ssl-enders) first-code 't) (let ((continue t)) (while (and continue (m3::in-arg-list part-start)) ;;; (message "incomplete-3.3-1") (sit-for 2) (re-search-forward (concat ";\\|" m3::keyword-ssl-enders) first-code 't) (goto-char (match-end 0)) ;;; (message "incomplete-3.3-2") (sit-for 2) (setq continue (m3::re-search-forward (concat ";\\|" m3::keyword-ssl-enders) first-code 't))) continue) ;;; (message "incomplete-3.3") (sit-for 2) (< (point) first-code)))) ;; ... or the previous statement is a multi-keyword statement ;; and the current line is completed by a subsequent keyword... (not (save-excursion (goto-char cur-point) (m3::backward-to-non-comment-line-start part-start) ;;; (message "m3::indent-for-line: multi-keyword") (sit-for 2) (looking-at m3::multi-keyword-lines))) ))))) (defun m3::after-keyword-adjust-indent (indent first-code part-start) "Point is looking at a keyword at column INDENT; if the current line has any code it starts at FIRST-CODE. Return the proper indentation for the current line." ;;; (message "m3::after-keyword: indent = %d" indent) (sit-for 2) (let ((call-adjust-indent t)) (cond ((looking-at "\\bEND\\b") ;;; (message "m3::after-keyword(END): i: %d, m3::END: %d, m3::stand: %d" ;;; indent m3::END-undent m3::standard-offset) ;;; (sit-for 2) (setq indent (- (+ indent m3::END-undent) m3::standard-offset))) ((looking-at "ELSE") (setq indent (+ indent m3::ELSE-undent)) (if (m3::in-case part-start) (setq indent (+ indent m3::case-offset)))) ((looking-at "METHODS") (setq indent (+ indent m3::METHODS-undent))) ((looking-at "OVERRIDES") (setq indent (+ indent m3::OVERRIDES-undent))) ((looking-at "EXCEPT\\b") ;;; (message "m3::after-keyword: EXCEPT" indent) (sit-for 2) (setq indent (+ indent m3::EXCEPT-undent))) ((looking-at "|") ;;; (message "m3::after-keyword: vert" indent) (sit-for 2) (setq indent (+ indent m3::VERT-undent m3::case-offset))) ((looking-at m3::handler-start-re) ;;; (message "m3::after-keyword: handler-start" indent) (sit-for 2) (setq indent (+ indent m3::handler-start-undent m3::case-offset))) ((looking-at "FINALLY") (setq indent (+ indent m3::FINALLY-undent))) ((looking-at "THEN") (setq indent (+ indent m3::THEN-undent))) ((looking-at "ELSIF") (setq indent (+ indent m3::ELSIF-undent))) ((looking-at "ELSE") (setq indent (+ indent m3::ELSE-undent))) ((looking-at "DO") (setq indent (+ indent m3::DO-undent))) ((looking-at "OF") (setq indent (+ indent m3::OF-undent))) ((looking-at m3::object-re) (setq indent (+ indent m3::OBJECT-undent))) ((looking-at "RECORD") (setq indent (+ indent m3::RECORD-undent))) ;; These are the keywords that can be followed by an SSL that begins on ;; the same line -- if so, indent to the level of the first elem. ((looking-at m3::same-line-ssl-keywords) ;;; (message "m3::after-keyword: same-line-ssl") (sit-for 2) (let ((eol (save-excursion (end-of-line 1) (point)))) (save-excursion (forward-word 1) (m3::forward-to-code (point-max)) ;;; (message "m3::after-keyword: SlSSL(2)") (sit-for 2) (cond ((and m3::follow-continued-indent ;;; (progn (message "m3::after-keyword: SlSSL(2.1)") (sit-for 2) t) (<= (point) eol) ;;; (progn (message "m3::after-keyword: SlSSL(2.2)") (sit-for 2) t) (save-excursion (goto-char first-code) (not (looking-at (concat m3::part-starters "\\|BEGIN\\|\\bEND\\b")))) ;;; (progn (message "m3::after-keyword: SlSSL(2.3)") (sit-for 2) t) (save-excursion (goto-char first-code) (m3::backward-to-code part-start) (looking-at ";")) ;;; (progn (message "m3::after-keyword: SlSSL(2.4)") (sit-for 2) t) ) ;;; (message "m3::after-keyword: SLSSL (3)") (sit-for 2) (setq indent (current-column)) (setq call-adjust-indent nil)) (t (setq indent (+ indent m3::standard-offset))))))) ;; These are all the keywords that don't affect the indentation ;; when they start complete lines. ((looking-at (concat "INTERFACE\\|MODULE\\|IMPORT\\|FROM\\|EXCEPTION")) ;;; (message "m3::after-keyword: no extra") (sit-for 2) indent) ;; Otherwise, give the standard indentation. (t ;;; (message "m3::after-keyword: standard") (sit-for 2) (setq indent (+ indent m3::standard-offset)))) (cond (call-adjust-indent (save-excursion (goto-char first-code) ;;; (message "m3::after-keyword: calling complete-adjust") (sit-for 2) (m3::complete-adjust-indent indent first-code part-start))) (t ;;; (message "m3::after-keyword: not calling complete-adjust") (sit-for 2) indent)))) (defun m3::in-case (part-start) ;;; (message "M3::in-case") (sit-for 2) (save-excursion (let ((cur-point (point))) (m3::backward-to-end-match part-start) ;;; (message "M3::in-case(2)") (sit-for 2) (and (looking-at m3::case-starters) (progn (cond ((looking-at "TRY") (forward-word 1) ;; Is it a TRY-FINALLY or a TRY-EXCEPT? (let (res (continue t)) (while continue (setq res (m3::re-search-forward "TRY\\|EXCEPT\\|FINALLY" cur-point t)) ;;; (message "M3::in-case(3)") (sit-for 2) (cond ((looking-at "EXCEPT") (setq continue nil)) ((looking-at "TRY") ;; Go to matching END and try again (m3::forward-to-end-match cur-point)) (t;; FINALLY or not found (setq res nil) (setq continue nil)))) res)) (t t))) ;;; We are now looking at a case starter. Make sure there is ;;; at least one case arm starter. (progn (cond ((looking-at "EXCEPT") (forward-word 1)) ((looking-at "CASE\\|TYPECASE") (forward-word 1) (m3::re-search-forward "OF" cur-point 'move-to-limit) (forward-word 1))) (m3::forward-to-code cur-point) ;;; (message "M3::in-case: about to test handler") (sit-for 2) (and (< (point) cur-point) (looking-at m3::handler-start-re))) ;;; (message "M3::in-case: returning t") (sit-for 2) )))) (defun m3::in-continued-record-def (part-start) (if (not (looking-at "\\bEND\\b")) (error "m3::in-continued-record-def assumes looking-at END")) (save-excursion (m3::backward-to-end-match part-start) (let ((end-match (point)) (eol (save-excursion (end-of-line) (point)))) (beginning-of-line) (or (save-excursion (re-search-forward "[ \t]*" eol t) (= (point) end-match)) (save-excursion (and (re-search-forward "[ \t]*BRANDED[ \t]+" eol t) (= (point) end-match) (save-excursion (goto-char end-match) (looking-at "OBJECT")))))))) (defun m3::correct-for-trailing-ends (indent part-start) ;; If the previous line ends in a (series of) END(s) that does ;; (do) not start the line, and are unmatched by the start of the line, ;; subtract the END-undent(s) from indent (the Eric Muller convention.) ;;; (message "correct-for-trailing-ends in: %d" indent) (sit-for 2) (let ((prev-line-start (save-excursion (m3::backward-to-code part-start) (beginning-of-line) (m3::forward-to-code (point-max)) ;;; (message "correct-for-trailing-ends (0)") (sit-for 2) (point)))) (save-excursion (if (save-excursion (m3::backward-to-code part-start) (beginning-of-line) (not (looking-at "[ \t]*END\\b"))) (save-excursion (let ((continue t)) (while continue ;; Move back to just after the last "real" (non-";") code (m3::backward-to-code part-start) ;;; (message "correct-for-trailing-ends (1)") (sit-for 2) (if (looking-at ";") (m3::backward-to-code part-start)) (forward-char 1) ;;; (message "correct-for-trailing-ends (2)") (sit-for 2) ;; Now, what are we looking at? (cond ;; Is it an END? ((or (save-excursion (forward-word -1) (looking-at "\\bEND\\b")) (save-excursion (forward-word -2) (looking-at (concat "\\bEND\\b" m3::poss-whitespace-re m3::identifier-re m3::poss-whitespace-re ";")))) ;; Move back to the beginning of the end... (re-search-backward "\\bEND\\b" part-start t) (goto-char (match-beginning 0)) ;;; (message "correct-for-trailing-ends (3)") (sit-for 2) (if (not (looking-at "\\bEND\\b")) (error "m3::complete-adjust-indent(A)")) ;; Find the end matcher. (let ((em-point (save-excursion (m3::backward-to-end-match part-start) ;;; (message "correct-for-trailing-ends EM") (sit-for 2) (point)))) ;;; (message "xxx") (sit-for 2) (cond ((< em-point prev-line-start) (goto-char prev-line-start) ;;; (message "xxx<") (sit-for 2) (setq indent (save-excursion (goto-char em-point) (current-column))) (setq continue nil)) ((= em-point prev-line-start) ;;; (message "xxx=") (sit-for 2) (setq indent (- indent m3::END-undent)) (setq continue nil)) ((> em-point prev-line-start) (goto-char em-point))))) (t (setq continue nil)))))))) ;;; (message "m3::trailing-end returns %d" indent) (sit-for 2) indent)) (defun m3::complete-adjust-indent (indent first-code part-start) "Previous statement is complete and starts at column INDENT; if the current line has any code it starts at FIRST-CODE. Returns the proper indentation for the current line." ;;; (message "m3::complete-adjust(A): indent = %d, first-code = %d" ;;; indent first-code) ;;; (sit-for 2) (save-excursion (goto-char first-code) ;;; (message "m3::complete-adjust(B)") (sit-for 2) ;; If the previous line ends in a (series of) END(s) that does ;; (do) not start the line, and are unmatched before the start of the line, ;; add the END-undent(s) (the Eric Muller convention.) ;;; (setq indent (m3::correct-for-trailing-ends indent part-start)) ;;; (message "yyy2: indent = %d" indent) (sit-for 2) (cond ;; Some things can only start parts, and must be on the left margin. ((looking-at (concat "REVEAL\\b\\|EXCEPTION\\b\\|" "FROM\\b\\|IMPORT\\b")) 0) ;; These can start parts, but can also appear in the procedures. ((looking-at (concat "\\(PROCEDURE\\b\\|CONST\\b\\|VAR\\b\\|TYPE\\b\\|BEGIN\\b\\)")) ;; Look backwards for line-beginning-keywords that increase the ;; indentation, start an SSL, but don't require an END (i.e., ;; TYPE, VAR, or CONST); or END's. If the former is found first, ;; decrease the indentation to the same as the keyword line's. ;; If an END is found whose matcher is not something that can ;; occur in a TYPE, VAR, or CONST (i.e. RECORD or OBJECT), ;; indent normally. If neither is found, indent normally. ;;; (message "yyy7") (sit-for 2) (let ((new-indent indent) (continue t)) (while continue ;;; (message "xxx1") (sit-for 2) (m3::re-search-backward (concat "\\(^[ \t]*\\(" m3::same-line-ssl-keywords "\\)\\|" "\\bEND\\b\\|" m3::statement-starters "\\)") part-start 'move-to-limit) ;;; (message "xxx2") (sit-for 2) (cond ;; If we reached the part-start because of the move-to-limit, ;; indent to here... ((looking-at (concat "^\\(" m3::part-starters "\\)")) ;;; (message "xxx2.5") (sit-for 2) (goto-char first-code) ;; If its the start of a procedure def, indent normally. ;; Otherwise, indent to left margin. (if (not (m3::after-procedure-introducer part-start)) (setq new-indent 0)) (setq continue nil)) ((and (looking-at (concat "^[ \t]*\\(" m3::same-line-ssl-keywords "\\)")) (not (m3::in-arg-list part-start))) (setq continue nil) ;;; To accomodate part-starters that establish new indentations, ;;; indent to the level of the previous part-starter, unless ;;; that was a BEGIN. (goto-char first-code) (m3::re-search-backward (concat m3::part-starters "\\|BEGIN") part-start t) (while (m3::in-arg-list part-start) (m3::re-search-backward (concat m3::part-starters "\\|BEGIN") part-start t)) ;;; (message "xxx3") (sit-for 2) (cond ((looking-at "BEGIN") (setq new-indent (- new-indent m3::standard-offset))) (t (setq new-indent (current-column))))) ((looking-at (concat "\\bEND[ \t]*" m3::identifier-re "[ \t]*;")) (setq continue nil) (setq new-indent (- new-indent m3::standard-offset))) ((looking-at "\\bEND\\b") (m3::backward-to-end-match part-start) ;;; (message "xxxEND-match") (sit-for 2) (cond ((looking-at "\\(RECORD\\|OBJECT\\)") nil) (t (setq continue nil)))) (t (setq continue nil)))) new-indent)) ;; If the current line is an END, add the END-undent. ((looking-at "\\bEND\\b") ;;; (message "zzz1") (sit-for 2) (cond ((m3::in-case part-start) (- indent m3::END-undent m3::case-offset)) ((save-excursion (m3::backward-to-end-match (point-min)) (looking-at "^INTERFACE\\|^MODULE\\|^UNSAFE\\|^GENERIC")) 0) (t ;;; (message "Subtracting %d from indent %d." m3::END-undent indent) (- indent m3::END-undent)))) ((looking-at "ELSE") (- indent m3::ELSE-undent (if (m3::in-case part-start) m3::case-offset 0))) ((looking-at "METHODS") (- indent m3::METHODS-undent)) ((looking-at "OVERRIDES") (- indent m3::OVERRIDES-undent)) ((looking-at "EXCEPT") (- indent m3::EXCEPT-undent)) ((looking-at "UNTIL") (- indent m3::UNTIL-undent)) ((looking-at "|") (cond ((save-excursion (m3::backward-to-code part-start) ;;; (message "zzz2") (sit-for 2) (or (save-excursion (and (> (point) 1) (progn (forward-char -1) (looking-at "OF")))) (save-excursion (and (> (point) 5) (progn (forward-char -5) (looking-at "EXCEPT")))))) (- indent m3::VERT-undent)) (t (- indent m3::VERT-undent m3::case-offset)))) ((looking-at "FINALLY") (- indent m3::FINALLY-undent)) ((looking-at "THEN") (- indent m3::THEN-undent)) ((looking-at "ELSIF") (- indent m3::ELSIF-undent)) ((looking-at "ELSE") (- indent m3::ELSE-undent)) ((looking-at "DO") (- indent m3::DO-undent)) ((looking-at "OF") (- indent m3::OF-undent)) ((looking-at "RECORD") ;;; (message "zzz-record") (sit-for 2) (- indent m3::RECORD-undent)) ((looking-at m3::object-re) ;;; (message "zzz-object") (sit-for 2) (- indent m3::OBJECT-undent)) (t ;;; (message "zzz-t: indent = %d" indent) (sit-for 2) indent)))) (defun m3::incomplete-indent (cur-point first-code part-start) (let* (list-indent (prev-line-start (save-excursion (m3::backward-to-non-comment-line-start part-start) (point))) (last-char-prev-line (save-excursion (m3::backward-to-non-comment-line-start part-start) (end-of-line) (m3::backward-to-code (save-excursion (beginning-of-line) (point))) (point))) (prev-line-indent (save-excursion (m3::backward-to-non-comment-line-start part-start) (let ((pli (current-column))) (cond ((looking-at m3::statement-keywords) (forward-word 1) (m3::forward-to-code first-code) (cond ((<= (point) last-char-prev-line) (current-column)) (t pli))) (t pli)))))) ;;; (message "m3::incomplete-indent(A)") (sit-for 2) (cond ;; Did the previous non-blank line end with a paren? ((save-excursion (goto-char last-char-prev-line) (looking-at m3::left-parens)) ;;; (message "m3::incomplete-indent(PAREN)") (sit-for 2) ;; Find the indentation of the previous line, ;; either add open-paren-offset, or indent of paren + ;; open-paren-sep (goto-char last-char-prev-line) (cond (m3::open-paren-offset ;;; (message "m3::incomplete-indent(PAREN offset)") (sit-for 2) (re-search-backward (concat m3::identifier-re m3::poss-whitespace-re) part-start t) (goto-char (match-beginning 0)) ;; Account for qualified names. (cond ((save-excursion (and (> (point) 1) (progn (forward-char -1) (looking-at "\\.")))) (re-search-backward (concat m3::identifier-re m3::poss-whitespace-re) part-start t) (goto-char (match-beginning 0)))) ;;; (message "m3::incomplete-indent(PAREN offset 2)") (sit-for 2) (if (and m3::proc-param-from-proc-keyword (save-excursion (forward-word -1) (looking-at "PROCEDURE"))) (forward-word -1)) ;;; (message "m3::incomplete-indent(PAREN offset 3)") (sit-for 2) (+ (current-column) m3::open-paren-offset)) (t (+ (current-column) m3::open-paren-sep)))) ;; Did the previous line end with a ',' or ';'?: ((save-excursion (goto-char last-char-prev-line) (looking-at ",\\|;")) ;;; (message "m3::incomplete-indent(COMMA)") (sit-for 2) ;; Skip over any matched parens; if this puts us at a line ;; containing an unmatched left paren, indent to that + ;; paren-sep. Otherwise, indent same as beginning of that line. (save-excursion (goto-char last-char-prev-line) (let ((continue t) res) (while continue ;;; (message "m3::incomplete-indent(COMMA) 0") (sit-for 2) (m3::re-search-backward (concat m3::left-parens "\\|" m3::right-parens) (save-excursion (beginning-of-line) (point)) 'move-to-limit) ;;; (message "m3::incomplete-indent(COMMA) 1") (sit-for 2) (cond ((looking-at m3::left-parens) ;;; (message "m3::incomplete-indent(COMMA) lp") (sit-for 2) (setq continue nil) (forward-char 1) (re-search-forward "[ \t]*") (goto-char (match-end 0)) (setq list-indent (current-column))) ((looking-at m3::right-parens) ;;; (message "m3::incomplete-indent(COMMA) rp") (sit-for 2) (forward-char 1) (backward-sexp 1)) (t ;;; (message "m3::incomplete-indent(COMMA) none") (sit-for 2) (beginning-of-line) (skip-chars-forward "[ \t]") (setq continue nil) (setq list-indent (current-column))))) ;;; (message "m3::incomplete-indent(COMMA) end") (sit-for 2) (cond ((looking-at (concat "|[ \t]*" m3::identifier-char-re)) (forward-word 1) (forward-word -1) (setq list-indent (current-column))) ((looking-at m3::statement-keywords) (forward-word 1) (re-search-forward "[ \t]*" last-char-prev-line t) (setq list-indent (current-column)))))) list-indent) ;; Did the previous non-blank line end a procedure header? ((m3::after-procedure-introducer part-start) ;;; (message "m3::incomplete-indent(PROCEDURE)") (sit-for 2) (goto-char last-char-prev-line) (m3::re-search-backward "PROCEDURE" part-start t) (+ (current-column) m3::standard-offset)) ;; Does the current line start a RAISES clause? ((looking-at "^[ \t]*RAISES") ;;; (message "m3::incomplete-indent(RAISES)") (sit-for 2) (goto-char last-char-prev-line) (m3::re-search-backward "\\(PROCEDURE\\|METHODS\\)" part-start t) (if (looking-at "METHODS") (progn (forward-word 1) (m3::forward-to-code (point-max)))) (+ (current-column) m3::RAISES-offset)) ;; Did the previous line end with an assignment? ((save-excursion (goto-char last-char-prev-line) (beginning-of-line) ;;; (message "m3::incomplete-indent(:= 1)") (sit-for 2) (and (m3::re-search-forward ":=" (1+ last-char-prev-line) t) (re-search-forward "[^ \t]" last-char-prev-line t))) ;;; (message "m3::incomplete-indent(:=)") (sit-for 2) (goto-char last-char-prev-line) (beginning-of-line) (m3::re-search-forward ":=" last-char-prev-line t) (forward-char 2) (re-search-forward "[ \t]*[^ \t]") (+ (- (current-column) 1) m3::assign-offset)) ;; Otherwise: (t ;;; (message "m3::incomplete-indent(OTHER)") (sit-for 2) ;; Find out if the previous line begins the statement. (goto-char prev-line-start) (m3::re-search-backward (concat ";\\|" m3::keyword-line-starters "\\|" m3::part-starters "\\|" m3::statement-keywords) part-start t) (while (m3::in-arg-list part-start) (m3::re-search-backward (concat ";\\|" m3::keyword-line-starters "\\|" m3::part-starters "\\|" m3::statement-keywords) part-start t)) ;;; (message "m3::incomplete-indent(OTHER1)") (sit-for 2) (if (or (> (point) part-start) (and (= (point) part-start) (looking-at m3::keyword-endable-ssl-introducers))) (progn (re-search-forward (concat ";\\|" m3::keyword-line-starters "\\|" m3::part-starters "\\|" m3::statement-keywords) cur-point t) (goto-char (match-end 0)))) ;;; (message "m3::incomplete-indent(OTHER1.5)") (sit-for 2) (m3::forward-to-code (point-max)) ;;; (message "m3::incomplete-indent(OTHER2), prev-line-start = %d" ;;; prev-line-start) ;;; (sit-for 2) (cond ;; If the previous line begins the statement, add ;; m3::standard-offset to indentation, unless the prev-line-indent ;; has already skipped over a keyword. ((= (point) prev-line-start) ;;; (message "m3::incomplete-indent(START): prev-line-indent = %d" ;;; prev-line-indent) ;;; (sit-for 2) (m3::complete-adjust-indent ;; Indent further if we haven't indented already. (cond ((= prev-line-indent (save-excursion (goto-char prev-line-start) (current-column))) (+ prev-line-indent m3::continued-line-offset)) (t prev-line-indent)) first-code part-start)) (t ;;; (message "m3::incomplete-indent(CONT)") (sit-for 2) ;; Otherwise, same indentation as previous, modulo adjustment ;; for current line prev-line-indent)))))) (defun m3::after-procedure-introducer (part-start) "Returns t iff first non-blank non-comment character before point is the '=' of a procedure definition." (save-excursion (m3::backward-to-code part-start) (and (looking-at "=") ;;; (message "m3::API(0)") (sit-for 2) (let ((eq-point (point))) (and ;; Not that this does not allow any comments in ;; PROCEDURE Foo ;; and all must occur on the same line. (m3::re-search-backward (concat "PROCEDURE[ \t]*" m3::identifier-re "[ \t]*(") part-start t) ;;; (message "m3::API(1)") (sit-for 2) (progn (re-search-forward (concat "PROCEDURE[ \t]*" m3::identifier-re "[ \t]*(") eq-point t) (goto-char (match-end 0)) ;;; (message "m3::API(2)") (sit-for 2) (forward-char -1) (and (condition-case err (progn (forward-sexp 1) t) (error nil)) ;;; (message "m3::API(3)") (sit-for 2) ;; We should now be at the right paren of the arg-list. ;; Check for a return type. (progn (m3::forward-to-code eq-point) (and ;;; (message "m3::API(4)") (sit-for 2) (cond ((looking-at ":") (forward-char 1) (m3::forward-to-code eq-point) (and (looking-at m3::poss-qual-ident-re) (progn (re-search-forward m3::poss-qual-ident-re eq-point t) (goto-char (match-end 0)) (m3::forward-to-code eq-point) t))) (t t)) ;; Now check for RAISES clause. ;;; (message "m3::API(5)") (sit-for 2) (cond ((looking-at "RAISES") (forward-word 1) (m3::forward-to-code eq-point) (cond ((looking-at "ANY") (forward-word 1) (m3::forward-to-code eq-point) t) ((looking-at "{") ;;; (message "m3::API(5.5)") (sit-for 2) (and (condition-case err (progn (forward-sexp 1) t) (error nil)) (progn (m3::forward-to-code eq-point) t))) (t t))) (t t)) ;; Now, we better be back to the original =! (= (point) eq-point)))))))))) (defun m3::backward-to-end-match (part-start &optional depth) (if (not depth) (setq depth 0)) (let (res (case-fold-search nil) (continue t)) (while continue ;;; (message "m3::backward-to-end-match(1) [%d]" depth) (sit-for 1) (setq res (m3::re-search-backward (concat "\\(" m3::end-matchers "\\|\\bEND\\b\\)") part-start t)) (cond ((and res (looking-at "\\bEND\\b")) (m3::backward-to-end-match part-start (1+ depth))) (t (setq continue nil)))) res)) (defun m3::forward-to-end-match (max-point &optional depth) (if (not depth) (setq depth 0)) (if (looking-at (concat "\\(" m3::statement-starters "\\)")) (forward-word 1) ) (let (res (case-fold-search nil) (continue t)) (while continue ;;; (message "m3::backward-to-end-match(1) [%d]" depth) (sit-for 1) (setq res (m3::re-search-forward (concat "\\(" m3::statement-starters "\\|\\bEND\\b\\)") max-point t)) (cond ((looking-at m3::statement-starters) (m3::forward-to-end-match max-point (1+ depth))) (t ;; looking at END or reached max-point (forward-word 1) (setq continue nil)))) res)) (defun m3::backward-to-until-match (part-start &optional depth) (if (not depth) (setq depth 0)) (let (res (case-fold-search nil) (continue t)) (while continue ;;; (message "m3::backward-to-end-match(1) [%d]" depth) (sit-for 1) (setq res (m3::re-search-backward (concat "\\(\\bREPEAT\\b\\|\\bUNTIL\\b\\)") part-start t)) (cond ((and res (looking-at "UNTIL")) (m3::backward-to-until-match part-start (1+ depth))) (t (setq continue nil)))) res)) (defun m3::forward-sexp (n) "Moves forward to the (end of the) END that terminates the current innermost syntactic unit. With a prefix argument, does that N times." (interactive "p") (while (and (> n 0) (< (point) (point-max))) (m3::forward-to-end-match (point-max)) (setq n (- n 1)))) (defun m3::backward-sexp (n) "Moves backward to the (start of) the keyword that starts the current innermost syntactic unit. With a prefix argument, does that N times." (interactive "p") (while (and (> n 0) (> (point) (point-min))) ;; Make forward and backward sexp inverses... (forward-word -1) (m3::backward-to-end-match (point-min)) (setq n (- n 1)))) (defun m3::end-of-defun (n) "Moves forward to the line after the end of the current 'defun', or top-level syntactic unit. With a prefix argument, does that N times." (interactive "p") (while (and (> n 0) (< (point) (point-max))) (m3::end-of-defun-work) (setq n (- n 1)))) (defun m3::end-of-defun-work () (skip-chars-forward " \t\n") (if (not (looking-at (concat "^\\(" m3::com-start-re "\\|" m3::part-starters "\\|\\bEND\\b\\)"))) (m3::backward-to-last-part-begin)) (cond ((looking-at m3::com-start-re) (m3::skip-comment-forward (point-max) t) (beginning-of-line 2)) ((looking-at m3::part-starters) (forward-char 1) (let ((start (point))) (if (re-search-forward (concat "^\\(" m3::com-start-re "\\|" m3::part-starters "\\|\\bEND\\b\\)") (point-max) 'move-to-limit) (goto-char (match-beginning 0))) (if (looking-at m3::com-start-re) (forward-char -2)) (m3::backward-to-code start) (beginning-of-line 2))) (t (beep)))) (defun m3::backward-to-non-comment-line-start (part-start) "Sets the point at the first non-whitespace character in a line that contains something other than comments and/or whitespace." (m3::backward-to-code part-start) (beginning-of-line) (m3::skip-whitespace-in-line)) (defun m3::skip-whitespace-in-line () (re-search-forward "[ \t]*")) (defun m3::indent-to (cur-point new-column) "Make current line indentation NEW-COLUMN. If the point is to the left of the first non-blank character, move it to NEW-COLUMN. Otherwise, maintain its relative position. Has the side effect of converting tabs to spaces." (goto-char cur-point) (untabify (save-excursion (beginning-of-line) (point)) (save-excursion (end-of-line) (point))) (let ((cur-column (current-column)) (cur-point (point)) (first-column (save-excursion (beginning-of-line) (re-search-forward " *") (current-column)))) (let ((diff (- new-column first-column))) (cond ((> diff 0) (beginning-of-line) ;; Must do this to make sure the keyword completion marker moves ;; correctly. (let ((d diff)) (while (> d 0) (insert-before-markers " ") (setq d (1- d)))) ) ((< diff 0) (save-excursion (forward-char (- first-column cur-column)) (backward-delete-char-untabify (- diff))))) (cond ((> first-column cur-column) (beginning-of-line) (forward-char new-column)) (t (goto-char (+ cur-point diff))))))) (defun m3::in-comment-or-string () "Returns 'string if point is in an unterminated string, 'comment if in an unterminated comment, otherwise, nil." (save-excursion (beginning-of-line) (let ((cur-point (point)) (state nil)) (save-excursion ;; We assume the lisp-like convention that "top-level defuns," ;; or "parts", are the only things that occur on the left ;; margin (we make an exception for end-comments.) (m3::backward-to-last-part-begin) (while (and (not state) (re-search-forward (concat "\\(" m3::com-start-re "\\|\"\\|'\\)") cur-point t)) (goto-char (match-beginning 0)) (cond ((looking-at m3::com-start-re) (setq state 'comment) (if (m3::skip-comment-forward cur-point t) (setq state nil))) ((looking-at "\"") (setq state 'string) (if (re-search-forward "[^\\\\]\"" cur-point t) (setq state nil))) ((looking-at "'") (setq state 'string) (if (re-search-forward "[^\\\\]'" cur-point t) (setq state nil))))) state)))) (defun m3::backward-to-last-part-begin () ;;; (beginning-of-line nil) ;;; (message "search-start") (sit-for 2) (let ((search-start (point))) (if (re-search-backward (concat "^\\(" m3::com-start-re "\\|" m3::part-starters "\\|\\bEND\\b\\)") (point-min) t) (progn (goto-char (match-beginning 0)) (when (looking-at "\\bEND\\b") (m3::end-of-ender (point-max)) (forward-line 1) (beginning-of-line 1)) ;;; (message "prev") (sit-for 2) ) (goto-char (point-min))) (let ((last-found (point))) (forward-char 1) (if (re-search-forward (concat "^\\(" m3::com-start-re "\\|" m3::part-starters "\\|\\bEND\\b\\)") (point-max) t) (progn (goto-char (match-beginning 0)) (when (looking-at "\\bEND\\b") (m3::end-of-ender (point-max)) (forward-line 1) (beginning-of-line 1)) ;;; (message "after-prev") (sit-for 2) ) (goto-char (point-max))) (if (<= search-start (point)) (goto-char last-found)))) ;;; (message "part-start") (sit-for 2) ) (defun m3::beginning-of-defun (n) "Moves backward to the start of the current 'defun', or top-level syntactic unit. With a prefix argument, does that N times." (interactive "p") (while (and (> n 0) (> (point) (point-min))) (forward-char -1) (m3::backward-to-last-part-begin) (setq n (- n 1)))) (defun m3::forward-to-code (max-point) "Sets the point at the first non-comment, non-whitespace character following the current point, else at max-point." ;;; (message "m3::forward-to-code (1)") (sit-for 2) (let ((continue t)) (while continue ;;; (message "m3::forward-to-code (1.5)") (sit-for 2) (setq continue (and (re-search-forward "[^ \t\n]" max-point 'move-to-limit) (progn (goto-char (match-beginning 0)) ;;; (message "m3::forward-to-code (2)") (sit-for 2) (and (looking-at m3::com-start-re) (m3::skip-comment-forward max-point t)))))))) (defun m3::backward-to-code (min-point) "Sets the point at the first non-comment, non-whitespace character before the current point, else at end-of-file" (let ((continue t)) (while continue (if (re-search-backward "[^ \t\n][ \t\n]*" min-point t) (goto-char (match-beginning 0)) (goto-char min-point)) (setq continue (and (save-excursion (and (> (point) 1) (progn (forward-char -1) (looking-at m3::com-end-re)))) (progn (forward-char 1) (m3::skip-comment-backward min-point t))))) t)) (defun m3::re-search-forward (re max-point fail) "Assumes we're not in a comment or a string. Puts point at the start of the first occurence of RE that is not in a comment or string, if such an occurence occurs before MAX-POINT, and returns non-nil. Otherwise, returns nil and leaves point unaffected. Results are undefined if RE matches any comment starter." (let ((continue t) (save-point (point)) (res nil)) (while continue (setq res (re-search-forward (concat "\\(" m3::com-start-re "\\|\"\\|" re "\\)") max-point fail)) (goto-char (match-beginning 0)) (cond (res (cond ((looking-at m3::com-start-re) (m3::skip-comment-forward max-point fail)) ((looking-at "\"") (forward-char -1) (re-search-forward "[^\\]\"" max-point 'move-to-point) (goto-char (match-end 0))) (t (setq continue nil)))) (t (setq continue nil) (if (and (eq fail t) (not res)) (goto-char save-point))))) res)) (defun m3::re-search-backward (re min-point fail) "Assumes we're not in a comment. Puts point the start of the first previous occurence of RE that is not in a comment, if such an occurence occurs before MIN-POINT, and returns non-nil. FAIL is interpreted as is third argument to re-search. Results are undefined if RE matches any comment starter." (let ((continue t) (save-point (point)) (res nil)) (while continue (setq res (re-search-backward (concat "\\(" m3::com-end-re "\\|\"\\|" re "\\)") min-point fail)) (cond (res (cond ((looking-at m3::com-end-re) (forward-char 2) (m3::skip-comment-backward min-point fail)) ((looking-at "\"") (let ((quote-continue t)) (while quote-continue ;;; (message "m3::re-search-backward (1)") (sit-for 2) (if (re-search-backward "\"" min-point 'move-to-point) (goto-char (match-beginning 0))) ;;; (message "m3::re-search-backward (2)") (sit-for 2) (cond ((or (= (point) min-point) (save-excursion (forward-char -1) (not (looking-at "\\\\")))) (setq quote-continue nil))) ;;; (message "m3::re-search-backward (3)") (sit-for 2) ))) (t (setq continue nil)))) (t (setq continue nil) (if (and (eq fail t) (not res)) (goto-char save-point))))) res)) (defun m3::skip-comment-forward (max-point fail) "Requires that point is at the start of a comment. If that comment is terminated before MAX-POINT, return t and leaves point after end of the comment. Otherwise, if fail is 't, returns returns nil and leaves the point unchanged; if fail is nil raises an errer; if fail is not t or nil, returns nil and leaves the point at max-point or (point-max), whichever is smaller." (if (not (looking-at m3::com-start-re)) (error "m3::skip-comment-forward should only be called when looking at comment-starter")) (forward-char 2) (let ((save-point (point)) (continue t) res) (while continue ;;; (message "m3::comment-forward (0.5)") (sit-for 2) (setq res (re-search-forward m3::com-start-or-end-re max-point fail)) (cond (res ;;; (message "m3::comment-forward (1)") (sit-for 2) (goto-char (match-beginning 0)) ;;; (message "m3::comment-forward (2)") (sit-for 2) (cond ((looking-at m3::com-start-re) (if (not (m3::skip-comment-forward max-point fail)) (progn (setq res nil) (setq continue nil)))) ((looking-at m3::com-end-re) (goto-char (match-end 0)) (setq continue nil)) (t ;;; (message "m3::comment-forward (4)") (sit-for 2) (goto-char save-point) (setq res nil) (setq continue nil)))) (t ;;; (message "m3::comment-forward (5)") (sit-for 2) (goto-char save-point) (setq res nil) (setq continue nil)))) res)) (defun m3::skip-comment-backward (min-point fail) "Requires that point is at the end of a comment. If that comment is terminated before MIN-POINT, return t and leaves point at the start the comment. Otherwise returns nil and leaves the point in an unspecified position." (forward-char -2) (if (not (looking-at m3::com-end-re)) (error "m3::skip-comment-backward should only be called when looking at comment-ender")) (let ((save-point (point)) (continue t) res) (while continue (setq res (re-search-backward m3::com-start-or-end-re min-point fail)) (cond (res (cond ((looking-at m3::com-end-re) (forward-char 2) (if (not (m3::skip-comment-backward min-point fail)) (progn (setq res nil) (setq continue nil)))) ((looking-at m3::com-start-re) (setq continue nil)) (t (goto-char save-point) (setq res nil) (setq continue nil)))) (t (goto-char save-point) (setq res nil) (setq continue nil)))) res)) ;;; -------- Electric END completion -------- (defun m3::do-electric-end () ;;; (message "m3::do-electric-end") (sit-for 2) (let ((start-point (point)) (case-fold-search nil)) (cond ((and (save-excursion (end-of-line) (forward-word -1) ;;; (progn (message "m3::do-electric-end 1.2") (sit-for 2) t) (and (looking-at "\\bEND\\b") (or (save-excursion (beginning-of-line) (looking-at "[ \t]*\\bEND\\b[ \t]*$")) (progn (forward-word 1) (= (point) start-point))))) (or m3::electric-end m3::blink-end-matchers)) ;;; (progn (message "m3::do-electric-end 1.5") (sit-for 2) t) (let ((insert-point (save-excursion (end-of-line) (forward-word -1) (forward-word 1) (point))) (insert-string)) ;;; (progn (message "m3::do-electric-end 2") (sit-for 2) t) (end-of-line) (forward-word -1) (save-excursion (and (m3::backward-to-end-match (point-min)) (if m3::blink-end-matchers (sit-for 1) t) ;;; (progn (message "m3::do-electric-end 3") (sit-for 1) t) (progn (cond ;; Do nothing if we're not supposed to... ((not m3::electric-end)) ;; If it's a begin, what is it the begin of? ((looking-at "BEGIN") (setq insert-string (save-excursion (m3::backward-to-BEGIN-owner))) ) ((looking-at "INTERFACE\\|MODULE") (forward-word 2) (setq insert-string (concat (buffer-substring (save-excursion (forward-word -1) (point)) (point)) "."))) ;; Otherwise, m3::electric-end must be 'all. ((eq m3::electric-end 'all) ;;; (progn (message "m3::do-electric-end non-BEGIN") (sit-for 2) t) (setq insert-string (concat "(* " (buffer-substring (point) (save-excursion (forward-word 1) (point))) " *)"))))))) (cond (insert-string (progn (goto-char insert-point) ;; If we completed an END and then added something, include ;; the something in the completion... (if (and (marker-position m3::cur-keyword-completion-start) (= insert-point (+ m3::cur-keyword-completion-start m3::cur-keyword-completion-len))) (setq m3::cur-keyword-completion-len (+ m3::cur-keyword-completion-len 1 (length insert-string)))) (insert " " insert-string))) (t (goto-char start-point)))))))) (defun m3::backward-to-BEGIN-owner () "Assumes looking-at BEGIN. If this begin is a module main body or the body of a procedure, moves backward to the MODULE or PROCEDURE keyword of that module or procedure, and returns the name of the MODULE or procedure. If neither of these are true, does not move point, and returns the string BEGIN if m3::electric-end is 'all, and nil otherwise." ;;; (message "begin-owner") (sit-for 2) (let ((insert-string nil) (orig-point (point)) (new-point (point))) (save-excursion (cond ;; If it's on the left margin, it must be a module. ((looking-at "^BEGIN") (goto-char (point-min)) (and (re-search-forward "MODULE\\|INTERFACE" (point-max) t) (progn (goto-char (match-beginning 0)) (setq new-point (point)) (forward-word 2) (setq insert-string (concat (buffer-substring (save-excursion (forward-word -1) (point)) (point)) "."))))) ;; Is it the body of a procedure? ((let ((continue t)) (while continue (m3::re-search-backward "BEGIN\\|PROCEDURE\\|\\bEND\\b" (point-min) t) (cond ((looking-at "\\bEND\\b") (m3::backward-to-end-match (point-min)) (cond ((looking-at "BEGIN") (m3::re-search-backward "BEGIN\\|PROCEDURE" (point-min) t) (if (looking-at "BEGIN") (forward-word 1))))) (t (setq continue nil)))) (and (looking-at "PROCEDURE") (progn ;;; (message "m3::BEGIN-owner PROC 2") (sit-for 2) (setq new-point (point)) (forward-word 2) (setq insert-string (concat (buffer-substring (save-excursion (forward-word -1) (point)) (point)) ";")))))) ;; Otherwise, it is just a random BEGIN, so ;; m3::electric-end must be 'all. ((eq m3::electric-end 'all) (setq insert-string "(* BEGIN *)")))) (goto-char new-point) insert-string)) ;;; -------- PSEUDO ABBREV MODE -------- (defun m3::toggle-abbrev () "Toggle the flag enabling/disabling Modula 3 pseudo abbrev mode." (interactive) (setq m3::abbrev-enabled (not m3::abbrev-enabled)) (message "M3 abbrev-enabled is now %s." m3::abbrev-enabled)) (defun m3::prev-word () "returns last word in buffer." (buffer-substring (point) (save-excursion (backward-word 1) (point)))) (defun m3::is-abbrev (keyword word) "Returns non-nil if WORD is abbreviation of given KEYWORD." (if (> (length word) (length keyword)) () (string-equal (substring keyword 0 (length word)) (upcase word)))) (defun m3::is-prefix (word prefix &optional no-upper) "returns non-nil if PREFIX is a (non-proper) prefix of WORD." (let ((uword (if no-upper word (upcase word))) (uprefix (if no-upper prefix (upcase prefix)))) (if (> (length prefix) (length word)) nil (string-equal (substring uword 0 (length prefix)) uprefix)))) (defun m3::if-abbrev-kill-prev (keyword word) "checks if word is abbreviation of keyword; if so deletes last word in buffer." (if (not (m3::is-abbrev keyword word)) () (forward-word -1) (delete-region (point) (save-excursion (forward-word 1) (point))) t)) (defun m3::complete-abbrev () "call appropriate m3::function depending on value of last word in buffer." (let ((pw (m3::prev-word))) ;; Must split this in two because it's so big (or else elisp ;; can't handle it.) (if m3::abbrev-enabled (m3::complete-abbrev-work pw)))) ;;; Here is the data structure we use to decide what keywords are ;;; appropriate completions of a prefix in the current context, and ;;; how we should order them. ;;; ;;; This alist associates with each keyword: ;;; ( ) ;;; ;;; is a score for breaking ties. Smaller numbers are ;;; preferred to higher. ;;; is a list of properties of the keyword. ;;; Properties include: ;;; left-margin status: It is assumed that a keyword cannot ;;; appear at the left-margin unless it has one of the ;;; properties 'lm-ok or 'lm-only, which indicate that it can ;;; or must appear at the left margin, respectively. ;;; line-starter status: It is assumed that a keyword cannot ;;; appear after an ssl-introducer unless it has one of the ;;; properties 'ls-ok or 'ls-only, which indicate that it can ;;; or must appear after an ssl-introducer, respectively. ;;; , if non-nil, is a function that must return non-nil for the ;;; completion to be legal (defconst m3::keyword-completions '(("ABS" . (3 ())) ("ADDRESS" . (5 ())) ("ADR" . (6 ())) ("ADRSIZE" . (7 ())) ("AND" . (2 ())) ("ANY" . (1 () (lambda (on-lm starts-ssl) (m3::keyword-before-ssl-introducer-p "RAISES")))) ("ARRAY" . (4 (ls-ok) (lambda (on-lm starts-ssl) (or (not starts-ssl) (save-excursion (forward-word -2) (looking-at "OF")))))) ("BEGIN" . (1 (lm-ok ls-ok) (lambda (on-lm starts-ssl) (save-excursion (forward-word -1) (if (not starts-ssl) (m3::after-procedure-introducer (point-min)) t))))) ("BITS" . (6 ())) ("BITSIZE" . (7 ())) ("BOOLEAN" . (3 ())) ("BRANDED" . (4 ())) ("BY" . (2 () (lambda (on-lm starts-ssl) (m3::keyword-before-ssl-introducer-p "FOR")))) ("BYTESIZE" . (5 ())) ("CARDINAL" . (4 (ls-of))) ("CASE" . (3 (ls-only))) ("CEILING" . (5 ())) ("CHAR" . (2 (ls-of))) ("CONST" . (1 (lm-ok ls-ok))) ("DEC" . (2 (ls-only))) ("DISPOSE" . (4 (ls-only))) ("DIV" . (3 ())) ("DO" . (1 () (lambda (on-lm starts-ssl) (save-excursion (forward-word -1) (or (m3::keyword-before-ssl-introducer-p "WHILE") (m3::keyword-before-ssl-introducer-p "WITH") (m3::keyword-before-ssl-introducer-p "FOR") (m3::keyword-before-ssl-introducer-p "LOCK")))))) ("ELSE" . (2 (ls-ok) (lambda (on-lm starts-ssl) (or (m3::end-matcher-is-p "IF") (m3::end-matcher-is-p "TRY") (m3::end-matcher-is-p "\\bCASE") (m3::end-matcher-is-p "\\bTYPECASE"))))) ("ELSIF" . (3 (ls-ok) (lambda (on-lm starts-ssl) (m3::end-matcher-is-p "IF")))) ("END" . (1 (lm-ok ls-ok))) ("EVAL" . (7 (ls-only))) ("EXCEPT" . (6 (ls-ok) (lambda (on-lm starts-ssl) (m3::end-matcher-is-p "TRY")))) ("EXCEPTION" . (5 (lm-only ls-ok))) ("EXIT" . (8 (ls-only))) ("EXPORTS" . (4 () (lambda (on-lm starts-ssl) (save-excursion ;; One for prefix of EXPORTS one for module name, ;; one for MODULE. (forward-word -3) (looking-at "MODULE"))))) ("FALSE" . (4 ())) ("FINALLY" . (3 (ls-ok) (lambda (on-lm starts-ssl) (m3::end-matcher-is-p "TRY")))) ("FIRST" . (5 ())) ("FLOAT" . (6 ())) ("FLOOR" . (7 ())) ("FOR" . (2 (ls-ok))) ("FROM" . (1 (lm-only ls-ok))) ("GENERIC" . (1 (lm-only))) ("IMPORT" . (2 (lm-ok ls-ok) (lambda (on-lm starts-ssl) (or on-lm (save-excursion (forward-word -3) (looking-at "\\bFROM\\b")))))) ("IF" . (3 (ls-only) (lambda (on-lm starts-ssl) (or (not starts-ssl) (save-excursion (forward-word -3) (not (looking-at "\\(\\bARRAY\\|\bSET\\)[ \t]+OF"))))))) ("IN" . (7 ())) ("INC" . (4 (ls-only) (lambda (on-lm starts-ssl) (or (not starts-ssl) (save-excursion (forward-word -3) (not (looking-at "\\(\\bARRAY\\|\bSET\\)[ \t]+OF"))))))) ("INTEGER" . (5 (ls-ok) (lambda (on-lm starts-ssl) (or (not starts-ssl) (save-excursion (forward-word -2) (looking-at "OF")))))) ("INTERFACE" . (1 (lm-ok) (lambda (on-lm starts-ssl) (save-excursion (or on-lm (progn (forward-word -2) (and (m3::at-left-margin-p) (looking-at "GENERIC\\|UNSAFE")))))))) ("ISTYPE" . (7 ())) ("LAST" . (3 ())) ("LOCK" . (1 (ls-only) (lambda (on-lm starts-ssl) (save-excursion (forward-word -2) (not (looking-at "OF")))))) ("LOOP" . (2 (ls-only) (lambda (on-lm starts-ssl) (save-excursion (forward-word -2) (not (looking-at "OF")))))) ("LONGFLOAT" . (4 ())) ("LONGREAL" . (5 (ls-of))) ("LOOPHOLE" . (6 ())) ("MAX" . (5 ())) ("METHODS" . (2 (ls-only))) ("MIN" . (4 ())) ("MOD" . (3 ())) ("MODULE" . (1 (lm-ok) (lambda (on-lm starts-ssl) (save-excursion (forward-word -1) (or (m3::at-left-margin-p) (progn (forward-word -1) (and (m3::at-left-margin-p) (looking-at "GENERIC\\|UNSAFE")))))))) ("NARROW" . (1 ())) ("NEW" . (2 ())) ("NIL" . (3 ())) ("NULL" . (6 ())) ("NUMBER" . (5 ())) ("NOT" . (4 ())) ("OBJECT" . (2 () (lambda (on-lm starts-ssl) (save-excursion (m3::re-search-backward m3::part-starters (point-min) t) (looking-at "TYPE\\|REVEAL"))))) ("OF" . (1 () (lambda (on-lm starts-ssl) (or (m3::keyword-before-ssl-introducer-p "\\bCASE\\|\\bTYPECASE") (m3::keyword-before-ssl-introducer-p "\\bARRAY\\|SET\\b"))))) ("OR" . (4 ())) ("ORD" . (5 ())) ("OVERRIDES" . (3 (ls-only))) ("PROCEDURE" . (1 (lm-ok ls-ok))) ("RAISE" . (5 (ls-only))) ("RAISES" . (3 () m3::raises-ok)) ("READONLY" . (4 (ls-ok) (lambda (on-lm starts-ssl) (m3::in-arg-list 0)))) ("REAL" . (9 (ls-of))) ("RECORD" . (6 ())) ("REF" . (7 ())) ("REFANY" . (8 ())) ("REPEAT" . (10 (ls-only))) ("RETURN" . (2 (ls-only))) ("REVEAL" . (1 (lm-only ls-ok))) ("ROOT" . (11 ())) ("ROUND" . (12 ())) ("SET" . (1 ())) ("SUBARRAY" . (2 (ls-ok))) ("TEXT" . (6 (ls-of))) ("THEN" . (1 () (lambda (on-lm starts-ssl) (or (m3::keyword-before-ssl-introducer-p "\\bIF") (m3::keyword-before-ssl-introducer-p "\\bELSIF"))))) ("TO" . (2 () (lambda (on-lm starts-ssl) (m3::keyword-before-ssl-introducer-p "\\bFOR")))) ("TRUE" . (8 ())) ("TRUNC" . (9 ())) ("TRY" . (3 (ls-only))) ("TYPE" . (4 (lm-ok ls-ok))) ("TYPECASE" . (5 (ls-only))) ("TYPECODE" . (7 ())) ("UNSAFE" . (1 (lm-only))) ("UNTIL" . (2 (ls-ok))) ("UNTRACED" . (3 ())) ("VAL" . (2 () (lambda (on-lm starts-ssl) (and (not (save-excursion (forward-word -1) (m3::after-procedure-introducer 0))) (not (m3::in-arg-list 0)))))) ("VALUE" . (3 () (lambda (on-lm starts-ssl) (not (save-excursion (forward-word -1) (m3::after-procedure-introducer 0)))))) ("VAR" . (1 (lm-ok ls-ok) (lambda (on-lm starts-ssl) (or on-lm starts-ssl (save-excursion (forward-word -1) (m3::after-procedure-introducer 0)) (m3::in-arg-list 0))))) ("WHILE" . (1 (ls-only))) ("WITH" . (2 (ls-only))))) (defun m3::at-left-margin-p () (eq (current-column) 0)) (defun m3::keyword-before-ssl-introducer-p (keyword) "Returns non-nil if KEYWORD occurs before an ssl-introducer (other than KEYWORD), looking backward." (save-excursion (m3::re-search-backward (concat "\\(;\\|\\bEND\\b\\|" m3::keyword-endable-ssl-introducers "\\|" keyword "\\)") (point-min) 't) (looking-at keyword))) (defun m3::end-matcher-is-p (keyword) "Returns non-nil if the keyword that would match an END inserted at point is KEYWORD." (save-excursion (m3::backward-to-end-match (point-min)) (looking-at keyword))) (defun m3::raises-ok (on-lm starts-ssl) (save-excursion (forward-word -1) (let ((save-point (point))) (and (m3::re-search-backward "[^*])" 0 t) (progn (forward-char 1) (and (m3::in-arg-list 0) (progn (forward-char 1) (let ((retval-pat (concat "[ \t\n]*:[ \t\n]*" m3::poss-qual-ident-re))) (if (looking-at retval-pat) (progn (re-search-forward retval-pat) (goto-char (match-end 0)))) (m3::forward-to-code (point-max)) (= (point) save-point))))))))) (defun m3::complete-abbrev-work (pw) ;;; (message "In m3::polite-abbrev") (sit-for 2) (let ((case-fold-search nil)) (cond ;; First, if the start of the current keyword is the same as the ;; start of the last keyword we completed, and the user hasn't ;; appended any characters, and m3::cur-keyword-completions is non-nil, ;; try the next completion in the list. ((and ;;; (progn (message "In m3::polite-abbrev (x1)") (sit-for 2) t) (marker-position m3::cur-keyword-completion-start) ;;; (progn (message "In m3::polite-abbrev (x2)") (sit-for 2) t) (> (point) m3::cur-keyword-completion-len) (= m3::cur-keyword-completion-start (save-excursion (forward-char (- m3::cur-keyword-completion-len)) (point))) ;;; (progn (message "In m3::polite-abbrev (x3)") (sit-for 2) t) m3::cur-keyword-completions (string-equal (buffer-substring (marker-position m3::cur-keyword-completion-start) (point)) (car m3::cur-keyword-completions))) (let ((cur-completion (car m3::cur-keyword-completions))) (setq m3::cur-keyword-completions (append (cdr m3::cur-keyword-completions) (list cur-completion))) ;;; (progn (message "In m3::polite-abbrev (xx1)") (sit-for 2) t) (forward-word -1) (delete-region m3::cur-keyword-completion-start (+ m3::cur-keyword-completion-start m3::cur-keyword-completion-len)) ;;; (progn (message "In m3::polite-abbrev (xx2)") (sit-for 2) t) (insert (car m3::cur-keyword-completions)) (setq m3::cur-keyword-completion-len (- (point) m3::cur-keyword-completion-start)) (if (> (length m3::cur-keyword-completions) 1) (message "Other matches: %s" (mapconcat '(lambda (x) x) (cdr m3::cur-keyword-completions) ", "))))) ;; Otherwise, form the list of ( . ) pairs such ;; that pw is a prefix of , is the score ;; associated with in m3::keyword-completions, and the ;; conditions in m3::keyword-completions are met. (t ;;; (message "In m3::polite-abbrev (t)") (sit-for 2) (let ((keyword-list m3::keyword-completions) matches (on-lm (and (= (save-excursion (forward-word -1) (current-column)) 0) (let ((continue t) (res nil)) (save-excursion ;;; (message "Checking on-lm, about to enter loop") (sit-for 2) (while continue (setq continue nil) ;;; (message "Checking on-lm, before search") (sit-for 2) (m3::re-search-backward (concat m3::part-starters "\\|" m3::end-matchers "\\|" "\\bEND\\b") (point-min) 'move-to-limit) ;;; (message "Checking on-lm, after search") (sit-for 2) (cond ((looking-at "\\bEND\\b") (m3::backward-to-end-match (point-min)) (if (and (looking-at "BEGIN") (not (looking-at "^BEGIN"))) (progn ;;; (message "Checking doing BEGIN adjustment") ;;; (sit-for 2) (m3::re-search-backward "\\(^PROCEDURE\\|^[ \t]+BEGIN\\)" (point-min) 'move-to-limit) (goto-char (match-end 0)))) (setq continue t)) ((looking-at (concat "^\\(" m3::part-starters "\\)")) (setq res t)) ((looking-at "IMPORT") (save-excursion (forward-word -2) ;;; (message "Doing FROM ... IMPORT special") (sit-for 2) (if (looking-at "^FROM") (setq res t)))) ((= (point) (point-min)) (setq res t))))) ;;; (message "After loop, res is %s" res) (sit-for 2) (and res (save-excursion (forward-word -1) (m3::backward-to-code (point-min)) (or (= (point) (point-min)) ;;; (progn (message "xxx") (sit-for 2) nil) (looking-at ";"))))))) (starts-ssl (let ((first-char (save-excursion (forward-word -1) (point)))) (save-excursion (forward-word -1) (m3::re-search-backward (concat "\\(;\\|\\bEND\\b\\|" m3::keyword-endable-ssl-introducers "\\)") (point-min) 'move-to-limit) (re-search-forward (concat "\\(;\\|\\bEND\\b\\|" m3::keyword-endable-ssl-introducers "\\)") first-char t) (goto-char (match-end 0)) ;;; (message "In m3::polite-abbrev (zz1)") (sit-for 2) (m3::forward-to-code (point-max)) (= (point) first-char)))) (after-of (save-excursion (forward-word -2) (looking-at "OF")))) ;;; (message ;;; "In m3::polite-abbrev, on-lm = %s, starts-ssl = %s, after-of = %s." ;;; on-lm starts-ssl after-of) ;;; (sit-for 2) (while keyword-list (let* ((entry (car keyword-list)) (kw (car entry))) ;;; (message "In m3::polite-abbrev kw = %s" kw) (sit-for 2) ;;; (message "Foo") (sit-for 2) (if (m3::is-prefix kw pw) (let* ((rest (cdr entry)) (score (car rest)) (props (car (cdr rest))) (pred (car (cdr (cdr rest))))) ;;; (message "In m3::polite-abbrev, found kw = %s" kw) (sit-for 1 ) (let ((lm-status (cond ((and (memq 'lm-ok props) (memq 'lm-only props)) (error "Bad prop-list in m3::keyword-completions.")) ((memq 'lm-ok props) 'lm-ok) ((memq 'lm-only props) 'lm-only) (t 'lm-not))) (ls-status (cond ((let ((n 0)) (if (memq 'ls-ok props) (setq n (+ n 1))) (if (memq 'ls-only props) (setq n (+ n 1))) (if (memq 'ls-of props) (setq n (+ n 1))) (> n 1)) (error "Bad prop-list in m3::keyword-completions.")) ((memq 'ls-ok props) 'ls-ok) ((memq 'ls-only props) 'ls-only) ((memq 'ls-of props) 'ls-of) (t 'ls-not)))) ;;; (message ;;; "In m3::polite-abbrev, (2) lm-status = %s ls-status = %s" ;;; lm-status ls-status) ;;; (sit-for 2) (and (or (eq lm-status 'lm-ok) (cond ((eq lm-status 'lm-only) on-lm) ((eq lm-status 'lm-not) (not on-lm)))) (or ;;; (progn (message "In m3::polite-abbrev, (3.2)") ;;; (sit-for 2) nil) (and (eq ls-status 'ls-ok) (not after-of)) (cond ((eq ls-status 'ls-only) (and starts-ssl (not after-of)) ) ((eq ls-status 'ls-not) (not starts-ssl)) ((eq ls-status 'ls-of) (or (not starts-ssl) after-of)))) (or ;;; (progn (message "In m3::polite-abbrev, (5), pred = %s" pred ) ;;; (sit-for 2) nil) (not pred) ;;; (progn (message "In m3::polite-abbrev, (5)") ;;; (sit-for 2) nil) (funcall pred on-lm starts-ssl)) ;;; (message "In m3::polite abbrev, adding %s to matches" kw) ;;; (sit-for 2) (setq matches (cons (cons kw score) matches))))))) (setq keyword-list (cdr keyword-list))) ;;; (message "In m3::polite-abbrev (after matches): %s" matches) (sit-for 4) ;; If there are any matches, do a completion (and matches (progn ;; Now sort matches according to score. ;;; (message "In m3::polite-abbrev, (10)") (sit-for 2) (setq matches (sort matches '(lambda (e1 e2) (< (cdr e1) (cdr e2))))) ;; And strip off the scores from the result. ;;; (message "In m3::polite-abbrev, (11)") (sit-for 2) (setq matches (mapcar'(lambda (e) (car e)) matches)) ;;; (message "In m3::polite-abbrev, (12)") (sit-for 2) (setq m3::cur-keyword-completions matches) (let ((first-match (car matches))) (forward-word -1) (delete-region (point) (save-excursion (forward-word 1) (point))) ;;; (message "In m3::polite-abbrev, (13)") (sit-for 2) (set-marker m3::cur-keyword-completion-start (point)) (insert first-match) (setq m3::cur-keyword-completion-len (- (point) m3::cur-keyword-completion-start)) (if (> (length matches) 1) (message "Other matches: %s" (mapconcat '(lambda (x) x) (cdr matches) ", "))))) )))))) ;;;====================================================================== (defun m3::is-letter (ch) "checks if argument is a letter." (and (>= (upcase ch) ?A) (<= (upcase ch) ?Z))) (defun m3::abbrev-and-or-indent () "If preceding char in buffer is letter, tries to expand abbrev. Otherwise, indents the current line." (interactive) ;;; (message "Foo1") (sit-for 2) (if (and m3::abbrev-enabled (or (m3::is-letter (preceding-char)) (save-excursion (and (> (point) 2) (progn (forward-char -2) (and (looking-at "*)") (progn (forward-word -1) (forward-char -3) (looking-at "(*")) (progn (forward-word -1) (looking-at "\\bEND\\b")))))) (save-excursion (and (> (point) 2) (progn (forward-char -1) (and (looking-at ";\\|.") (progn (forward-word -2) (looking-at "\\bEND\\b"))))))) (or (eq (point) (point-max)) (eq (following-char) ?\ ) (eq (following-char) ?\t) (eq (following-char) ?\n))) (progn (m3::complete-abbrev) (m3::indent-line)) (m3::indent-line))) ;;; ----------------- M3PP pretty printing ------------------ (defvar m3::pp-options '("-ZZ") "Command line options that should be passed to m3pp when it is started up.") (defvar m3::pp-modunit "\002") (defvar m3::pp-defunit "\005") (defvar m3::pp-endunit "\001") (defvar m3::pp-process nil) (defvar m3::pp-in-progress nil) (defvar m3::pp-unit-boundary (concat "^[ \t]*\nCONST\\|" "^[ \t]*\nTYPE\\|" "^[ \t]*\nVAR\\|" "^[ \t]*\nPROCEDURE\\|" "^[ \t]*\nEXCEPTION\\|" "^[ \t]*\n<\*EXTERNAL\*>|" "^[ \t]*\n<\*INLINE\*>|" "^[ \t]*\nMODULE\\|" "^[ \t]*\nINTERFACE\\|" "^[ \t]*\nIMPORT\\|" "^[ \t]*\nBEGIN")) (defun m3::pp-startup () (if (not (and m3::pp-process (process-status (process-name m3::pp-process)))) (save-excursion (get-buffer-create "m3::pp") (set-buffer "m3::pp") (erase-buffer) (setq m3::pp-process (apply 'start-process "m3::pp" nil "m3pp" m3::pp-options)) (process-kill-without-query m3::pp-process) (set-process-filter m3::pp-process 'm3::pp-filter) (process-send-string m3::pp-process (concat m3::pp-modunit m3::pp-endunit "\n")) (accept-process-output m3::pp-process)))) (defun m3::pp-buffer () (interactive) (m3::pp-region-safe (point-min) (point-max) (point))) (defun m3::pp-unit () "Pretty prints the 'unit' containing the cursor. A unit starts with a blank line followed by CONST, TYPE, VAR, PROCEDURE, EXCEPTION, IMPORT, FROM, MODULE, or BEGIN, and it extends to the start of the next unit. If there is no such unit around the cursor, the entire file is pretty printed." (interactive) (let ((return-point (point)) start end) (save-excursion (if (not (looking-at (concat "^\\(" m3::part-starters "\\)"))) (m3::beginning-of-defun 1)) (setq start (point)) ;;; (message "Unit start...") (sit-for 2) (m3::end-of-defun 1) ;;; (message "Unit end.") (sit-for 2) (setq end (point))) (m3::pp-region-safe start end return-point))) (defun m3::pp-region () "Pretty prints the region. The region should consist of zero or more declarations, definitions, import statements, or modules." (interactive) (m3::pp-region-safe (min (point) (mark)) (max (point) (mark)) (point))) (defun m3::pp-region-safe (start end return-point) ;;; (message "m3::pp-region-safe (1) rt = %d" return-point) (sit-for 2) (let ((m3pp-type nil) (m3pp-start nil)) (m3::pp-startup) ;;; (message "m3::pp-region-safe (2)") (sit-for 2) (save-excursion (goto-char (point-min)) (if (search-forward m3::pp-endunit (point-max) t) (error "m3pp: file mustn't contain ^A")) (get-buffer-create "m3::pp-output") (set-buffer "m3::pp-output") (erase-buffer)) ;;; (message "m3::pp-region-safe (3)") (sit-for 2) (if (buffer-file-name) (let* ((len (length (buffer-file-name))) (tail (substring (buffer-file-name) (- len 3) len))) (cond ((or (string-equal tail ".m3") (string-equal tail ".mg")) (setq m3pp-type m3::pp-modunit)) ((or (string-equal tail ".i3") (string-equal tail ".ig")) (setq m3pp-type m3::pp-defunit)) (t (error "m3pp: pretty-print only .m3, .mg, .i3, or .ig files")))) (save-excursion (goto-char (point-min)) (m3::forward-to-code (point-max)) (cond ((looking-at "INTERFACE") (setq m3pp-type m3::pp-defunit)) ((looking-at "MODULE") (setq m3pp-type m3::pp-modunit)) ((looking-at "\\(GENERIC\\|UNSAFE\\)") (forward-word 1) (m3::forward-to-code (point-max)) (cond ((looking-at "INTERFACE") (setq m3pp-type m3::pp-defunit)) ((looking-at "MODULE") (setq m3pp-type m3::pp-modunit)) (t (error "m3pp: buffer is not an interface or module."))))))) (message "m3pp: working ...") (setq m3::pp-in-progress t) (cond ;; Empirically, this number seems to work; lengths over 8000 seem ;; to get hung up somewhere when using process-send-string. ((> (- end start) 4000) (let* ((num (mod (random) 1000)) (fn-in (concat "/tmp/" (getenv "USER") "-m3pp-in-" (format "%d" num))) (fn-out (concat "/tmp/" (getenv "USER") "-m3pp-out-" (format "%d" num)))) ;;; (message "random-filename is %s" fn) (sit-for 1) (goto-char end) (insert "") (goto-char start) (insert "") (write-region start end fn-in nil 'no-msg) (goto-char start) (delete-char 1) (goto-char end) (delete-char 1) (let ((cur-buffer (current-buffer))) (get-buffer-create "m3::pp-output") (set-buffer "m3::pp-output") (shell-command (concat "m3pp -ZZG < " fn-in " > " fn-out)) (insert-file fn-out) (set-buffer cur-buffer)))) (t (process-send-string m3::pp-process (concat m3pp-type (buffer-substring start end) m3::pp-endunit "\n")) (while m3::pp-in-progress (accept-process-output m3::pp-process)))) ;;; (setq m3::pp-start (point-marker)) (kill-region start end) (insert-buffer "m3::pp-output") (save-excursion (set-buffer "m3::pp-output") (if (re-search-backward "(\\* SYNTAX ERROR " (point-min) t) (progn (beep) (message "m3pp: syntax error")) (progn ;else (message "m3pp: done")))) (goto-char return-point))) ;; (if (not (pos-visible-in-window-p)) ;; (let ((dotval (+ (point-marker)))) ;; (line-to-bottom-of-window) ;; (goto-char dotval))))) (defun m3::pp-filter (&process &str) (save-excursion (get-buffer-create "m3::pp-output") (set-buffer "m3::pp-output") (goto-char (point-max)) (insert &str) (if (search-backward m3::pp-endunit (point-min) t) (progn (delete-char 2) (setq m3::pp-in-progress nil))))) (defun m3::pp-find-format-unit () ;;; (message "Beginning of format region") (sit-for 2) (set-mark (point)) (m3::end-of-defun 1) ;;; (message "End of format region") (sit-for 2) (exchange-point-and-mark) nil) ;;;----------- SRC-specific (but adaptable) stuff ---- (defvar m3::path-alist nil "Alist with entries of the form: If DIRECTORY has an entry on this list, its m3makefile has been processed to yield the path PATH-AS-DIR-LIST at a time in the past when the modification time of the m3makefile was M3MAKEFILE-MOD-DATE. If the m3makefile has not been modified since then, it is safe to use the cached path.") (defvar m3::path-default nil "The search path corresponding to the 'be' directory.") (defvar m3::path-default-time nil "The modification date of the default m3path file when it was last read.") (defvar m3::derived-dir "DS" "Subdirectories into which emacs assumes m3build will put derived files.") (defun m3::read-path () "Assumes that the current directory is a (possibly non-proper) subdirectory of the src directory of the current package, that that src directory contains the m3makefile for the package, and that the package contains one subdirectory named src, and it is an immediate subdirectory of the package directory. Constructs and returns the search path associated with that m3makefile, if this m3makefile exists; otherwise returns NIL. May do caching based on the modification time of the m3makefile." ;; First, find the src directory. (let ((old-dd default-directory)) (when (not (m3::find-main-src-dir)) (setq default-directory old-dd) (error "Unable to find main src directory.")) (let ((entry (assoc default-directory m3::path-alist))) (cond (entry (let ((imp-tab-name (concat "../" m3::derived-dir "/.M3IMPTAB"))) (cond ((file-exists-p imp-tab-name) (let ((mod-time (m3::get-mod-time imp-tab-name))) ;; Do we have this cached? (cond ((let ((cached-date (cadr entry))) (m3::time-le mod-time cached-date)) ;; we got a cache hit that is still valid. (setq default-directory old-dd) (nth 2 entry)) (t ;; Cache entry was invalid. Update it. (m3::update-m3-alist) (setq entry (assoc default-directory m3::path-alist)) (setq default-directory old-dd) (nth 2 entry))))) (t (message "%s file is no longer-present."))))) (t nil))))) (defun m3::find-main-src-dir () "Moves the current directory to the main 'src' directory of the current package, if it can find it. Returns non-nil iff it finds one." (while (and (not (string= (file-name-nondirectory (substring default-directory 0 -1)) "src")) (not (string= default-directory "/"))) (cd "..")) (and (not (string= default-directory "/")) ;; We found the src directory. Make sure. (if (not (string= (file-name-nondirectory (substring default-directory 0 -1)) "src")) (error "INTERNAL") t))) (defun m3::search-for-pkg (off) "Asserts that the current directory has special imports not covered by the default, so we should use parse and use a directory-specific search-path for it. With a prefix-argument, removes search-path entry for current package. " (interactive "P") (let ((old-dd default-directory)) (when (not (m3::find-main-src-dir)) (setq default-directory old-dd) (error "Unable to find main src directory.")) (cond (off (delete-if '(lambda (elem) (string= (car elem) default-directory)) m3::path-alist)) (t (when (not (assoc default-directory m3::path-alist)) (setq m3::path-alist (cons (list default-directory '(0 0) nil) m3::path-alist))))))) (defun m3::update-m3-alist () "m3::path-alist has an out-of-date entry for the current directory. Make that entry valid again. Requires that we're in the main 'src' directory of the current package, and that the appropriate .M3IMPTAB exists." (setq m3::path-alist (delete-if '(lambda (elem) (string= (car elem) default-directory)) m3::path-alist)) ;; Find the .M3IMPTAB for the current directory, if it exists. (let ((imp-tab-name (concat "../" m3::derived-dir "/.M3IMPTAB"))) (if (not (file-exists-p imp-tab-name)) (error "INTERNAL")) (message "Reading %s for search path..." imp-tab-name) (let ((sav-buffer (current-buffer)) (m3path-buffer (create-file-buffer "m3path")) (path nil)) (set-buffer m3path-buffer) (delete-region (point-min) (point-max)) (shell-command-on-region (point-min) (point-max) (concat "grep '^@.*$' " imp-tab-name " | sed -e 's/^@//'") t) (goto-char (point-min)) (while (< (point) (point-max)) (let ((dir (buffer-substring (point) (progn (end-of-line nil) (point))))) (if (> (length dir) 0) (setq path (cons dir path))) (forward-line 1))) (set-buffer sav-buffer) (setq m3::path-alist (cons (list default-directory (m3::get-mod-time imp-tab-name) path) m3::path-alist))))) (defun m3::get-mod-time (fn) "Assumes fn exists; returns modification date as two-element-list." (let ((attrs (file-attributes fn))) (nth 5 attrs))) (defun m3::time-le (t1 t2) "t1 and t2 are times represented as two-element lists of (16 bit) integers. Returns non-NIL iff t1 <= t2." (or (< (car t1) (car t2)) (and (= (car t1) (car t2)) (<= (cadr t1) (cadr t2))))) (defconst m3::be-pkg "/proj/m3/pkg/be/") (defun m3::read-default-path () "Ensures that m3::path-default has an up-to-date value." (let ((fn (concat m3::be-pkg m3::derived-dir "/m3path"))) (cond ((file-exists-p fn) (let ((tm (m3::get-mod-time fn))) (when (or (not m3::path-default-time) (not (m3::time-le tm m3::path-default-time))) (message "Reading default m3path...") (save-excursion (let ((sav-buffer (current-buffer)) (path nil)) (find-file-read-only fn) (goto-char (point-min)) (while (< (point) (point-max)) (let ((dir (buffer-substring (point) (progn (end-of-line nil) (point))))) (if (> (length dir) 0) (setq path (cons dir path))) (forward-line 1))) (let ((m3path-buffer (current-buffer))) (set-buffer sav-buffer) (kill-buffer m3path-buffer) (setq m3::path-default (cons "." path)) (setq m3::path-default-time tm))))))) (t (message "Default m3path file '%s' does not exist..." fn) )))) ;;; stolen from lib-complete, ;;; Author : Mike Williams ;;; Created On : Sat Apr 20 17:47:21 1991 ;;; Last Modified By: Mike Williams ;;; Last Modified On: Tue Jun 18 12:53:08 1991 (defun m3::locate-file (FILE SEARCH-PATH &optional SUFFIX-LIST PRED) "Search for FILE on SEARCH-PATH (list). If optional SUFFIX-LIST is provided, allow file to be followed by one of the suffixes. Optional second argument PRED restricts the number of files which may match. The default is file-exists-p." (if (not SUFFIX-LIST) (setq SUFFIX-LIST '(""))) (if (not PRED) (setq PRED 'file-exists-p)) (if (file-name-absolute-p FILE) (setq SEARCH-PATH '(nil))) (if (equal FILE "") (error "Empty filename")) (let ((filelist (mapcar (function (lambda (ext) (concat FILE ext))) SUFFIX-LIST))) ;; Search SEARCH-PATH for a readable file in filelist (catch 'found (while SEARCH-PATH (let ((filelist filelist)) (while filelist (let* ((expanded (expand-file-name (car filelist) (car SEARCH-PATH))) (filepath (substitute-in-file-name expanded))) (if (funcall PRED filepath) (throw 'found filepath))) (setq filelist (cdr filelist)))) (setq SEARCH-PATH (cdr SEARCH-PATH)))) )) (defvar m3::show-file-other-frame t "If non-nil and using emacs19, files found using m3::show-interface or m3::show-implementation will be displayed on new screens.") (defun m3::show-interface (&optional arg) "Find a Modula-3 interface. If ARG is a string, it is the name of the interface. If ARG is nil, get the name from the text around the point. Otherwise, ARG should be an epoch mouse position and the name is found around that position. If the current directory has an 'm3path' file, reads that to get a search path; otherwise, uses m3::path. Then find the file that contains that interface. Under gnuemacs, or if using epoch and m3::show-interface-other-frame is nil, show the interface in another window of the current screen. If using epoch and m3::show-interface-other-frame is non-nil, show the interface in a new screen of the Modula-3 pool; the screens in that pool are in the class m3::poolclass. The Modula-3 pool is of size m3::poolsize." (interactive) (let ((interface (if (stringp arg) arg (m3::ident-around-point)))) (m3::show-file-work interface 'interface))) (defun m3::show-spec (&optional arg) "Find a Modula-3 spec file." (interactive) (let ((interface (if (stringp arg) arg (m3::ident-around-point)))) (m3::show-file-work interface 'specification))) (defvar m3::trait-path '("." "/udir/horning/TheBook/handbook" "/proj/m3/pkg/lm3-traits/traits" "/udir/kjones/larch/LM3/pkg/TEST") "The list of directories to search for lsl files...") (defun m3::show-trait (&optional arg) "Find an LSL trait file." (interactive) (let* ((trait (if (stringp arg) arg (m3::ident-around-point))) (file (m3::locate-file (concat trait ".lsl") m3::trait-path))) (if file (m3::show-file file) (error "Unable to locate trait %s." trait)))) (defun m3::ident-around-point () (save-excursion (let (end) (re-search-forward "[^A-Za-z0-9_]" nil t) (backward-char) (setq end (point)) (re-search-backward "[^A-Za-z0-9_]" nil t) (forward-char) (buffer-substring (point) end)))) (defun m3::show-file-work (interface kind) (m3::read-default-path) (let ((path (m3::read-path))) (message "Searching for file...") (cond ((eq kind 'interface) (setq filename (or (m3::locate-file interface path '(".i3" ".ig")) (m3::locate-file interface m3::path-default '(".i3" ".ig")) ))) ((eq kind 'specification) (setq filename (or (m3::locate-file (concat interface ".lm3") path) (m3::locate-file (concat interface ".lm3") m3::path-default) )))) (if (not filename) (message "Unable to locate %s '%s'" kind interface) (message "found.") (m3::show-file filename)))) (defun m3::show-file (filename) (cond ((and m3::show-file-other-frame (fboundp 'find-file-other-frame)) (find-file-other-frame filename)) (t (find-file-other-window filename)))) (defun m3::show-implementation () "If the current buffer contains an interface file, attempts to find the implementation of that interface in the same directory as the interface, and displays that file if it is found. If using epoch and m3::show-file-other-frame is non-nil, displays the file in a new screen." (interactive) (let* ((bfn (buffer-file-name)) (ext (m3::get-extension (file-name-nondirectory bfn)))) (if (and bfn (or (equal ext ".i3") (equal ext ".ig"))) (progn ;; First, find the true directory of the file. (let* ((true-name (m3::file-true-name bfn)) (true-dir (file-name-directory true-name)) (interface-name (m3::strip-extension (file-name-nondirectory bfn))) (save-buffer (current-buffer)) (new-buffer (get-buffer-create "*implementation*")) (impl-name (concat true-dir interface-name (if (equal ext ".i3") ".m3" ".mg")))) (if (not (file-exists-p impl-name)) (if (not (equal ext ".i3")) (setq impl-name nil) (save-excursion (setq impl-name nil) (set-buffer new-buffer) (delete-region (point-min) (point-max)) (let ((grep-cmd (concat "cd " true-dir ";" "egrep -l " "'(MODULE +" interface-name ")|" "(MODULE +[a-zA-Z_][a-zA-Z_0-9]* +EXPORTS +" "([a-zA-Z_][a-zA-Z_0-9]*, *)*" interface-name ")' *.m3"))) (message "Searching for exporter of %s..." interface-name ) (shell-command-on-region (point-min) (point-min) grep-cmd t) (message "done.")) (goto-char (point-min)) (if (> (point-max) (point-min)) (progn (setq impl-name (buffer-substring (point-min) (save-excursion (end-of-line nil) (point)))) (message "Implementation is %s." impl-name)))))) (if (not impl-name) (message "Implementation of %s not found in directory %s." interface-name true-dir) (m3::show-file (concat true-dir impl-name))))) (message "Current file does not appear to be an interface.")))) (defun m3::file-true-name (fn) (let ((continue t)) (while continue (let* ((fa (file-attributes fn)) (fa1 (car fa))) (cond ((or (eq fa1 t) (not fa1)) (setq continue nil)) (t ;; Otherwise, fa is a symbolic link; follow it. (setq fn fa1))))) (expand-file-name fn))) (defun m3::get-extension (name) "Gets .ext from the given string (where ext is any extension)" (let ((dot-pos (string-match "\\." name))) (if dot-pos (let ((ext (substring name dot-pos nil)) ext-pos) (setq ext-pos (string-match "<" ext)) (if ext-pos (substring ext 0 ext-pos) ext))))) (defun m3::strip-extension (name) "Strips .ext from the given string (where ext is any extension)" (let ((dot-pos (string-match "\\." name))) (if dot-pos (substring name 0 dot-pos) name))) -- ====================================================================== Dave Detlefs DEC Systems Research Center Palo Alto, CA ======================================================================= 83 === Date: 22 Jan 1995 20:08:05 GMT From: bm@shadow.cs.columbia.edu (Blair MacIntyre) Subject: Re: modula3.el - blink-matching-open problem in Emacs 19 ... >>>>> On 20 Jan 1995 23:03:39 GMT, detlefs@src.dec.com (Dave Detlefs) >>>>> said: Dave> Blair MacIntyre writes: Dave> I was just wonder if anyone else had this problem and had a Dave> workaround. When I close a comment in Emacs, I get the Dave> error Dave> Signalling: (wrong-type-argument number-or-marker-p nil) Dave> blink-matching-open() Dave> This doesn't seem to happen in Emacs-18, so I'm wondering if Dave> it's something weird with 19, and if anybody has a fix. Dave> Turning of blink-matching-paren obviously fixes it, but Dave> that's not entirely satisfactory. Dave> I don't have this problem with emacs19. Here is the version of Dave> modula3.el we're currently using at SRC; perhaps yours is older... Well, mine is the one included in the v3.4 distribution ... it looks pretty similar. Must be something else. -- Blair MacIntyre (bm@cs.columbia.edu), Graduate Student (Graphics and UI Lab) smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St. Columbia University, New York, NY 10027 ======================================================================= 84 === Date: 22 Jan 1995 19:43:11 GMT From: schwartz@galapagos.cse.psu.edu (Scott Schwartz) Subject: Re: Request for status on v. 3.4 (SPARC) nayeri@gte.com (Farshad Nayeri) writes: > Please don't take these numbers seriously, Why not? If M3 has such a huge runtime system, that's important to know. Is there some subtle aspect of the language that makes it so difficult to implement efficienty? ======================================================================= 85 === Date: 23 Jan 95 01:02:39 From: nayeri@gte.com (Farshad Nayeri) Subject: Re: Request for status on v. 3.4 (SPARC) In article schwartz@galapagos.cs e.psu.edu (Scott Schwartz) writes: nayeri@gte.com (Farshad Nayeri) writes: > Please don't take these numbers seriously, Why not? I am sorry, I was not being clear. I will try again: "Please don't take my numbers seriously as performance measurements go since I haven't taken real care of making sure that they are accurate." If M3 has such a huge runtime system, that's important to know. My judgement for the current size of the runtime system is "moderate". For my case, the trade-offs have been well worth it. (Note that just by stripping the binaries you may half their size!) Is there some subtle aspect of the language that makes it so difficult to implement efficienty? Quite the oppossite: M3's design is a delicate balance of "high-level programming" features that have been massaged so that they can be implemented efficiently. In fact, there are some subtle aspects of the language that makes it easier to implement efficiently. Note that "to implement efficiently" can mean different things in different contexts. Do you mean run-time, development, compile-time, or space efficiency? -- Farshad -- Farshad Nayeri nayeri@gte.com ======================================================================= 86 === Date: 24 Jan 1995 06:00:40 GMT From: schwartz@galapagos.cse.psu.edu (Scott Schwartz) Subject: Re: Request for status on v. 3.4 (SPARC) nayeri@gte.com (Farshad Nayeri) writes: | Note that "to implement efficiently" can mean different things in | different contexts. Do you mean run-time, development, compile-time, | or space efficiency? I mean, why is the runtime system so huge? If it takes 400K just to get off the ground, something is wrong. My idea of a well written program is the shell I normally use (author Byron Rakitzis). On a sparc running sunos4.1, the statically linked version is this big: ; size /bin/rc text data bss dec hex 73728 16384 6944 97056 17b20 This shell uses dynamic memory allocation, an lalr parser, a string formatting library, and various nontrivial data structures. The source is about 7000 lines of C. If it was written in m3 instead of C, the runtime system would be an order of magnitude larger than the program itself. That's hard to ignore. Please understand, I don't mean to pick on m3; plenty of things are bloated these days, after all. I'm bitching because I like m3. ======================================================================= 87 === Date: Tue, 24 Jan 1995 09:45:00 -0500 From: gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS) Subject: Re: Request for status on v. 3.4 (SPARC) In-Reply-To: Distribution: world X-Received: from suneast.East.Sun.COM by East.Sun.COM (4.1/SMI-4.1) X-Received: by src-mail.pa.dec.com; id AA24308; Tue, 24 Jan 95 06:53:13 -0800 X-Newsgroups: comp.lang.modula3 X-Content-Length: 3002 X-Received: from cloyd.East.Sun.COM by suneast.East.Sun.COM (5.0/SMI-4.1-900117 ) X-Received: from Sun.COM by inet-gw-1.pa.dec.com (5.65/10Aug94) X-Received: by cloyd.East.Sun.COM (5.x/SMI-SVR4) X-Received: from East.Sun.COM (east.East.Sun.COM) by Sun.COM (sun-barr.Sun.COM) X-Received: by src-news.pa.dec.com; id AA21803; Tue, 24 Jan 95 06:53:18 -0800 Scott Schwartz writes: > nayeri@gte.com (Farshad Nayeri) writes: > | Note that "to implement efficiently" can mean different things in > | different contexts. Do you mean run-time, development, compile-time, > | or space efficiency? > > I mean, why is the runtime system so huge? If it takes 400K just to > get off the ground, something is wrong. > > My idea of a well written program is the shell I normally use (author > Byron Rakitzis). On a sparc running sunos4.1, the statically linked > version is this big: > > ; size /bin/rc > text data bss dec hex > 73728 16384 6944 97056 17b20 > > This shell uses dynamic memory allocation, an lalr parser, a string > formatting library, and various nontrivial data structures. The > source is about 7000 lines of C. If it was written in m3 instead of > C, the runtime system would be an order of magnitude larger than the > program itself. That's hard to ignore. > > Please understand, I don't mean to pick on m3; plenty of things are > bloated these days, after all. I'm bitching because I like m3. The runtime proper provides quite a bit more functionality than the C runtime gives you. In particular, it gives you: - Threads - Exception Handling - Text Manipulation - Incremental, conservative, generational GC - weak references - fingerprints - unix interfaces - runtime type information on Solaris 2.4, the shared library for the M3 runtime (m3core) is about 400K stripped (448084 to be exact). For comparison, libc on the same release is 476983 bytes. On SunOS 4.1.3, a stripped libc shared library is also 400K. Given that these two libraries have essentially the same role in life and libm3 gives you much more functionality, I'm not sure there is all that much to complain about. It would be possible to build a version of 'libm3' that didn't require 'libc' to be linked at all, and I would expect that a commercial implementation might do just that. Carefully written C programs may be smaller than the equivalent M3 programs due to the fact that object modules in 'libc' tend to be pretty much isolated from each other, whereas 'libm3core' tends to have a fair number of references between the components. Thus in any given application, all of 'libm3core' will be pulled in, whereas only a subset of 'libc' will be pulled into the application. As a research project, SRC has not chosen to focus on building minimal-sized i mages, but has tended to focus on higher-level functionality. I'm not sure that it is entirely fair to compare Modula-3 with C. They have di fferent goals and this has led to differences in the functionality provided. Also Modul a-3 programmers program in a different style than C programmers writing shells. I t hink a more accurate (or interesting) comparison would be between Modula-3 and Smallta lk or Modula-3 and Eiffel. --geoff Geoff Wyant Geoff.Wyant@east.sun.com Sun Microsystems Laboratories, Inc. 2 Elizabeth Drive Chelmsford, Ma. 01824 ======================================================================= 88 === Date: Tue, 24 Jan 1995 15:06:16 GMT From: freeman@coolidge.coolidge.grenoble.xerox.fr (Steve Freeman) Subject: European Users' group meeting at ECOOP? Is anyone interested in organising/speaking at/attending an M3 Users Group at ECOOP (in Aarhus) this year? Could you drop me a note (or post here) and maybe we can get something started? steve -- - - - - - - - - - - - - - - - - - - - - - - - - - - Dr. Steve Freeman, Research Scientist, Rank Xerox France. Surface: Rank Xerox Research Centre, 6, chemin de Maupertuis, 38240 Meylan, France. Internet: steve.freeman@xerox.fr Phone: +33 76 61 50 21 Fax: +33 76 61 50 99 but wotthehel wotthehel toujours gai -- mehitabel the cat ======================================================================= 89 === Date: 24 Jan 1995 20:04:22 GMT From: schwartz@galapagos.cse.psu.edu (Scott Schwartz) Subject: Re: Request for status on v. 3.4 (SPARC) gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS) writes: | The runtime proper provides quite a bit more functionality than the C runtime | gives you. Does it really take 400K to get those features? Features are useless if they are too expensive. Oberon provides that kind of stuff in a very much smaller package. | As a research project, SRC has not chosen to focus on building | minimal-sized images, but has tended to focus on higher-level | functionality. As I've said, I think m3 is very nice, and I applaud the good people at SRC. At the same time, I don't think it is fair to dismiss the issue. Computers are finite and efficiency counts. | I think a more accurate (or interesting) comparison would be between | Modula-3 and Smalltalk or Modula-3 and Eiffel. As to that, I've used Smalltalk on PCs that were far too small to run SRC m3. ======================================================================= 90 === Date: Wed, 25 Jan 1995 10:23:22 -0500 From: gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS) Subject: Re: Request for status on v. 3.4 (SPARC) <9501241445.AA22145@cloyd.East.Sun.COM> Cc: nayeri@gte.com In-Reply-To: Distribution: world X-Received: from suneast.East.Sun.COM by East.Sun.COM (4.1/SMI-4.1) X-Received: by src-mail.pa.dec.com; id AA25075; Wed, 25 Jan 95 10:29:04 -0800 X-Newsgroups: comp.lang.modula3 X-Content-Length: 3837 X-Received: from cloyd.East.Sun.COM by suneast.East.Sun.COM (5.0/SMI-4.1-900117 ) X-Received: from Sun.COM by inet-gw-2.pa.dec.com (5.65/10Aug94) X-Received: by cloyd.East.Sun.COM (5.x/SMI-SVR4) X-Received: from East.Sun.COM (east.East.Sun.COM) by Sun.COM (sun-barr.Sun.COM) X-Received: by src-news.pa.dec.com; id AA18387; Wed, 25 Jan 95 10:29:26 -0800 Scott Schwartz writes: > gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS) write s: > | The runtime proper provides quite a bit more functionality than the C runt ime > | gives you. > > Does it really take 400K to get those features? Features are useless > if they are too expensive. Oberon provides that kind of stuff in a > very much smaller package. Well, Oberon makes a number of simplifying assumptions. First, threads are non-preemptive. This elimates the locking and scheduling issues entirely. Secon dly, the garbage collector is a simple mark&sweep GC which is easy to implement but doesn't scale particularly well. The garbage collector in M3 is fairly sophisti cated. The support for preemptive threads in M3 complicates the garbage collector some what, thus adding to the size of the runtime. Additionally, Oberon doesn't have excep tions. This makes the runtime and libraries smaller.One reason they are smaller is tha t the SRC implementation uses PC tables so that exception handlers can be quickly loc ated. Which of these simplifying assumptions would you make for M3 and why ? Finally, and here I think is a key difference. Oberon (and I'm talking about th e ETH Zurich implementation) is a programming language, programming environment, and operating system rolled into one. This gives considerable leverage that the SRC M3 implementation doesn't have. In particular, they get to define their own object file format and own loader. Some of the size of the SRC object files come from having to encode M3 functionality into standard object file formats and from having to duplicate some of the information which is in the object file (procedure & type names, type information, etc.) Portability comes at a price. Would you have SRC conce ntrate on an optimized MIPS-specific implementation and not worry about portability an d the ability to use standard tools ? I know the counter-argument that you will make here, which is that Oberon has b een ported to a number of platforms and still manages to have small platform-specif ic implementations. The difference lies in the size of the development groups. Wir th essentially has an endless supply of graduate students that can put in arbitrar y amounts of time to bring up a platform-specific Oberon implementation. DEC SRC doesn't really have a large full-time M3 group. The M3 group is, I think, about two people. Ot her SRC researchers contribute to the runtime as needed, but there is no one that works on the runtime full-time and who's sole job is ehancing and porting the runtime. A lso bear in mind that SRC has essentially only MIPS and Alpha machines. All of the other ports come from outside. Given this, I would say that SRC has done more than a reasonable job on the M3 implementation. > > | As a research project, SRC has not chosen to focus on building > | minimal-sized images, but has tended to focus on higher-level > | functionality. > > As I've said, I think m3 is very nice, and I applaud the good people > at SRC. At the same time, I don't think it is fair to dismiss the > issue. Computers are finite and efficiency counts. > I'm not dismissing the issue entirely. I personally believe that SRC has made t he right choices on what they choose to spend their research efforts on. I think t hat a commercial implementation of M3 could be made smaller by having more intimate knowledge of object file formats. I personally don't feel that this is somethin g that SRC should be devoting resources to. If you really do like the language, a nd believe that the same functionality could be provided in considerably less spac e, I'll challange you to take the SRC implementation and make it smaller. You hav e all of the sources available. If you succeed, then you will have provided a service to everyone. --geoff ======================================================================= 91 === Date: 25 Jan 95 11:36:24 From: dagenais@gutrune.vlsi.polymtl.ca (Michel Dagenais) Subject: Re: Request for status on v. 3.4 (SPARC) Does it really take 400K to get those features? Features are useless if they are too expensive. Oberon provides that kind of stuff in a very much smaller package. Last time i checked the GC and threads in Oberon were "rudimentary". Each background module is given a turn to do "a bit of work" one after the other (i.e. non preemptive multi threading). The garbage collection takes place between the turns, while the stack is empty. Less functionality and less memory, there is obviously a trade off. Pick the trade off which best matches to your needs. -- Prof. Michel Dagenais http://www.vlsi.polymtl.ca/dagenais/home/home.html Dept of EE and Computer Eng. dagenais@vlsi.polymtl.ca Ecole Polytechnique de Montreal tel: (514) 340-4029 ======================================================================= 92 === Date: Wed, 25 Jan 1995 17:10:07 GMT From: ljp@my21.sm.luth.se (Johan Persson) Subject: [Q] Problem with VBT.MMToPixels() Does anyone have any idea why my library version of VBT.MMToPixels() insists on that 1mm <-> 1 pixels, which on my screen certainly is not true, (it should be 4). Should I put the blame on the X-server? I'm currently using version 3.4 of m3, but I had the same problem with 3.3. The other routines that uses mm, e.g RigidVBT, behaves as expected. /Johan --- Johan Persson, (ljp@sm.luth.se) -- --- Johan Persson http://www.sm.luth.se/~ljp/ Dept. of Computer Science University of Lulea ======================================================================= 93 === Date: 25 Jan 1995 10:50:45 -0800 From: bertrand@vienna.eiffel.com (Bertrand Meyer) Subject: L'OBJET: A new journal (in French) on object technology. [This message describes the launching of a new journal, in French, entirely devoted to object technology.] Une nouvelle publication en langue francaise, la premiere a notre connaissance a etre entierement consacree aux technologies objet, vient d'etre creee: L'OBJET Logiciel, Reseaux, Bases de Donnees Le premier numero sera disponible debut mars pour la conference TOOLS (Versailles, 6-10 mars). La revue est trimestrielle et parait les 1er mars, 1er juin, 1er septembre et 1er decembre. Elle est consacree a tous les aspects des technologies objets, couvre tous les domaines d'application (langages, methodes, telecommunications, bases de donnees, finance, materiel, intelligence artificielle etc.), et est ouverte a toutes les tendances du domaine. La revue contiendra des articles d'information technique ainsi que des nouvelles d'interet general et des offres d'emploi. Elle se veut un trait d'union entre tous les membres de la communaute "Objet". A ce titre n'hesitez pas a nous envoyer toute annonce susceptible d'interesser les lecteurs: publications, conferences, realisations industrielles, theses, formations universitaires, seminaires ... Redacteur en chef: Jean-Alain Hernandez (ENST Paris) Directeur de la Publication: Jean-Marc Nerson (SOL, Paris) Conseiller scientifique: Bertrand Meyer (ISE, Santa Barbara) Patronage: AFCET (a confirmer) Comite de Redaction (* = non confirme): Jean Bezivin (Univ. de Nantes) Pere Botella (Univ. Polyt. de Catalogne) Fiorella De Cindio (Universita di Milano) Pierre Desjardins (CITI, Laval - Quebec) Jean-Marc Eber* (Societe generale) Andre Flory (INSA) Nasser Kettani (CR2A) Sophie Gamerman (O2 Technology) Hafedh Mili (Univ. du Quebec a Montreal) Oscar Nierstrasz (Univ. de Berne) Jean Francois Perrot* (Laforia) Arnold Rochfeld (Consultant) Philippe Stephan (CALFP/Credit Agricole) Jean Bernard Stefani* (CNET) Patrick Valduriez (Inria) Jean Vaucher* (Univ. de Montreal) Abonnement annuel: 95 F (France), 120 F (autres pays europeens), 150 F (autres pays). Abonnements, offres d'emploi, publicite: SOL 104 rue Castagnary 75015 Paris Telephone 45 32 58 80, Telecopie 45 32 58 81, Courrier electronique Pour soumettre des articles ou envoyer des informations a publier : Jean-Alain Hernandez ENST, 46 rue Barrault 75634 Paris Cedex 13 Courrier electronique -- Bertrand Meyer - ISE, Santa Barbara, California 805-685-1006, fax 805-685-6869, Web home page: http://www.eiffel.com ftp://eiffel.com ======================================================================= 94 === Date: Wed, 25 Jan 1995 18:23:46 PST From: janssen@parc.xerox.com (Bill Janssen) Subject: Re: Request for status on v. 3.4 (SPARC) <9501241445.AA22145@cloyd.East.Sun.COM>Sender: janssen@parc.xerox.com ( Bill Janssen) In-Reply-To: <9501241445.AA22145@cloyd.East.Sun.COM> Distribution: world X-Received: by holmes.parc.xerox.com id <16136>; Wed, 25 Jan 1995 18:23:49 -080 0 X-Received: by src-mail.pa.dec.com; id AA03895; Wed, 25 Jan 95 18:30:32 -0800 X-Received: from Messages.7.15.N.CUILIB.3.45.SNAP.NOT.LINKED.holmes.parc.xerox. com.sun4.41 X-Received: from alpha.Xerox.COM by inet-gw-2.pa.dec.com (5.65/10Aug94) X-Received: from holmes.parc.xerox.com ([13.1.100.162]) by alpha.xerox.com with SMTP id <14593(7)>; Wed, 25 Jan 1995 18:23:55 PST X-Received: by src-news.pa.dec.com; id AA01207; Wed, 25 Jan 95 18:30:34 -0800 X-Illegal-Object: Syntax error in To: address found on alpha.xerox.com: An interesting note: I was told today that PARC Posix Portable Common Runtime, a library that provides threads, garbage-collection, and dynamic (or incremental) loading as library routines, is about 400k stripped. Bill ======================================================================= 95 === Date: 25 Jan 1995 23:56:00 GMT From: semb100@cus.cam.ac.uk (Simon Barber) Subject: Static binding in Objects, Inlining and Defining operators I am fairly new to M3, so please excuse me if the answers to any of these questions are obvious. 1) I have recently been writing a program to manipulate MPEG streams in Modula 3 and have come up with these problems. My initial structure for the program had a separate module which defined a file object that was buffered, and which I could perform bit aligned bit IO. This proved very slow, I suspect due to the dynamic binding of my BitIO.T object. Reading megabyte sized files several bits at a time is just too slow. I re-wrote the program using inline procedures on a mpeg stream type, and now it runs at an acceptable speed. Is there a way to define a static bound, and so inlinable object method in Modula 3? I believe this can be done in C++, and see this as a serious flaw in Modula 3 as a conender against C++ on efficiency grounds. 2) In Modula 3 if I put <*INLINE*> before a procedure signature in its interface and before its definition in its module will it be inlined when it's used in another module? (Under M3 v3.3 for Solaris?) 3) Sometimes it is very clumsey to express operations as FunctionCall(Operand1, Operand2 etc etc), would it be an idea to include a declarator OPERATOR to allow one to define operations. This would allow overloading of operators and choose the appropriate function call according to the types taken by the operator. The syntax could look something like\ OPERATOR argument1 + argument2 = SpecialAdd(argument1, argument2); The types would be culled from the procedure signature. Does this go too far against the Modula 3 way of thinking? One way it could be used - and easily abused - would be to alias function calls, but call the currect function for the appropriately typed arguments - eg. OPERATOR add(argument1, argument2) = SpecialAdd(argument1, argument2); Comments and ideas? Simon ======================================================================= 96 === Date: 26 Jan 1995 01:02:59 -0500 From: kraizman@news.cs.columbia.edu (Michael Kraizman) Subject: Status of various ports? Sorry to sound like a broken record, but does anyone know the status of the modula3 ports to NT and OS/2 and where to get them? Thanks. Michael Kraizman ---------------------------------------------------------------------- kraizman@cs.columbia.edu -- Michael Kraizman ======================================================================= 97 === Date: 26 Jan 1995 20:56:53 GMT From: ckingsto%hookup.net@mail.hookup.net Subject: Re: Modula-3 for OS/2 In , dagenais@notung.vlsi.polymt l.ca (Michel Dagenais) writes: > >From the FAQ. The last persons known to be working on such a port were >Hendrik Boom hendrick@CAM.ORG and Craig Andrew Kingston >ckingsto@undergrad.math.uwaterloo.ca. >-- > >Prof. Michel Dagenais dagenais@vlsi.polymtl.ca >Dept of Electrical and Computer Eng. >Ecole Polytechnique de Montreal tel: (514) 340-4029 Hi Everyone - Craig here. I am still continuing to work on the port - just got delayed for a couple of mo nths because of issues not relating to the port. Not sure at this time of any dates . CRAIG note: (my email has changed - not longer ckingsto@undergrad.math.uwaterloo.ca but is now ckingsto@hookup.net) ======================================================================= 98 === Date: Thu, 26 Jan 95 18:58:05 -0500 From: Dj Harris Subject: Modula-3 for NT Is there a port of M3 for NT ? And where can I get it, if it exists ? Thanks, Dj. ======================================================================= 99 === Date: Fri, 27 Jan 1995 00:32:03 GMT From: eric@telebit.com (Eric Smith) Subject: Anyone using Modula-3 for embedded systems? I'd like to use Modula-3 for an embedded system (i.e., on bare metal rather than in a Unix process), so I'd like to know if anyone has any experience doing so. Are there any published reports or papers on Modula-3 based embedded systems? I expect that I'll have to rewrite portions of the run time system, and add support to the Thread interface for the specification of thread priority and stack size. Has anyone already done this sort of thing, or at least come up with proposed extensions to Thread? Thanks! Eric ======================================================================= 100 === Date: 27 Jan 1995 01:22:29 GMT From: mbk@inls1.ucsd.edu (Matt Kennel) Subject: Re: Request for status on v. 3.4 (SPARC) Geoffrey Wyant - Sun Microsystems Labs BOS (gwyant@cloyd.East.Sun.COM) wrote: : The runtime proper provides quite a bit more functionality than the C runtime : gives you. In particular, it gives you: : - Threads : - Exception Handling : - Text Manipulation : - Incremental, conservative, generational GC : - weak references : - fingerprints : - unix interfaces : - runtime type information : on Solaris 2.4, the shared library for the M3 runtime (m3core) : is about 400K stripped (448084 to be exact). For comparison, libc : on the same release is 476983 bytes. On SunOS 4.1.3, a stripped libc shared : library is also 400K. Given that these two libraries have essentially the sam e : role in life and libm3 gives you much more functionality, I'm not sure there is : all that much to complain about. : Carefully written C programs may be smaller than the equivalent M3 programs : due to the fact that object modules in 'libc' tend to be pretty much isolated : from each other, whereas 'libm3core' tends to have a fair number of reference s : between the components. Thus in any given application, all of 'libm3core' wil l be : pulled in, whereas only a subset of 'libc' will be pulled into the applicatio n. : As a research project, SRC has not chosen to focus on building minimal-sized images, : but has tended to focus on higher-level functionality. : I'm not sure that it is entirely fair to compare Modula-3 with C. They have different : goals and this has led to differences in the functionality provided. Also Mod ula-3 : programmers program in a different style than C programmers writing shells. I think a : more accurate (or interesting) comparison would be between Modula-3 and Small talk or : Modula-3 and Eiffel. The Sather test suite, which exercises a fair number of library classes and functions, compiles to 204K stripped on Solaris. (Only needs dynamic linking to libc). Sather is a full-fledged OO language. The Sather compiler itself compiles to 745K stripped. There are a couple of reasons why it can make relatively small code: 1) It only makes code for those individual *routines* that are reachable in the call graph from 'main'. So if there are some bloat routines in a big library that call some other libraries, if you never call those routines in the first place, they will not need to be brought in, and neither will the things that they call either. 2) It distinguishes dispatched references from non-dispatched references. In realistic programs one often does not end up needing dispatches in many places: the exact type of the object is known. Thus in combination with #1, when you know the exact type the compiler need only generate code for specific routines, and not all routines that might match a signature in any subtypes. ----- I do not know how either of these points apply to Modula-3. Please: This is not flame bait. The goals are different: sather does place a reasonably high premium on performance and efficiency. Some space efficiency can probably still be wrung out of the Sather compiler, as inlining isn't working yet. The run-time is smaller, it does not include threads, but it does have RTTI, GC and exceptions. cheers Matt : : --geoff : Geoff Wyant : Geoff.Wyant@east.sun.com : Sun Microsystems Laboratories, Inc. : 2 Elizabeth Drive : Chelmsford, Ma. : 01824 -- -Matt Kennel mbk@inls1.ucsd.edu -Institute for Nonlinear Science, University of California, San Diego -*** AD: Archive for nonlinear dynamics papers & programs: FTP to -*** lyapunov.ucsd.edu, username "anonymous". ======================================================================= 101 === Date: Fri, 27 Jan 95 14:23:34 -0800 From: rustan@pa.dec.com Subject: Re: Anyone using Modula-3 for embedded systems? A couple of years ago, I wrote a new runtime system for Modula-3. The runtime system targeted a multicomputer called the Mosaic, built by Chuck Seitz et al. at Caltech. Each Mosaic processor only has 64 KB RAM. The implementation, described in Multicomputer Programming with Modula-3D Caltech Technical report Caltech-CS-TR-93-15, available on the Web and through FTP (ftp://ftp.cs.caltech.edu/tr/cs-tr-93-15.ps.Z), includes everything required by the language (except floating point support). This includes threads, exceptions, and garbage collection. The "D" (for "distributed") extension of Modula-3 adds remote procedure calls through method invocations of NETWORK objects (a new type in Modula-3D). The Thread interface, like that provided in the SRC implementation, features a special Thread.Closure type called SizedClosure that allows the stack size to be set, but Thread priorities are not included. Rustan Leino ======================================================================= 102 === Date: 27 Jan 1995 15:09:38 GMT From: Jeffrey Fries P865 Subject: Re: L'OBJET: A new journal (in French) on object technology. bertrand@vienna.eiffel.com (Bertrand Meyer) wrote: > > > [This message describes the launching of a new journal, in French, > entirely devoted to object technology.] > > Une nouvelle publication en langue francaise, la premiere a notre > connaissance a etre entierement consacree aux technologies objet, vient > d'etre creee: > > L'OBJET > Logiciel, Reseaux, Bases de Donnees > > Le premier numero sera disponible debut mars pour la conference > TOOLS (Versailles, 6-10 mars). > > La revue est trimestrielle et parait les 1er mars, 1er juin, 1er > septembre et 1er decembre. Elle est consacree a tous les aspects des > technologies objets, couvre tous les domaines d'application (langages, > methodes, telecommunications, bases de donnees, finance, materiel, > intelligence artificielle etc.), et est ouverte a toutes les tendances > du domaine. > > La revue contiendra des articles d'information technique ainsi que > des nouvelles d'interet general et des offres d'emploi. Elle se veut un > trait d'union entre tous les membres de la communaute "Objet". > A ce titre n'hesitez pas a nous envoyer toute annonce susceptible > d'interesser les lecteurs: publications, conferences, realisations > industrielles, theses, formations universitaires, seminaires ... > > Redacteur en chef: Jean-Alain Hernandez (ENST Paris) > Directeur de la Publication: Jean-Marc Nerson (SOL, Paris) > Conseiller scientifique: Bertrand Meyer (ISE, Santa Barbara) > Patronage: AFCET (a confirmer) > Comite de Redaction (* = non confirme): > > Jean Bezivin (Univ. de Nantes) > Pere Botella (Univ. Polyt. de Catalogne) > Fiorella De Cindio (Universita di Milano) > Pierre Desjardins (CITI, Laval - Quebec) > Jean-Marc Eber* (Societe generale) > Andre Flory (INSA) > Nasser Kettani (CR2A) > Sophie Gamerman (O2 Technology) > Hafedh Mili (Univ. du Quebec a Montreal) > Oscar Nierstrasz (Univ. de Berne) > Jean Francois Perrot* (Laforia) > Arnold Rochfeld (Consultant) > Philippe Stephan (CALFP/Credit Agricole) > Jean Bernard Stefani* (CNET) > Patrick Valduriez (Inria) > Jean Vaucher* (Univ. de Montreal) > > > Abonnement annuel: 95 F (France), 120 F (autres pays europeens), > 150 F (autres pays). > > Abonnements, offres d'emploi, publicite: > SOL > 104 rue Castagnary > 75015 Paris > Telephone 45 32 58 80, Telecopie 45 32 58 81, > Courrier electronique > > Pour soumettre des articles ou envoyer des informations a publier : > Jean-Alain Hernandez > ENST, 46 rue Barrault 75634 Paris Cedex 13 > Courrier electronique > -- > Bertrand Meyer - ISE, Santa Barbara, California > 805-685-1006, fax 805-685-6869, > Web home page: http://www.eiffel.com > ftp://eiffel.com What did ya say ? huh ? ======================================================================= 103 === Date: 27 Jan 95 07:44:56 From: nayeri@gte.com (Farshad Nayeri) Subject: Re: Modula-3 for NT In article Dj Harris writes : Is there a port of M3 for NT ? And where can I get it, if it exists ? Thanks, Dj. Dj, Yes, there is. SRC Modula-3 has been ported to NT (it actually compiles to native code!) You can find it in gatekeeper.dec.com:/pub/DEC/Modula-3/release-3.4 There are also various DOS ports which should run in emulation, but you are probably better off using the NT port. See the FAQ for more info. -- Farshad -- Farshad Nayeri nayeri@gte.com ======================================================================= 104 === Date: 25 Jan 1995 18:02:46 -0800 From: rro@Tera.COM (Rod Oldehoeft) Subject: Re: Request for status on v. 3.4 (SPARC) On the discussion about the size of M3 executables: this is often a problem with "young" language software--the same was true, in spades, for Ada. That said, one wonders just what library routines are present in a "Hello World" M3 executable. One should look before going too much further in this discussion. I cannot easily check myself just now, since I'm in a temporary place at the moment. If there really is thread software in there, for example, it would be disappointing. The idea of minimizing the strength of connection among functions is not a new idea, just a good one. Back to the young software point, this is just not on the top of the list for implementors. A commercial motivation would clearly help. Just my $.02. ======================================================================= 105 === Date: 27 Jan 1995 15:34:10 GMT From: root@owl.bias.Uni-Bremen.DE (Jochen Skupin) Subject: Problems with M3 V3.4 and Solaris 2.3 Hello, I'm trying to install the new Modula3 version 3.4 on my Sparcstation5 under Solaris 2.3 with gcc 2.6.3. The bootstrap installation succeded after replacing the boot-SOLgnu/m3cc/gcc/va-sparc.h file by it's newer version from gcc 2.6.3 (as mentioned in this list a few days before). Installing the m3-packages still makes problems. Not all packages compile without errors (Which doesn't bother me to much, because I don't need them all). In m3core/src/runtime/SOLgnu/RTThreadC.c I have replaced #include with #include to get it compiled. At this stage compiling and running of the "hello world" programm works. But the compiled packages (Tetris, Cube ...) won't run. They all stop with the error (And that what's bothering me.): *** *** runtime error: *** Exception "Date.Error" not in RAISES list *** Abort - core dumped I have no clue, what's happening here (I'm wether used to work with Modula3 nor UNIX nor C :-( ). Does anybody know how to solve this problem? Thanks in advance Jochen Skupin PS: I noticed that libs (for example libm3core.so) don't get installed (shipped ?) in the /usr/local/lib/m3/SOLgnu folder as they should. Instead they are in /usr/local/lib/m3/pkg/package-name/SOLgnu. The templates/SOLgnu-file reads as: readonly TARGET = "SOLgnu" readonly DEFAULT_BUILD_DIR = TARGET INSTALL_ROOT = "/usr/local/" %-- handy for installations that keep all M3 stuff together BIN_INSTALL = INSTALL_ROOT & "bin" % executables LIB_INSTALL = INSTALL_ROOT & "lib/m3/" & TARGET % libraries ^^^^^^^^^^^^^^^^^ this should do the tr ick I think, but it doesn't :-( DOC_INSTALL = INSTALL_ROOT & "lib/m3/doc" % documents PKG_INSTALL = INSTALL_ROOT & "lib/m3/pkg" % packages EMACS_INSTALL = INSTALL_ROOT & "lib/elisp" % emacs lisp code MAN_INSTALL = INSTALL_ROOT & "man" % man pages HTML_INSTALL = INSTALL_ROOT & "lib/m3/www" % public hypertext ======================================================================= 106 === Date: Sat, 28 Jan 1995 19:44:42 GMT From: leendert@cs.vu.nl (Leendert van Doorn) Subject: Re: Problems with M3 V3.4 and Solaris 2.3 root@owl.bias.Uni-Bremen.DE (Jochen Skupin) writes: # At this stage compiling and running of the "hello world" programm works. # But the compiled packages (Tetris, Cube ...) won't run. They all stop with # the error (And that what's bothering me.): # # *** # *** runtime error: # *** Exception "Date.Error" not in RAISES list # *** # # Abort - core dumped # # I have no clue, what's happening here (I'm wether used to work with Modula3 # nor UNIX nor C :-( ). Does anybody know how to solve this problem? This has to do with SRC being west of GMT instead of east :-) The following fixes it: *** libm3/src/uid/Common/TimeStamp.m3 Fri Jan 6 17:18:50 1995 --- libm3/src/uid/Common/TimeStamp.m3.ORIG Fri Jan 6 17:08:40 1995 *************** *** 2,9 **** (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) ! (* Last modified on Fri Jan 6 17:18:05 MET 1994 by leendert *) ! (* modified on Tue Aug 24 09:05:29 PDT 1993 by kalsow *) (* modified on Thu Jul 15 17:33:05 PDT 1993 by swart *) (* modified on Wed Apr 21 13:15:46 PDT 1993 by mcjones *) (* modified on Tue Mar 9 15:02:05 PST 1993 by mjordan *) --- 2,8 ---- (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) ! (* Last modified on Tue Aug 24 09:05:29 PDT 1993 by kalsow *) (* modified on Thu Jul 15 17:33:05 PDT 1993 by swart *) (* modified on Wed Apr 21 13:15:46 PDT 1993 by mcjones *) (* modified on Tue Mar 9 15:02:05 PST 1993 by mjordan *) *************** *** 142,148 **** PROCEDURE FindEpoch () = CONST ! epochDate = Date.T{1970, Date.Month.Jan, 2, 0, 0, 0, 0, "", Date.WeekDay.Sun}; <*FATAL Date.Error*> BEGIN --- 141,147 ---- PROCEDURE FindEpoch () = CONST ! epochDate = Date.T{1970, Date.Month.Jan, 1, 0, 0, 0, 0, "", Date.WeekDay.Sun}; <*FATAL Date.Error*> BEGIN Leendert -- Leendert van Doorn Vrije Universiteit / Dept. of Math. & Comp. Sci. +31 20 4447762 Amoeba project / De Boelelaan 1081A 1081 HV Amsterdam / The Netherlands ======================================================================= 107 === Date: Sun, 29 Jan 1995 02:55:02 GMT From: krystof@cs.washington.edu (Krzysztof Zmudzinski) Subject: WANTED: programs written in Modula 3 I am looking for some interesting (multi-threaded, memory intensive) programs (source codes) to test my M3 GC port to Alpha. Krystof ======================================================================= 108 === Date: 29 Jan 1995 05:51:06 GMT From: ckingsto%hookup.net@mail.hookup.net Subject: Re: Modula-3 for NT In , Dj Harris writes: >Is there a port of M3 for NT ? >And where can I get it, if it exists ? > >Thanks, Dj NT 386 port is available at the ftp site gatekeeper.dec.com in /pub/DEC/Modula-3/release3.4 (hope that dir is correct). Not a full implementation (networking is missing I think). CRAIG. ======================================================================= 109 === Date: 29 Jan 1995 05:47:17 GMT From: ckingsto%hookup.net@mail.hookup.net Subject: Re: Status of various ports? In <3g7duj$30d@lucy.cs.columbia.edu>, kraizman@news.cs.columbia.edu (Michael Kr aizman) writes: >Sorry to sound like a broken record, but does anyone know the status >of the modula3 ports to NT and OS/2 and where to get them? > >Thanks. > > >Michael Kraizman > >---------------------------------------------------------------------- >kraizman@cs.columbia.edu >-- >Michael Kraizman Work on OS/2 port was delayed a couple of months due to unrelated issues but work has resumed - sorry, no date available (give me a few weeks) CRAIG - ======================================================================= 110 === Date: 29 Jan 1995 21:50:48 GMT From: knechamk@ic.sunysb.edu (Kirk A Nechamkin) Subject: Help-Modula3 for Linux Ok, Somebody please help, FAST. As a student at Stony Brook I have grown accustomed to using linux ports of various software pakacges/languages to do my comp. sci. assignments, rather than using the schools HP workstations, mainly because they are outdated and extremely overloaded. So I downloaded Modula-3 and installed it...it's sort of working, it can compile Hello-world. But when I try to run the out-file I get the message: 'can't find 'libm3.so.3'. I get this message even when the library file is in the same directory. Also, many of the programs in the modula3-3.3/bin directory won't run either-giving me the same error message. Ok, now. Somebody out there must have had this error at some point and have had to pull their hair out to solve it. Please email me ANY info on how I can eradicate this error so I can do my projects. It would be very appreciated. Thanks. -Kirk knechamk@ic.sunysb.edu Newsgroups: comp.lang.modula3 Subject: Help - Modula3 for Linux Summary: Followup-To: Distribution: world Organization: State University of New York at Stony Brook Keywords: ======================================================================= 111 === Date: 27 Jan 1995 01:58:33 GMT From: bm@shadow.cs.columbia.edu (Blair MacIntyre) Subject: Macintosh port of M3? Is anyone working on a mac port of modula-3? While looking through the Useful Interfaces document (SRC Report 113), I saw a reference to Macintosh filename conventions ... it got me wondering about a possible port of m3. (It would be nice to be able to work on my laptop). -- Blair MacIntyre (bm@cs.columbia.edu), Graduate Student (Graphics and UI Lab) smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St. Columbia University, New York, NY 10027 ======================================================================= 112 === Date: 28 Jan 1995 09:13:07 -0800 From: rro@Tera.COM (Rod Oldehoeft) Subject: Re: Request for status on v. 3.4 (SPARC) In the discussion of the sizes of things, two ideas are being confused. The first is the sizes of compilers, libraries and executables as they reside in disk files. The second is the memory-resident size of executable products of the language implementation. In some sense, large libraries may only mean that there's a lot of support for much functionality, should a particular program actually want to use it. Sounds like a good thing. On the other hand, a large memory-resident executable for a really simple application often is a symptom of an ensemble of library functions that rely on each other too much. This is what I referred to earlier as being common in "young" implementations. ======================================================================= 113 === Date: 29 Jan 1995 20:40:00 +0100 From: kai@khms.westfalen.de (Kai Henningsen) Subject: Re: Request for status on v. 3.4 (SPARC) rro@Tera.COM wrote on 25.01.95 in <3g6vs6$35s@tera.com>: > If there really is thread software in there, for example, it would be > disappointing. The idea of minimizing the strength of connection among > functions is not a new idea, just a good one. Back to the young > software point, this is just not on the top of the list for > implementors. A commercial motivation would clearly help. I think the real problem is that there is no support for dividing up modules in parts, only some of which get linked in. That, by the way, is what makes Borland Pascal or Mac Object Pascal programs small. As a programmer, you don't want to spend your time figuring out what sort of modularization would make for small executables. You want logical modularization instead. The system should do the rest. The abovementioned cases show it's possible. Kai -- Internet: kh@ms.maus.de, kai@khms.westfalen.de Bang: major_backbone!{ms.maus.de!kh,khms.westfalen.de!kai} ## CrossPoint v3.02 ## ======================================================================= 114 === Date: 29 Jan 1995 20:45:00 +0100 From: kai@khms.westfalen.de (Kai Henningsen) Subject: Re: Request for status on v. 3.4 (SPARC) gwyant@cloyd.East.Sun.COM wrote on 25.01.95 in <9501251523.AA23934@cloyd.East.S un.COM>: > on. I think that a commercial implementation of M3 could be made smaller by > having more intimate knowledge of object file formats. I personally don't > feel that this is something that SRC should be devoting resources to. If you Correct. The SRC compiler uses gcc code, so the optimal solution would be to enhance gcc to do it right, then leverage this for M3. Kai -- Internet: kh@ms.maus.de, kai@khms.westfalen.de Bang: major_backbone!{ms.maus.de!kh,khms.westfalen.de!kai} ## CrossPoint v3.02 ## ======================================================================= 115 === Date: 30 Jan 1995 11:18:37 -0500 From: hendrik@CAM.ORG (Hendrik Boom) Subject: Re: Modula-3 for OS/2 ckingsto@hookup.net@mail.hookup.net wrote: : In , dagenais@notung.vlsi.poly mtl.ca (Michel Dagenais) writes: : > : >From the FAQ. The last persons known to be working on such a port were : >Hendrik Boom hendrick@CAM.ORG and Craig Andrew Kingston : >ckingsto@undergrad.math.uwaterloo.ca. : >-- : > : >Prof. Michel Dagenais dagenais@vlsi.polymtl.ca : >Dept of Electrical and Computer Eng. : >Ecole Polytechnique de Montreal tel: (514) 340-4029 : Hi Everyone - Craig here. : I am still continuing to work on the port - just got delayed for a couple of months : because of issues not relating to the port. Not sure at this time of any dat es. : CRAIG : note: (my email has changed - not longer ckingsto@undergrad.math.uwaterloo.ca : but is now ckingsto@hookup.net) Hi everyone, Hendrik here. I too have been delayed by issues not related to the port -- most notably a series of total and catastrophic hardware failures. The machine is up and running now (except for the tape backup system :-( ), but I am still putting the pieces together, and it will be quite a while before I get back to modula-3. When I do it will probably be best if I see if Craig needs any help, rather than going it alone. ======================================================================= 116 === Date: Mon, 30 Jan 1995 16:11:37 -0500 From: douglm@rpi.edu Subject: Revelations All below refers to V3.3 on a SPARC. I have a program built out of a number of components. I think we can ignore most and concentrate on the part of the structure where: Program P includes an interface from package M which includes A from package C A defines a public object to represent the package C. Within C there are a number of private routines and an interface Apvt which defines further private fields and methods for the public object. The structure is: INTERFACE A; TYPE T <: Public; Public = OBJECT METHODS END; END A; ---------------------------- INTERFACE Apvt; IMPORT A; TYPE T = A.Public OBJECT METHODS END; REVEAL A.T <: T; (* Define A.T <: Apvt.T <: A.Public *) END Apvt. ---------------------------- MODULE Apvt; ... REVEAL A.T = T BRANDED "..." OBJECT OVERRIDES END; .... END Apvt. The intention is that only A.T should be visible to users of the package and the internal methods are restricted to those routines that implement the package. These definitions worked previously. I restructured the packages (without changing the definitions above) making A the only visible interface. Despite the explicit revalation of A.T in Apvt, when I try to build the program, I get the message opaque type never revealed: A.T (... I guess the revelation of A.T is being hidden in some way. Any ideas? ======================================================================= 117 === Date: 30 Jan 1995 09:52:29 -0600 From: claird@Starbase.NeoSoft.COM (Cameron Laird) Subject: Re: L'OBJET: A new journal (in French) on object technology. In article <3gb2bi$20o@crchh327.bnr.ca>, Jeffrey Fries P865 wrote: [eighty lines of pointlessly included text, among which were this summary] >bertrand@vienna.eiffel.com (Bertrand Meyer) wrote: >> >> >> [This message describes the launching of a new journal, in French, >> entirely devoted to object technology.] . . . >What did ya say ? > >huh ? > Professor Meyer, please know that you have many readers who welcomed your announcement. For my part, I would only have suggested that you per- haps expand your cross-posting to include {alt,misc}.books.technical. The rudeness of Mr. Fries' follow-up tells far more about his per- sonal failings than about the merit of your notice. Follow-ups trimmed. -- Cameron Laird ftp://ftp.neosoft.com/pub/users/claird/home.html claird@Neosoft.com +1 713 267 7966 claird@litwin.com +1 713 996 8546 ======================================================================= 118 === Date: Mon, 30 Jan 1995 16:46:52 -0500 From: gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS) Subject: Re: Request for status on v. 3.4 (SPARC) <9501241445.AA22145@cloyd.East.Sun.COM> <3g6vs6$35s@tera.com> <5emh2nYEcsB@khms.westfalen.de>Cc: m3@src.dec.com In-Reply-To: <5emh2nYEcsB@khms.westfalen.de> Distribution: world X-Received: from suneast.East.Sun.COM by East.Sun.COM (4.1/SMI-4.1) X-Received: by src-mail.pa.dec.com; id AA07508; Mon, 30 Jan 95 13:55:28 -0800 X-Newsgroups: comp.lang.modula3 X-Content-Length: 1157 X-Received: from cloyd.East.Sun.COM by suneast.East.Sun.COM (5.0/SMI-4.1-900117 ) X-Received: from Sun.COM by inet-gw-2.pa.dec.com (5.65/10Aug94) X-Received: by cloyd.East.Sun.COM (5.x/SMI-SVR4) X-Received: from East.Sun.COM (east.East.Sun.COM) by Sun.COM (sun-barr.Sun.COM) X-Received: by src-news.pa.dec.com; id AA01281; Mon, 30 Jan 95 13:55:30 -0800 Kai Henningsen writes: > rro@Tera.COM wrote on 25.01.95 in <3g6vs6$35s@tera.com>: > > > If there really is thread software in there, for example, it would be > > disappointing. The idea of minimizing the strength of connection among > > functions is not a new idea, just a good one. Back to the young > > software point, this is just not on the top of the list for > > implementors. A commercial motivation would clearly help. > > I think the real problem is that there is no support for dividing up > modules in parts, only some of which get linked in. That, by the way, is > what makes Borland Pascal or Mac Object Pascal programs small. > > As a programmer, you don't want to spend your time figuring out what sort > of modularization would make for small executables. You want logical > modularization instead. The system should do the rest. The abovementioned > cases show it's possible. > Just remember, Borland Pascal and Mac Object Pascal implement their own linkers. The SRC implementors made an explicit decision to not implement an M3-specific linker and instead provide easy portability of the system. --geoff ======================================================================= 119 === Date: Mon, 30 Jan 1995 15:44:09 GMT From: gcorneau@absolu.qc.ca (Gaetan Corneau) Subject: Re: L'OBJET: A new journal (in French) on object technology. >> [This message describes the launching of a new journal, in French, >> entirely devoted to object technology.] >> >> Une nouvelle publication en langue francaise, la premiere a notre >> connaissance a etre entierement consacree aux technologies objet, vient >> d'etre creee: Snip! Snip! >> Bertrand Meyer - ISE, Santa Barbara, California >> 805-685-1006, fax 805-685-6869, >> Web home page: http://www.eiffel.com >> ftp://eiffel.com >What did ya say ? >huh ? Et TOI, qu'as-tu dit? (And YOU, what did you say?)... Yes: not every people on the planet (or in the universe) speak english: real life is not like Star Trek! ;-) -------------------------------------------------------------------- GAETAN CORNEAU Software designer Absolu Technologies inc. Phone: (418) 650-5516 360 Franquet, suite 70 Fax: (418) 650-0860 Quebec Metro High Tech Park E-Mail: gcorneau@absolu.qc.ca Sainte-Foy, Quebec, G1P 4N3 Compuserve: 73062,3653@compuserve.com Canada -------------------------------------------------------------------- ======================================================================= 120 === Date: 29 Jan 1995 20:41:43 -0500 From: bm@news.cs.columbia.edu (Blair MacIntyre) Subject: Initializing a multidimension array (and possible bug in compiler) I'm obviously missing something. How does one write an initialization expression for a multidimension array? For example, lets say I have: --------------------------- INTERFACE GraphicsTypes; TYPE Matrix = ARRAY [0..3], [0..3] OF LONGREAL; Vector = ARRAY [0..3] OF LONGREAL; END GraphicsTypes. ---------------------------- MODULE Test EXPORTS Main; IMPORT Wr, Stdio, Fmt, Word, GraphicsTypes; VAR rotation_m := GraphicsTypes.Matrix{{0.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}}; BEGIN END Test. ---------------------------- This doesn't work, resulting in a compiler core dump in M3Buf.m3: ---------------------------- m3build --- building in ../HPPA --- m3 -w1 -why -g -o Test -F/usr/tmp/qkAAAa18650 new source -> compiling ../src/Test.m3 "../src/Test.m3", line 6: unexpected type expression *** *** runtime error: *** Value out of range *** file "../src/M3Buf.m3", line 73 *** sh: 18652 Abort(coredump) *** error code 134 (ignored) Compilation finished at Sun Jan 29 20:35:44 ------------------------------- Similarly, making the declaration one level: rotation_m := GraphicsTypes.Matrix{0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}; results in --------------------------------- m3build --- building in ../HPPA --- m3 -w1 -why -g -o Test -F/usr/tmp/qkAAAa18654 new source -> compiling ../src/Test.m3 "../src/Test.m3", line 6: too many values specified "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: expression is not assignable to array element "../src/Test.m3", line 6: warning: not used (rotation_m) 17 errors encountered compilation failed => not building program "Test" *** error code 1 (ignored) ----------------------------------- Thanks for any help. ======================================================================= 121 === Date: 31 Jan 1995 16:21:05 GMT From: kalsow@src.dec.com (Bill Kalsow) Subject: Re: Initializing a multidimension array (and possible bug in compiler) In article <199501300141.UAA02891@shadow.cs.columbia.edu>, bm@news.cs.columbia. edu (Blair MacIntyre) writes: > I'm obviously missing something. How does one write an initialization > expression for a multidimension array? > > VAR > rotation_m := GraphicsTypes.Matrix{{0.0, 0.0, 0.0, 0.0}, > {0.0, 1.0, 0.0, 0.0}, > {0.0, 0.0, 1.0, 0.0}, > {0.0, 0.0, 0.0, 1.0}}; > > This doesn't work, resulting in a compiler core dump in M3Buf.m3: Modula-3 requires a type name or expression at the beginning of every constructor. In your case, the inner arrays constructors require type names. The following should work: VAR rotation_m := GraphicsTypes.Matrix{ GraphicsTypes.Vector{0.0, 0.0, 0.0, 0.0}, GraphicsTypes.Vector{0.0, 1.0, 0.0, 0.0}, GraphicsTypes.Vector{0.0, 0.0, 1.0, 0.0}, GraphicsTypes.Vector{0.0, 0.0, 0.0, 1.0}}; - Bill Kalsow P.S. I fixed the bug that caused the compiler crash in M3Buf. Thanks for the indirect bug report. ======================================================================= 122 === Date: 31 Jan 1995 23:12:05 GMT From: kalsow@src.dec.com (Bill Kalsow) Subject: Re: Revelations In article , douglm@rpi.edu writes: > I have a program built out of a number of components. I think we can ignore > most and concentrate on the part of the structure where: > > Program P includes an interface from package M which includes A from packag e C > > A defines a public object to represent the package C. Within C there are a > number of private routines and an interface Apvt which defines further > private fields and methods for the public object. The structure is: I can't be certain from the facts you posted. My guess is that no interface or module imports Apvt, so the linker is not including it. Since Apvt is providing the full revelation for A.T, I would have Apvt export A and Apvt. But, since both interfaces A and Apvt define a type T, you'll need to shuffle some names. - Bill Kalsow ======================================================================= 123 === Date: Tue, 31 Jan 1995 13:45:13 GMT From: bwbecker@dragon.uwaterloo.ca (Byron Weber Becker) Subject: Differences between 3.3 and 3.4 Can someone summarize the differences between version 3.3 and 3.4? We've got 3.3 running -- what does the pain and agony of installing 3.4 buy me? Is it worth it? ===== Byron Weber Becker (519) 888-4567 x4661 Computer Science Lecturer/Advisor bwbecker@dragon.uwaterloo.ca University of Waterloo ======================================================================= 124 === Date: Tue, 31 Jan 1995 13:44:01 GMT From: bwbecker@dragon.uwaterloo.ca (Byron Weber Becker) Subject: Re: Initializing a multidimension array (and possible bug in compiler) In article <199501300141.UAA02891@shadow.cs.columbia.edu> bm@news.cs.columbia.edu (Blair MacIntyre) writes: > I'm obviously missing something. How does one write an initialization > expression for a multidimension array? > > For example, lets say I have: > --------------------------- > INTERFACE GraphicsTypes; > > TYPE > Matrix = ARRAY [0..3], [0..3] OF LONGREAL; > Vector = ARRAY [0..3] OF LONGREAL; > > END GraphicsTypes. > ---------------------------- > MODULE Test EXPORTS Main; > IMPORT Wr, Stdio, Fmt, Word, GraphicsTypes; > > VAR > rotation_m := GraphicsTypes.Matrix{{0.0, 0.0, 0.0, 0.0}, > {0.0, 1.0, 0.0, 0.0}, > {0.0, 0.0, 1.0, 0.0}, > {0.0, 0.0, 0.0, 1.0}}; > > BEGIN > END Test. > ---------------------------- > > This doesn't work, resulting in a compiler core dump in M3Buf.m3: Can't comment on the core dump, but I believe the right way to initialize it is to view Matrix this way: TYPE Vector = ARRAY [0..3] OF LONGREAL; Matrix = ARRAY [0..3] OF Vector; (* Exactly equivilent to what you have *) VAR rotation_m := GraphicsTypes.Matrix{Vector{0.0, 0.0, 0.0, 0.0}, Vector{0.0, 1.0, 0.0, 0.0}, Vector{0.0, 0.0, 1.0, 0.0}, Vector{0.0, 0.0, 0.0, 1.0}}; ===== Byron Weber Becker (519) 888-4567 x4661 Computer Science Lecturer/Advisor bwbecker@dragon.uwaterloo.ca University of Waterloo ======================================================================= 125 === Date: Tue, 31 Jan 1995 20:24:44 GMT From: hinsenk@cyclone.ERE.UMontreal.CA (Hinsen Konrad) Subject: Re: L'OBJET: A new journal (in French) on object technology. In article <3gluda$nm1@crchh327.bnr.ca> Jeffrey Fries P865 wr ites: When in Rome....speak Italian....When in USA, speak English. Usenet has become quite international. It's not just the USA any more. -- ------------------------------------------------------------------------------- Konrad Hinsen | E-Mail: hinsenk@ere.umontreal.ca Departement de Chimie | Tel.: +1-514-343-6111 ext. 3953 Universite de Montreal | Fax: +1-514-343-7586 C.P. 6128, succ. A | Deutsch/Esperanto/English/Nederlands/ Montreal (QC) H3C 3J7 | Francais (phase experimentale) ------------------------------------------------------------------------------- ======================================================================= 127 === Date: 31 Jan 1995 20:09:57 GMT From: jhoward@solar.sky.net (John Howard) Subject: Abstract Data Types book I am looking for a book published by Springer-Verlag which is a comprehensive compendium of abstract data types. Their were two authors for it. The title and ISBN number elude me. This info was posted recently in one of the comp.*.* groups but I lost it. Can anyone help? ======================================================================= 128 === Date: 31 Jan 1995 18:09:46 GMT From: Jeffrey Fries P865 Subject: Re: L'OBJET: A new journal (in French) on object technology. gcorneau@absolu.qc.ca (Gaetan Corneau) wrote: > > > >> [This message describes the launching of a new journal, in French, > >> entirely devoted to object technology.] > >> > >> Une nouvelle publication en langue francaise, la premiere a notre > >> connaissance a etre entierement consacree aux technologies objet, vient > >> d'etre creee: > > Snip! Snip! > > >> Bertrand Meyer - ISE, Santa Barbara, California > >> 805-685-1006, fax 805-685-6869, > >> Web home page: http://www.eiffel.com > >> ftp://eiffel.com > > > >What did ya say ? > > >huh ? > > Et TOI, qu'as-tu dit? (And YOU, what did you say?)... > > Yes: not every people on the planet (or in the universe) speak english: real > life is not like Star Trek! ;-) > > > -------------------------------------------------------------------- > GAETAN CORNEAU > Software designer > > Absolu Technologies inc. Phone: (418) 650-5516 > 360 Franquet, suite 70 Fax: (418) 650-0860 > Quebec Metro High Tech Park E-Mail: gcorneau@absolu.qc.ca > Sainte-Foy, Quebec, G1P 4N3 Compuserve: 73062,3653@compuserve.com > Canada > -------------------------------------------------------------------- When in Rome....speak Italian....When in USA, speak English. Rude...my butt! ======================================================================= 129 === Date: 29 Jan 1995 16:48:11 GMT From: Quentin Stafford-Fraser Subject: Re: Modula-3 for NT Is anyone able to make NT binaries available? Quentin ======================================================================= 149 === Date: 31 Jan 1995 03:49:30 GMT From: bm@stieglitz.cs.columbia.edu (Blair MacIntyre) Subject: YASQ: any hints as to why @M3showthread might now work? showthread is at least running and trying to open the display (if I take away xhost permission, it fails (and prints out something to that effect). When xhost permission is there, no window appears and the program doesn't start (the program runs fine without the @M3showthread). BTW, YASQ is "yet another stupid question". This is on the SPARC implementation, v3.4, with a remote display (either an HP or an SGI). -- Blair MacIntyre (bm@cs.columbia.edu), Graduate Student (Graphics and UI Lab) smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St. Columbia University, New York, NY 10027 ======================================================================= 169 === Date: 31 Jan 1995 01:07:48 GMT From: ilu-core@parc.xerox.com Subject: ILU 1.7 now available ILU 1.7, which fixes many bugs in ILU 1.6, and provides new support for the programming language Python, is now available via the links from ftp://ftp.parc.xerox.com/pub/ilu/ilu.html, or directly as ftp://ftp.parc.xerox.com/pub/ilu/1.7/ilu-1.7.tar.gz. ILU is a system for defining and using language-independent object-oriented interfaces. It can be used to define and implement the API's for reusable software libraries. It is also, due to its implementation design, a ``distributed object'' system, which can be used to interlink code written in either C, C++, Modula-3, Common Lisp, or Python. It can be used with any mix of these languages as an object-oriented RPC system to build client-server systems. It can understand interface descriptions written in OMG IDL ("CORBA" IDL), and produces CORBA-compliant language mappings for ANSI C. Xerox is providing it free of charge for any use, including commercial products. -- Bill Janssen (415) 812-4763 FAX: (415) 812-4777 Xerox Palo Alto Research Center, 3333 Coyote Hill Rd, Palo Alto, CA 94304 URL: ftp://parcftp.parc.xerox.com/pub/ilu/misc/janssen.html